You Are Here Home > Mac Programming

Mac Programming

Cocoa: Determining Size Of a NSTextView’s Content

You can do this:

[[textView layoutManager] usedRectForTextContainer:[textView textContainer]].size
Cocoa: Determining Size Of a NSTextView’s Content
Comments (0)   Filed under: Cocoa,Mac Programming,Objective-C,Xcode   Posted by: Codehead

iPhone: libpng error: CgBI: unknown critical chunk

If you get this error when trying your app on the device, you have PNG compression on in Xcode, in Xcode 4 goto “Build Settings” search for PNG in the search box and turn off PNG compression…

iPhone: libpng error: CgBI: unknown critical chunk
Comments (1)   Filed under: C Programming,iPhone SDK,Mac Programming,Xcode   Posted by: Hamid

Cocoa App Doesn’t Show Up In Activity Monitor

This was happening because I accidentally deleted “Bundle Display Name” from my info.plist…..

Cocoa App Doesn’t Show Up In Activity Monitor
Comments (0)   Filed under: Mac Programming,Objective-C,Xcode   Posted by: Hamid

Popen+ a Bidirectional Popen Implementation With Ability to Access PID and Kill/Terminate Processes

On Github:
https://github.com/Codingrecipes/Popen+

This is a little popen implementation which will make it easier to kill processes and will give you access to the PID of the process, I don’t know why they didn’t do this in popen but I’m sure they had good reasons because those guys are way too smart…

popen_plus.h:

/*
 ** Author: Hamid Alipour http://codingrecipes.com http://twitter.com/code_head
 ** SQLite style license:
 ** 
 ** 2001 September 15
 **
 ** The author disclaims copyright to this source code.  In place of
 ** a legal notice, here is a blessing:
 **
 **    May you do good and not evil.
 **    May you find forgiveness for yourself and forgive others.
 **    May you share freely, never taking more than you give.
 **/
 
#ifndef POPEN_PLUS_H
#define POPEN_PLUS_H
 
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <paths.h>
#include <sys/stat.h>
#include <dirent.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
 
#define READ 0
#define WRITE 1
 
struct popen_plus_process {
    pthread_mutex_t mutex;
    pid_t pid;
    FILE *read_fp;
    FILE *write_fp;
};
 
struct popen_plus_process *popen_plus(const char *command);
int popen_plus_close(struct popen_plus_process *process);
int popen_plus_kill(struct popen_plus_process *process);
int popen_plus_kill_by_id(int process_id);
int popen_plus_terminate(struct popen_plus_process *process);
int popen_plus_terminate_with_id(int process_id);
 
#endif

popen_plus.c:

/*
 ** Author: Hamid Alipour http://codingrecipes.com http://twitter.com/code_head
 ** SQLite style license:
 ** 
 ** 2001 September 15
 **
 ** The author disclaims copyright to this source code.  In place of
 ** a legal notice, here is a blessing:
 **
 **    May you do good and not evil.
 **    May you find forgiveness for yourself and forgive others.
 **    May you share freely, never taking more than you give.
 **/
 
#include <errno.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <paths.h>
#include <sys/stat.h>
#include <dirent.h>
#include <stdlib.h>
#include <string.h>
#include "popen_plus.h"
 
struct popen_plus_process *popen_plus(const char *command)
{
    int inpipe[2];
    int outpipe[2];
    char *argv[4];
    struct popen_plus_process *process = malloc(sizeof(struct popen_plus_process));
 
    if (!process)
        goto error_out;
 
    if (pipe(inpipe) != 0)
        goto clean_process_out;
 
    if (pipe(outpipe) != 0)
        goto clean_inpipe_out;
 
    process->read_fp = fdopen(outpipe[READ], "r");
    if (!process->read_fp)
        goto clean_outpipe_out;
 
    process->write_fp = fdopen(inpipe[WRITE], "w");
    if (!process->write_fp)
        goto clean_read_fp_out;
 
    if (pthread_mutex_init(&process->mutex, NULL) != 0)
        goto clean_write_fp_out;
 
    process->pid = fork();
    if (process->pid == -1)
        goto clean_mutex_out;
 
    if (process->pid == 0) {
        close(outpipe[READ]);
        close(inpipe[WRITE]);
 
        if (inpipe[READ] != STDIN_FILENO) {
            dup2(inpipe[READ], STDIN_FILENO);
            close(inpipe[READ]);
        }
 
        if (outpipe[WRITE] != STDOUT_FILENO) {
            dup2(outpipe[WRITE], STDOUT_FILENO);
            close(outpipe[WRITE]);
        }
 
        argv[0] = "sh";
        argv[1] = "-c";
        argv[2] = (char *) command;
        argv[3] = NULL;
 
        execv(_PATH_BSHELL, argv);
        exit(127);
    }
 
    close(outpipe[WRITE]);
    close(inpipe[READ]);
 
    return process;
 
clean_mutex_out:
    pthread_mutex_destroy(&process->mutex);
 
clean_write_fp_out:
    fclose(process->write_fp);
 
clean_read_fp_out:
    fclose(process->read_fp);
 
clean_outpipe_out:
    close(outpipe[READ]);
    close(outpipe[WRITE]);
 
clean_inpipe_out:
    close(inpipe[READ]);
    close(inpipe[WRITE]);
 
clean_process_out:
    free(process);
 
error_out:
    return NULL;
}
 
int popen_plus_close(struct popen_plus_process *process)
{
    int pstat;
    pid_t pid;
 
    /**
     * If someone else destrys this mutex, then this call will fail and we know
     * that another thread already cleaned up the process so we can safely return
     * and since we are destroying this mutex bellow then we don't need to unlock
     * it...
     */
    if (pthread_mutex_lock(&process->mutex) != 0)
        return 0;
 
    if (process->pid != -1) {
        do {
            pid = waitpid(process->pid, &pstat, 0);
        } while (pid == -1 && errno == EINTR);
    }
 
    if (process->read_fp)
        fclose(process->read_fp);
 
    if (process->write_fp)
        fclose(process->write_fp);
 
    pthread_mutex_destroy(&process->mutex);
 
    free(process);
 
    return (pid == -1 ? -1 : pstat);
}
 
int popen_plus_kill(struct popen_plus_process *process)
{
    char command[64];
 
    sprintf(command, "kill -9 %d", process->pid);
    system(command);
 
    return 0;
}
 
int popen_plus_kill_by_id(int process_id)
{
    char command[64];
 
    sprintf(command, "kill -9 %d", process_id);
    system(command);
 
    return 0;
}
 
int popen_plus_terminate(struct popen_plus_process *process)
{
    char command[64];
 
    sprintf(command, "kill -TERM %d", process->pid);
    system(command);
 
    return 0;
}
 
int popen_plus_terminate_with_id(int process_id)
{
    char command[64];
 
    sprintf(command, "kill -TERM %d", process_id);
    system(command);
 
    return 0;
}

This code was inspired by many sources and I think I perfected it, although you might find bugs or issues and if you do, please let me know if the comments section.

You can use it like so:

struct popen_plus_process *process = popen_plus("ls -l");
if (!process) {
     /* Failed do something and return or exit */
     return -1;
}
 
int MAX_BUFFER = 256;
char buffer[256];
 
while (!feof(process->read_fp))
     if (fgets(buffer, MAX_BUFFER, process->read_fp) != NULL)
          printf("%s\n", buffer);
 
popen_plus_close(process);

To kill a process:

popen_plus_kill(process);
popen_plus_close(process);

Terminate is similar to kill…

I hope this helps someone!

:)

Popen+ a Bidirectional Popen Implementation With Ability to Access PID and Kill/Terminate Processes

NSNotificationCenter Is Not Thread Safe

If you have to send notifications from secondary threads, then you might have noticed that your app crashes randomly and it’s unstable, the way to get around this is to have a method that sends the notification and use a second method to call that method using performSelectorOnMainThread like so:

- (void)doPostStatusNotification:(NSString *)message {
    [[NSNotificationCenter defaultCenter] postNotificationName:@"SOME_ID" object:self userInfo:[NSDictionary dictionaryWithObject:message forKey:@"message"]];
}
 
- (void)postStatusNotification:(NSString *)message {
    [self performSelectorOnMainThread:@selector(doPostStatusNotification:) withObject:message waitUntilDone:NO];
}

And, never call the first method, always use the second one…

NSNotificationCenter Is Not Thread Safe
Comments (0)   Filed under: Cocoa,Mac Programming,Objective-C   Posted by: Hamid

A Nicer Way Of Updating NSTableView Without A NSTimer

I used to use timers to update my table views, but you know that the timer runs in the same thread that you create it and it attaches to the same runloop so that’s not very nice and it’s silly to make a thread for it so naturally you might end up making a timer with longer time intervals and your table view will have delays.

There is a nicer way of handling this, you can use NSKeyValueObserving and all you have to do in is to import two headers on top of your model:

#import <Foundation/NSKeyValueCoding.h>
#import <Foundation/NSKeyValueObserving.h>

Then, when you load your model items attach observers to each one, like so:

[directory addObserver:self forKeyPath:@"some-property-of-your-model-object-like-status" options:NSKeyValueObservingOptionNew context:nil];

You can add and observer to as many properties as you want.

Then implement the delegate method in your controller:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if (![the-table-view needsDisplay])
        [the-table-view setNeedsDisplay:YES];
}

If you add new rows or remove them, you will need to send a reloadData message to your table view.

That’s it, much simpler than caveman way of doing it and updates are almost instant…

A Nicer Way Of Updating NSTableView Without A NSTimer
Comments (0)   Filed under: Cocoa,Mac Programming,Objective-C   Posted by: Hamid

NSTableView reloadData Hangs And Doesn’t Work

This happened to me and everything was working, the table was linked up properly to it’s delegate and datasource but I discovered that I was calling reloadData too many times, so this problem could be caused by two things:

1 – If you call reloadData too many times, it messes up some internal thing and it stops responding.
2 – It has a mechanism in place that detects this issue and kind of stops responding.

Now, to try to fix this, you must know what reloadData does, it simply sets a flag in the table view:

[the-table-view setNeedsDisplay:YES];

And if you did any reading or research you know that this doesn’t guaranty a refresh – which leads me to believe the second point above might be true – of the view so to fix my issue I tried:

if (![the-table-view needsDisplay])
        [the-table-view setNeedsDisplay:YES];

You must call reloadData only when you add new/or remove data to/from the dataset.

This seems to be working…

NSTableView reloadData Hangs And Doesn’t Work
Comments (1)   Filed under: Cocoa,Mac Programming,Objective-C   Posted by: Hamid

SQLite And The Problem Of Storing Long Long Integers

Recently, I was trying to store a very large integer value in a SQLite column, it didn’t matter wether I used INTEGER or UNSIGNED BIG INT, SQLite rounded it for me and I was left with an integer value that wasn’t even close to what I needed.

So one solution was to just use a VARCHAR or TEXT or event a BLOB and insert the number with quotes around it but guess what? SQLite did it again!!!

It turns out that SQLite tries to convert your values to ints to give you some benefits with sorting and comparing etc. – in case you didn’t know you really wanted an int rather than a BLOB – and that happens here in one of it’s functions:

/*
** Try to convert a value into a numeric representation if we can
** do so without loss of information.  In other words, if the string
** looks like a number, convert it into a number.  If it does not
** look like a number, leave it alone.
*/
static void applyNumericAffinity(Mem *pRec){
  if( (pRec->flags & (MEM_Real|MEM_Int))==0 ){
    double rValue;
    i64 iValue;
    u8 enc = pRec->enc;
    if( (pRec->flags&MEM_Str)==0 ) return;
    if( sqlite3AtoF(pRec->z, &rValue, pRec->n, enc)==0 ) return;
    if( 0==sqlite3Atoi64(pRec->z, &iValue, pRec->n, enc) ){
      pRec->u.i = iValue;
      pRec->flags |= MEM_Int;
    }else{
      pRec->r = rValue;
      pRec->flags |= MEM_Real;
    }
  }
}

The solution to this issue is to prepend a 0 to your number and use a BLOB or TEXT type column and insert it like this: ’0THEVERYLARGENUMBER’

Don’t get me wrong, SQLite is a great library that I’ve been using, it’s very well tested and works great, it’s fast and thread safe, I specially like it’s licensee:

/*
** 2001 September 15
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************

I hope this helps…

SQLite And The Problem Of Storing Long Long Integers

Objective-C: A Function For Escaping Values Before Inserting Into SQLite

- (NSString *)escape:(NSObject *)value {
    if (value == nil)
        return nil;
    NSString *escapedValue = nil;
    if ([value isKindOfClass:[NSString class]] || [value isKindOfClass:[NSMutableString class]]) {
        NSString *valueString = (NSString *) value;
        char *theEscapedValue = sqlite3_mprintf("'%q'", [valueString UTF8String]);
        escapedValue = [NSString stringWithUTF8String:(const char *)theEscapedValue];
        sqlite3_free(theEscapedValue);
    } else
        escapedValue = [NSString stringWithFormat:@"%@", value];
    return escapedValue;
}
Objective-C: A Function For Escaping Values Before Inserting Into SQLite