objective-c snippets

How to trace Objective-C messages with dtrace in OSX

Tagged dtrace, osx, objective-c  Languages objectivec

First, find the process id:

$ ps -ef|grep Grab
  501 50335   319   0   0:02.11 ??         0:04.40 /Applications/Utilities/Grab.app/Contents/MacOS/Grab -psn_0_7309048

The pid is 50335 so create a D program that captures the Objective-C calls for that process:

objc50335:::entry
{
   printf("%s %s\n", probemod, probefunc);
}

Save the code in a file called grab.trace.d and start tracing by executing this command:

sudo dtrace -s grab.trace.d > trace.log

Output is sent to the trace.log file.

How to put the run loop to sleep

Tagged sleep, runloop, objective-c  Languages objectivec
NSDate *stopDate = [NSDate dateWithTimeIntervalSinceNow:2];
[[NSRunLoop currentRunLoop] runUntilDate:stopDate];

How to configure and use ASIHttpRequest with XCode

Tagged asihttprequest, objective-c, http, xcode  Languages objectivec

Get ASIHttpRequest from GitHub

$ cd project-dir
$ git clone git://github.com/pokeb/asi-http-request.git
mkdir -p lib/ASIHttpRequest
mv asi-http-request/Classes/* lib/ASIHttpRequest

Link required frameworks

In Groups & Files in XCode, right-click Frameworks > Linked Frameworks choose Add Existing Frameworks.

Select CoreServices.framework. Do the same for SystemConfiguration.framework.

Next add libz.1.2.3.dylib by selecting Add Existing Files from the same menu. The full path to this file is /Developer/SDKs/MacOSX10.5.sdk/usr/lib/libz.1.2.3.dylib

Making asynchronous requests

- (void)requestDone:(ASIHTTPRequest *)request
{
    NSString *response = [request responseString];
    NSLog ( @"Response %@", response );

}

- (void)requestWentWrong:(ASIHTTPRequest *)request
{
    NSError *error = [request error];
    NSLog ( @"Something wrong" );
}

- (void)requestURL()
{
    NSURL *url = [NSURL URLWithString:@"http://allseeing-i.com"];
    ASIHTTPRequest *request = [[[ASIHTTPRequest alloc] initWithURL:url] autorelease];
    
    [request setDelegate:self];
    [request setDidFinishSelector:@selector(requestDone:)];
    [request setDidFailSelector:@selector(requestWentWrong:)];
    
        [networkQueue addOperation:request];
    [networkQueue go];
}

Making synchronous requests

NSURL *url = [NSURL URLWithString:@"http://allseeing-i.com"];
    ASIHTTPRequest *request = [[[ASIHTTPRequest alloc] initWithURL:url] autorelease];
    [request start];
    NSError *error = [request error];
    
    if (!error) {
        NSString *response = [request responseString];
        NSLog ( @"Response: %@", response );
    } else {
        NSLog ( @"Something went wrong" );
    }

How to make asynchronous HTTP requests with NSURLConnection

Tagged http, objective-c, nsurlconnection  Languages objectivec

Example of how to make asynchronous HTTP requests with NSURLConnection:

//
//  HTTP.h
//
#import <Cocoa/Cocoa.h>
#import "HTTPDelegate.h"

@interface HTTP : NSObject {
    id delegate;
    NSMutableData *receivedData;
    NSURL *url;
}
@property (nonatomic,retain) NSMutableData *receivedData;
@property (retain) id delegate;

- (void)get: (NSString *)urlString;
- (void)post: (NSString *)urlString;

@end
//
//  HTTP.m
//

#import "HTTP.h"


@implementation HTTP

@synthesize receivedData;

- init {
    if ((self = [super init])) {
        
    }
    return self;
}

- (void)dealloc {
    [super dealloc];
}


- (void)setDelegate:(id)val
{
    delegate = val;
}

- (id)delegate
{
    return delegate;
}

- (void)get: (NSString *)urlString {
    
    NSLog ( @"GET: %@", urlString );

    self.receivedData = [[NSMutableData alloc] init];
    
       NSURLRequest *request = [[NSURLRequest alloc]
                             initWithURL: [NSURL URLWithString:urlString]
                             cachePolicy: NSURLRequestReloadIgnoringLocalCacheData
                             timeoutInterval: 10
                             ];

       NSURLConnection *connection = [[NSURLConnection alloc]
                                   initWithRequest:request
                                   delegate:self
                                   startImmediately:YES];
    if(!connection) {
        NSLog(@"connection failed :(");
    } else {
        NSLog(@"connection succeeded  :)");
        
    }
    
    [connection release];
        [request release];  
        [receivedData release];  
}


- (void)post: (NSString *)urlString {
    
    // POST
    //[request setHTTPMethod:@"POST"];
    // NSString *postString = @"Some post string";
    //[request setHTTPBody:[postString dataUsingEncoding:NSUTF8StringEncoding]];
}   

// ====================
// Callbacks
// ====================

#pragma mark NSURLConnection delegate methods
- (NSURLRequest *)connection:(NSURLConnection *)connection
             willSendRequest:(NSURLRequest *)request
            redirectResponse:(NSURLResponse *)redirectResponse {
    NSLog(@"Connection received data, retain count");
       return request;
}


- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    NSLog(@"Received response: %@", response);
    
      [receivedData setLength:0];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    NSLog(@"Received %d bytes of data", [data length]); 
    
       [receivedData appendData:data];
    NSLog(@"Received data is now %d bytes", [receivedData length]); 

}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    NSLog(@"Error receiving response: %@", error);
       [[NSAlert alertWithError:error] runModal];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
       // Once this method is invoked, "responseData" contains the complete result
    NSLog(@"Succeeded! Received %d bytes of data", [receivedData length]); 
    
    NSString *dataStr=[[NSString alloc] initWithData:receivedData encoding:NSASCIIStringEncoding];
    NSLog(@"Succeeded! Received %@ bytes of data", dataStr); 
    
    if ([delegate respondsToSelector:@selector(didFinishDownload:)]) {
        NSLog(@"Calling the delegate"); 
        //NSString* dataAsString = [[[NSString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding] autorelease];
        [delegate performSelector:@selector(didFinishDownload:) withObject: dataStr];
    }
    
    [dataStr release];
}


@end

How to store user settings with NSUserDefaults

Tagged nsuserdefaults, preferences, settings, objective-c  Languages objectivec

Storing preferences

NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];
[preferences setObject:@"SOME_DATA" forKey:@"KEY"];

Retrieving preferences

[preferences stringForKey:@"KEY"];
[preferences integerForKey:@"KEY"];
[preferences booleanForKey:@"KEY"];

Listing preferences with the defaults command

To list all preferences for a specific app, use this command:

$ defaults read com.aktagon.XXXApp

References

http://developer.apple.com/documentation/Cocoa/Conceptual/UserDefaults/UserDefaults.html

How to scroll images with NSImageView and NSScrollView

Tagged cocoa, objective-c, autoresize, nsscrollview, nsimageview, scroll  Languages objectivec
  1. In IB (Interface Builder) add an NSImageView to the window.
  2. Select the NSImageView.
  3. From the menu select Select Layout ~~> Embed Objects In~~> Scroll View.
  4. Select the NSScrollView press Cmd+3 and configure the NSScrollView to expand and fill all available space.
  5. Remove the NSImageView's border
  6. Use this code to resize the NSImageView's frame to match the size of the NSImage
NSImageView *imageView = ...;
[imageView setFrameSize:viewSize];

NSLog(@"imageView's frame after resizing: %@", NSStringFromRect([imageView frame]));

Registering global hot keys with Cocoa and Objective-C

Tagged cocoa, hotkeys, objective-c  Languages objectivec

In your application's controller add the following:

- (void)awakeFromNib
{
    [self registerHotKeys];
}

And the following code which registers the hot keys:

-(void)registerHotKeys
{   
    EventHotKeyRef gMyHotKeyRef;
    EventHotKeyID gMyHotKeyID;
    EventTypeSpec eventType;
    eventType.eventClass=kEventClassKeyboard;
    eventType.eventKind=kEventHotKeyPressed;    
    
    InstallApplicationEventHandler(&OnHotKeyEvent, 1, &eventType, (void *)self, NULL);
    
    gMyHotKeyID.signature='htk1';
    gMyHotKeyID.id=1;
    RegisterEventHotKey(20, cmdKey+optionKey, gMyHotKeyID, GetApplicationEventTarget(), 0, &gMyHotKeyRef);  
    
    gMyHotKeyID.signature='htk2';
    gMyHotKeyID.id=2;   
    RegisterEventHotKey(21, cmdKey+optionKey, gMyHotKeyID, GetApplicationEventTarget(), 0, &gMyHotKeyRef);  
    
    gMyHotKeyID.signature='htk3';
    gMyHotKeyID.id=3;   
    RegisterEventHotKey(23, cmdKey+optionKey, gMyHotKeyID, GetApplicationEventTarget(), 0, &gMyHotKeyRef);  
}

OSStatus OnHotKeyEvent(EventHandlerCallRef nextHandler,EventRef theEvent,void *userData)
{
    EventHotKeyID hkCom;
    
    GetEventParameter(theEvent, kEventParamDirectObject, typeEventHotKeyID, NULL, sizeof(hkCom), NULL, &hkCom);
    AppController *controller = (AppController *)userData;  
    
    int l = hkCom.id;
    
    switch (l) {
        case 1:         
            NSLog(@"Capture area"); 
            [ScreenCapture captureArea:controller];
            break;
        case 2: 
            NSLog(@"Capture screen");   
            [ScreenCapture captureScreen:controller];
            break;
        case 3: 
            NSLog(@"Capture window");   
            [ScreenCapture captureWindow:controller];
            break;  
    }

    return noErr;
}

The code used in this snippet was inspired by this blog post http://dbachrach.com/blog/2005/11/28/program-global-hotkeys-in-cocoa-easily/

Alternatives

If you need a more complete solution you can use one of these open-source alternatives:

Showing the application window

Usually you want to show the application window when the hot key is pressed. This can be done as explained in this snippet

How to set an application to load at login with Cocoa and Objective-C

Tagged startup, login, cocoa, objective-c  Languages objectivec

In XCode add the following to your controller's header file:

@interface AppController : NSObject {
IBOutlet NSButton *buttonOpenAtLogin;
}
.
.
.
- (IBAction)addLoginItem:(id)sender;
- (void)enableLoginItemWithLoginItemsReference:(LSSharedFileListRef )theLoginItemsRefs ForPath:(CFURLRef)thePath;
- (void)disableLoginItemWithLoginItemsReference:(LSSharedFileListRef )theLoginItemsRefs ForPath:(CFURLRef)thePath;

Add the following to the implementation:

@implementation AppController

- (void)enableLoginItemWithLoginItemsReference:(LSSharedFileListRef )theLoginItemsRefs ForPath:(CFURLRef)thePath {
    // We call LSSharedFileListInsertItemURL to insert the item at the bottom of Login Items list.
    LSSharedFileListItemRef item = LSSharedFileListInsertItemURL(theLoginItemsRefs, kLSSharedFileListItemLast, NULL, NULL, thePath, NULL, NULL);        
    if (item)
        CFRelease(item);
}

- (void)disableLoginItemWithLoginItemsReference:(LSSharedFileListRef )theLoginItemsRefs ForPath:(CFURLRef)thePath {
    UInt32 seedValue;
    
    // We're going to grab the contents of the shared file list (LSSharedFileListItemRef objects)
    // and pop it in an array so we can iterate through it to find our item.
    NSArray  *loginItemsArray = (NSArray *)LSSharedFileListCopySnapshot(theLoginItemsRefs, &seedValue);
    for (id item in loginItemsArray) {      
        LSSharedFileListItemRef itemRef = (LSSharedFileListItemRef)item;
        if (LSSharedFileListItemResolve(itemRef, 0, (CFURLRef*) &thePath, NULL) == noErr) {
            if ([[(NSURL *)thePath path] hasPrefix:SGApplicationPath])
                LSSharedFileListItemRemove(theLoginItemsRefs, itemRef); // Deleting the item
        }
    }
    
    [loginItemsArray release];
}

- (IBAction)addLoginItem:(id)sender {
    CFURLRef url = (CFURLRef)[NSURL fileURLWithPath:SGApplicationPath];
    
    // Create a reference to the shared file list.
    LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
    
    if (loginItems) {
        if ([[buttonOpenAtLogin selectedCell] state] == YES)
            [self enableLoginItemWithLoginItemsReference:loginItems ForPath:url];
        else
            [self disableLoginItemWithLoginItemsReference:loginItems ForPath:url];
    }
    CFRelease(loginItems);
}
.
.
.

In Interface Builder do the following:

  • Add a User Defaults Controller Bindings object to IB.
  • Add a checkbox button or menu item to IB
  • Bind the button to the IBOutlet in the controller
  • Select the button and bind it to the User Defaults Controller (Cmd+5). Enter values in "Controller Key" and "Model Key Path"

Code found here

See http://developer.apple.com/cocoa/cocoabindings.html for more details...

How to capture photos/videos with iSight and Objective-C

Tagged cocoa, isight, objective-c, record  Languages objectivec

There are plenty of resources online that explain how to access iSight:

This article explains how to use QuartzComposer for capturing images with iSight. The benefit of using QuartzComposer is that you don't have to write a lot of code to capture an image. All you have to do is setup a QCView with IB and bind it to an outlet, then to get the snapshot you call this method:

NSImage *screenshot = [isightView snapshotImage];

Alternatively, you could also use:

- (id) createSnapshotImageOfType:(NSString*)type

The code in the article didn't work for me:

NSImage *currentImage = [qcView valueForOutputKey:@"ImageOutput"];

The article also forgot to mention that you have to import and link to the following frameworks:

#import <QuartzCore/QuartzCore.h>
#import <Quartz/Quartz.h>

Haven't tried this one yet.

This example is not complete.

Have a look at one of the demos like StillMotion

How to install and use RegexKitLite

Tagged objective-c, regexkitlite, regex, regular expression  Languages objectivec

Install RegexKitLite

First download RegexKitLite.

Configure your project

Double-click the project target under Targets in the Groups & Files sidebar.

Under the Linking header add -licucore to the Other Linker Flags setting.

Setup documentation

In the Xcode menu, open Xcode->Preferences->Documentation. Then click the Add Publisher button.

Add this URL: feed://regexkit.sourceforge.net/RegexKitLiteDocSets.atom

Using RegexKitLite

This will extract the integer that is embedded in a td tag:

NSString *regex = @"<td id\"amount\">(\\d+)</td>";
NSString *body = [[[NSString alloc] initWithData:html encoding: NSASCIIStringEncoding] autorelease];
NSString *amount = [body stringByMatching:regex capture:1];

if ([amount isEqual:@""] == NO) {
    NSLog(@"Amount is %@", amount);
} else {
    NSLog(@"Amount was not found.");
}