Introduction to Cocoa Programming for Mac OS X

Arthur Clemens 27 May 2008 - Amsterdam

What are we going to make?

What we are going to create

What will you learn?
XCode Tools Interface Builder Objective-C How to open and process files:
open dialog, drag on icon, drag on app

Extending classes Image resizing Messaging Saving

27 May 2008 | Introduction to Cocoa | 3

XCode Tools
 http://developer.apple.com/

27 May 2008 | Introduction to Cocoa | 4

New application 27 May 2008 | Introduction to Cocoa | 5 .

XCode interface 27 May 2008 | Introduction to Cocoa | 6 .

Interface builder 27 May 2008 | Introduction to Cocoa | 7 .

Drag and drop the interface 27 May 2008 | Introduction to Cocoa | 8 .

Create AppController class “AppController” 27 May 2008 | Introduction to Cocoa | 9 .

Instantiate AppController 27 May 2008 | Introduction to Cocoa | 10 .

Adding outlets 27 May 2008 | Introduction to Cocoa | 11 .

Adding actions 27 May 2008 | Introduction to Cocoa | 12 .

Setting properties 27 May 2008 | Introduction to Cocoa | 13 .

Make connections 27 May 2008 | Introduction to Cocoa | 14 .

Creating files ctrl-drag 27 May 2008 | Introduction to Cocoa | 15 .

(IBAction)updateSliderValue:(id)sender { NSLog(@"updateSliderValue:%f".(IBAction)exportImage:(id)sender { NSLog(@"export:%@". [sender floatValue]).Testing UI output AppController. } 27 May 2008 | Introduction to Cocoa | 16 . sender).m . } .

(id)init { self = [super init]. } 27 May 2008 | Introduction to Cocoa | 17 . } return self. } . exportButton).(void)awakeFromNib { NSLog(@"exportButton=%@".m . if (self) { NSLog(@"exportButton=%@".Availability of UI objects AppController. exportButton).

} .m . } 27 May 2008 | Introduction to Cocoa | 18 .(IBAction)updateSliderValue:(id)sender { [imageSizeText setStringValue:[sender stringValue]].(void)awakeFromNib { [imageSizeText setStringValue:@""].Selectors: setting the size textfield AppController.

shorthand: NSMutableArray* list = [[NSMutableArray alloc] init]. 27 May 2008 | Introduction to Cocoa | 19 .
 [list init]. destroy: [list release].
 list = [NSMutableArray alloc]. initialize object: NSMutableArray* list.
 list = [NSMutableArray alloc].Objective-C is C with extensions object instance: [NSMutableArray alloc] pointer to object: NSMutableArray* list.

selector = insertObject:atIndex: return values: int x = [list count]. multiple arguments: [list insertObject:foo atIndex:5]. 27 May 2008 | Introduction to Cocoa | 20 .Methods method that takes an argument: selector = addObject: [list addObject:foo].

see: + (NSNumber *)numberWithInt:(int)value
 Cocoa class methods return autoreleased objects 27 May 2008 | Introduction to Cocoa | 21 .
 convenience constructor.Memory management with reference counting -alloc -copy allocates memory and returns object with retain count of 1 at 0 the object is deallocated and the memory freed makes a copy of an object. or: [NSNumber numberWithInt:5]. and returns it with retain count of 1 retain count ++ retain count -- -retain -release -autorelease retain count = number of references to the object decreases the reference count of an object by 1 at some stage in the future NSMutableArray* list = 
 [[[NSMutableArray alloc] init] autorelease].

IBOutlet NSButton *exportButton.01.m .com/Articles/Technical/2001-03-11.(void)dealloc { [self setImageFilePath:nil]. AppController. [imageFilePath release].(NSString*)imageFilePath { return imageFilePath. NSString* imageFilePath. } .Member variables: storing the image file path AppController. } .stepwise. IBOutlet NSImageView *imageView.(void)setImageFilePath:(NSString*)newFilePath. } Very simple rules for memory management in Cocoa http://www. [super dealloc]. IBOutlet NSSlider *slider.(void)setImageFilePath:(NSString*)newFilePath { [newFilePath retain]. } .h @interface AppController : NSObject{ IBOutlet NSTextField *imageSizeText. imageFilePath = newFilePath.html 27 May 2008 | Introduction to Cocoa | 22 .

@"gif".(IBAction)showOpenPanel:(id)sender. and update the NIB file .nil] NSString *path = [op filename]. [op beginSheetForDirectory:nil file:nil types:[NSImage imageFileTypes] modalForWindow:[NSApp mainWindow] modalDelegate:self didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:) contextInfo:nil].(void)openPanelDidEnd:(NSOpenPanel *)op only PNG: returnCode:(int)returnCode [NSArray arrayWithObject:@"png"] contextInfo:(void *)ci PNG and GIF: { [NSArray if (returnCode != NSOKButton) return. arrayWithObjects:@"png".Opening an image file in a dialog window AppController.m .(IBAction)showOpenPanel:(id)sender { NSOpenPanel *op = [NSOpenPanel openPanel]. } AppController... } . 27 May 2008 | Introduction to Cocoa | 23 .h .

Connecting the menu in IB 27 May 2008 | Introduction to Cocoa | 24 .

[imageView setImage:image].(BOOL)importImageFromPath:(NSString*)path { NSImage *image = [[[NSImage alloc] initWithContentsOfFile:path] autorelease]. [self setImageFilePath:path]. 27 May 2008 | Introduction to Cocoa | 25 .(void)openPanelDidEnd:(NSOpenPanel *)op returnCode:(int)returnCode contextInfo:(void *)ci { if (returnCode != NSOKButton) return. } [self importImageFromPath:path]. } Update: . NSString *path = [op filename]. if (!image) return NO.m .Putting the image into the view AppController. return YES.

} Step 2: edit app document types. BOOL result = [self importImageFromPath:path]...m . [self setImageFilePath:path].Opening the image file when dragging on app icon Step 1: add code AppController. return YES. 27 May 2008 | Introduction to Cocoa | 26 . if (!result) return NO. Step 3: set the File’s Owner delegate...(BOOL)application:(NSApplication *)theApplication openFile:(NSString *)path { // do a check on filetype here...

Opening target info Command-i 27 May 2008 | Introduction to Cocoa | 27 .

Set the app delegate in IB 27 May 2008 | Introduction to Cocoa | 28 .

27 May 2008 | Introduction to Cocoa | 29 . Step 1: create a new subclass for NSImageView: ImageView Step 2: edit the code @interface ImageView : NSImageView { } Step 3: drag new . Step 4: add drag and drop methods.....h file onto IB and set view to new subclass.Drag and drop onto the app window We need to extend the image view.

Set image view to new subclass in IB 27 May 2008 | Introduction to Cocoa | 30 .

(NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender { return NSDragOperationLink.(BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender { return YES. } .(void)concludeDragOperation:(id <NSDraggingInfo>)sender { [super concludeDragOperation:sender]. } .m @implementation ImageView #pragma mark Drag and drop . } @end 27 May 2008 | Introduction to Cocoa | 31 .(BOOL)performDragOperation:(id <NSDraggingInfo>)sender { return YES.Drag and drop methods ImageView. } .

m .(void)awakeFromNib { [imageSizeText setStringValue:@""].png"]. NSString* path = [[NSBundle mainBundle] pathForImageResource:@"anteprima.Testing: loading an image from the app bundle Drag image on XCode: Resources AppController. [self importImageFromPath:path]. } 27 May 2008 | Introduction to Cocoa | 32 .com.

Show image in real size Override NSImageView’s drawRect: ImageView. [[self image] drawInRect:drawRect fromRect:imageRect operation:NSCompositeSourceOver fraction:1. NSRect drawRect = imageRect.0]. imageRect.(void)drawRect:(NSRect)rect { if ([self image]) { NSRect imageRect. imageRect.size = [[self image] size]. 27 May 2008 | Introduction to Cocoa | 33 . } } The image is now oriented bottom left.origin = NSZeroPoint.m .

} 27 May 2008 | Introduction to Cocoa | 34 .Orient to top left Flip coordinate system: ImageView.(BOOL)isFlipped { return YES.m .

[transform concat].height].0 yBy:1.size = [[self image] size]. NSRect drawRect = imageRect. } } 27 May 2008 | Introduction to Cocoa | 35 . [transform scaleXBy:[zoomFactor floatValue] yBy:-[zoomFactor floatValue]].Use a transformation to flip the image Update drawRect in ImageView. [[self image] drawInRect:drawRect fromRect:imageRect operation:NSCompositeSourceOver fraction:1. imageRect. NSAffineTransform* transform = [NSAffineTransform transform].0 * imageRect. imageRect.size.(void)drawRect:(NSRect)rect { if ([self image]) { NSRect imageRect.origin = NSZeroPoint.m .0]. [transform translateXBy:0.

h @interface ImageView : NSImageView { NSNumber* zoomFactor.Store zoom factor in image view ImageView. } ImageView. } .(void)setZoomFactor:(NSNumber*)newZoomFactor { [newZoomFactor retain]. [zoomFactor release].m . [super dealloc]. } [self setZoomFactor:[NSNumber numberWithFloat:1]]. [self setNeedsDisplay:YES]. } .(id)initWithFrame:(NSRect)frame { if (![super initWithFrame:frame]) { return nil. return self. zoomFactor = newZoomFactor. } 27 May 2008 | Introduction to Cocoa | 36 .(void)dealloc { [self setZoomFactor:nil].

27 May 2008 | Introduction to Cocoa | 37 .Connect the slider value to the image size Replace updateSliderValue in AppController.(IBAction)updateSliderValue:(id)sender { [imageView setZoomFactor:[sender objectValue]].size. } Update drawRect in ImageView.height].m [transform translateXBy:0.m .0 yBy:[zoomFactor floatValue] * imageRect.

imageSize.width *= [zoomFactor floatValue].height *= [zoomFactor floatValue]. } .(void)notifyImageUpdated { [[NSNotificationCenter defaultCenter] postNotificationName:@"imageUpdated" object:[self imageSize]].(NSValue*)imageSize { NSSize imageSize = [[self image] size].m .Getting the image size Using NSNotification messages ImageView. } Add to setZoomFactor: [self notifyImageUpdated]. return [NSValue valueWithSize:imageSize]. 27 May 2008 | Introduction to Cocoa | 38 . imageSize.

0f x %.m [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleImageUpdated:) name:@"imageUpdated" object:nil]. } Update the text field .Receiving the notification Add to awakeFromNib in AppController. [imageSizeText setStringValue:[NSString stringWithFormat:@"%.(void)handleImageUpdated:(NSNotification*)note { NSSize size = [[note object] sizeValue]. } 27 May 2008 | Introduction to Cocoa | 39 . Unsubscribe before AppController is destroyed: . [super dealloc]. size.width.height]].0f". [self setImageFilePath:nil].(void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]. size.

} 27 May 2008 | Introduction to Cocoa | 40 .Update the text field when the image is loaded Override to setImage in ImageView.m . [self notifyImageUpdated].(void)setImage:(NSImage *)image { [super setImage:image].

NSString* draggedFilePath = nil. [self setImageFilePath:imagePath]. } [[NSGraphicsContext currentContext] setImageInterpolation:NSImageInterpolationHigh]. NSPasteboard *pboard = [sender draggingPasteboard].m . draggedFilePath = [files objectAtIndex:0]. } 27 May 2008 | Introduction to Cocoa | 41 .Update the file path when the image is dragged Update concludeDragOperation in ImageView. if ( [[pboard types] containsObject:NSFilenamesPboardType] ) { NSArray *files = [pboard propertyListForType:NSFilenamesPboardType].(void)concludeDragOperation:(id <NSDraggingInfo>)sender { [super concludeDragOperation:sender].m [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleImageDragged:) name:@"imageDragged" object:nil]. . [[NSNotificationCenter defaultCenter] postNotificationName:@"imageDragged" object:draggedFilePath]. } Register for notifications in AppController.(void)handleImageDragged:(NSNotification*)note { NSString* imagePath = [note object].

.h @interface NSArray (PrettyPrintElements) . } @end Create new Cocoa class ImageViewAdditions (m and h files) 27 May 2008 | Introduction to Cocoa | 42 .Export the image: Categories Categories are the prototypes of Cocoa.h" @implementation NSArray (PrettyPrintElements) .(NSString *)prettyPrintDescription.. @end PrettyPrintCategory.(NSString *)prettyPrintDescription { // implementation code here.m #import "PrettyPrintCategory. Extend a class without subclassing PrettyPrintCategory.

h @interface NSImageView (ImageViewAdditions) . } @end 27 May 2008 | Introduction to Cocoa | 43 .0].origin = NSZeroPoint. NSRect scaledRect. scaledRect. return copyOfImage. [sourceImage drawInRect:scaledRect fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.(NSImage*)imageOfSize:(NSSize)size.height.width. [[NSGraphicsContext currentContext] setImageInterpolation:NSImageInterpolationHigh].A category on NSImageView ImageViewAdditions. NSImage* copyOfImage = [[[NSImage alloc] initWithSize:size] autorelease]. scaledRect. [copyOfImage unlockFocus].m @implementation NSImageView (ImageViewAdditions) . [copyOfImage lockFocus]. scaledRect. @end ImageViewAdditions.size.(NSImage*)imageOfSize:(NSSize)size { NSImage* sourceImage = [self image].height = size.width = size.size.

return YES. barePath. size. NSData* fileData = [imageRep representationUsingType:NSPNGFileType properties:nil]. NSString* barePath = [imageFilePath stringByDeletingPathExtension]. size.0f.(NSString*)createFilePath:(NSString*)imageFilePath size:(NSSize)size { NSString *pathExtension = [imageFilePath pathExtension]. BOOL success = [fileData writeToFile:[path stringByExpandingTildeInPath] atomically:YES].(BOOL)saveImage:(NSImage*)image toPath:(NSString*)path { NSData *imageAsData = [image TIFFRepresentation]. NSString* path = [self createFilePath:imageFilePath size:size].height]. } .m: .(IBAction)exportImage:(id)sender { NSSize size = [[imageView imageSize] sizeValue]. NSString* filePath = [path stringByExpandingTildeInPath]. [self saveImage:imageCopy toPath:path].png". NSImage* imageCopy = [imageView imageOfSize:size]. NSBitmapImageRep *imageRep = [NSBitmapImageRep imageRepWithData:imageAsData]. return [NSString stringWithFormat:@"%@_%. } . } 27 May 2008 | Introduction to Cocoa | 44 .0fx%.Export the image In AppController.width.

Result 27 May 2008 | Introduction to Cocoa | 45 .

Sign up to vote on this title
UsefulNot useful