Post on 15-May-2015
description
Introduction to CocoaProgramming for Mac OS X
Arthur Clemens
27 May 2008 - Amsterdam
What are we going to make?
What we are going to create
27 May 2008 | Introduction to Cocoa | 3
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 | 4
http://developer.apple.com/
XCode Tools
27 May 2008 | Introduction to Cocoa | 5
New application
27 May 2008 | Introduction to Cocoa | 6
XCode interface
27 May 2008 | Introduction to Cocoa | 7
Interface builder
27 May 2008 | Introduction to Cocoa | 8
Drag and drop the interface
27 May 2008 | Introduction to Cocoa | 9
Create AppController class
“AppController”
27 May 2008 | Introduction to Cocoa | 10
Instantiate AppController
27 May 2008 | Introduction to Cocoa | 11
Adding outlets
27 May 2008 | Introduction to Cocoa | 12
Adding actions
27 May 2008 | Introduction to Cocoa | 13
Setting properties
27 May 2008 | Introduction to Cocoa | 14
Make connections
27 May 2008 | Introduction to Cocoa | 15
Creating files
ctrl-drag
27 May 2008 | Introduction to Cocoa | 16
Testing UI output
AppController.m
- (IBAction)exportImage:(id)sender{
NSLog(@"export:%@", sender);}
- (IBAction)updateSliderValue:(id)sender{
NSLog(@"updateSliderValue:%f", [sender floatValue]);}
27 May 2008 | Introduction to Cocoa | 17
Availability of UI objects
AppController.m
- (id)init{
self = [super init];if (self) {
NSLog(@"exportButton=%@", exportButton); } return self;}
- (void)awakeFromNib{
NSLog(@"exportButton=%@", exportButton);}
27 May 2008 | Introduction to Cocoa | 18
Selectors: setting the size textfield
AppController.m
- (void)awakeFromNib{
[imageSizeText setStringValue:@""];}
- (IBAction)updateSliderValue:(id)sender{
[imageSizeText setStringValue:[sender stringValue]];}
27 May 2008 | Introduction to Cocoa | 19
Objective-C is C with extensions
object instance:
[NSMutableArray alloc]
pointer to object:
NSMutableArray* list;list = [NSMutableArray alloc];
initialize object:
NSMutableArray* list;list = [NSMutableArray alloc];[list init];
shorthand:
NSMutableArray* list = [[NSMutableArray alloc] init];
destroy:
[list release];
27 May 2008 | Introduction to Cocoa | 20
Methods
method that takes an argument:
selector = addObject:
[list addObject:foo];
multiple arguments:
[list insertObject:foo atIndex:5];
selector = insertObject:atIndex:
return values:
int x = [list count];
27 May 2008 | Introduction to Cocoa | 21
Memory management with reference counting
-alloc allocates memory and returns object with retain count of 1at 0 the object is deallocated and the memory freed
-copy makes a copy of an object, and returns it with retain count of 1
-retain retain count ++
-release retain count --retain count = number of references to the object
-autorelease decreases the reference count of an object by 1 at some stage in the future
NSMutableArray* list = [[[NSMutableArray alloc] init] autorelease];
or:[NSNumber numberWithInt:5];
convenience constructor, see:+ (NSNumber *)numberWithInt:(int)value
Cocoa class methods return autoreleased objects
27 May 2008 | Introduction to Cocoa | 22
Member variables: storing the image file path
AppController.h
@interface AppController : NSObject{ IBOutlet NSTextField *imageSizeText; IBOutlet NSImageView *imageView; IBOutlet NSButton *exportButton; IBOutlet NSSlider *slider;
NSString* imageFilePath;}- (void)setImageFilePath:(NSString*)newFilePath;
AppController.m
- (void)setImageFilePath:(NSString*)newFilePath{
[newFilePath retain];[imageFilePath release];imageFilePath = newFilePath;
}- (NSString*)imageFilePath{
return imageFilePath;}- (void)dealloc { [self setImageFilePath:nil]; [super dealloc];}
Very simple rules for memory management in Cocoahttp://www.stepwise.com/Articles/Technical/2001-03-11.01.html
27 May 2008 | Introduction to Cocoa | 23
Opening an image file in a dialog window
AppController.m
- (IBAction)showOpenPanel:(id)sender{ NSOpenPanel *op = [NSOpenPanel openPanel]; [op beginSheetForDirectory:nil file:nil types:[NSImage imageFileTypes] modalForWindow:[NSApp mainWindow] modalDelegate:self didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:) contextInfo:nil]; }- (void)openPanelDidEnd:(NSOpenPanel *)op returnCode:(int)returnCode contextInfo:(void *)ci{ if (returnCode != NSOKButton) return; NSString *path = [op filename];}
AppController.h
- (IBAction)showOpenPanel:(id)sender; ... and update the NIB file
only PNG:[NSArray arrayWithObject:@"png"]PNG and GIF:[NSArray arrayWithObjects:@"png",@"gif",nil]
27 May 2008 | Introduction to Cocoa | 24
Connecting the menu in IB
27 May 2008 | Introduction to Cocoa | 25
Putting the image into the view
AppController.m
- (BOOL)importImageFromPath:(NSString*)path{
NSImage *image = [[[NSImage alloc] initWithContentsOfFile:path] autorelease];if (!image) return NO;[imageView setImage:image];return YES;
}
Update:
- (void)openPanelDidEnd:(NSOpenPanel *)op returnCode:(int)returnCode contextInfo:(void *)ci{ if (returnCode != NSOKButton) return; NSString *path = [op filename];
[self importImageFromPath:path];[self setImageFilePath:path];
}
27 May 2008 | Introduction to Cocoa | 26
Opening the image file when dragging on app icon
Step 1: add code
AppController.m
- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)path{
// do a check on filetype here...BOOL result = [self importImageFromPath:path];if (!result) return NO;[self setImageFilePath:path];return YES;
}
Step 2: edit app document types...
Step 3: set the File’s Owner delegate...
27 May 2008 | Introduction to Cocoa | 27
Opening target info
Command-i
27 May 2008 | Introduction to Cocoa | 28
Set the app delegate in IB
27 May 2008 | Introduction to Cocoa | 29
Drag and drop onto the app window
We need to extend the image view.
Step 1: create a new subclass for NSImageView: ImageView
Step 2: edit the code
@interface ImageView : NSImageView{}
Step 3: drag new .h file onto IB and set view to new subclass...
Step 4: add drag and drop methods...
27 May 2008 | Introduction to Cocoa | 30
Set image view to new subclass in IB
27 May 2008 | Introduction to Cocoa | 31
Drag and drop methods
ImageView.m
@implementation ImageView
#pragma mark Drag and drop
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender{ return NSDragOperationLink;}- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender{ return YES;}- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender{ return YES;}- (void)concludeDragOperation:(id <NSDraggingInfo>)sender{ [super concludeDragOperation:sender];}
@end
27 May 2008 | Introduction to Cocoa | 32
Testing: loading an image from the app bundle
Drag image on XCode: Resources
AppController.m
- (void)awakeFromNib{ [imageSizeText setStringValue:@""]; NSString* path = [[NSBundle mainBundle] pathForImageResource:@"anteprima.com.png"]; [self importImageFromPath:path];}
27 May 2008 | Introduction to Cocoa | 33
Show image in real size
Override NSImageView’s drawRect:
ImageView.m
- (void)drawRect:(NSRect)rect{ if ([self image]) { NSRect imageRect; imageRect.origin = NSZeroPoint; imageRect.size = [[self image] size]; NSRect drawRect = imageRect; [[self image] drawInRect:drawRect fromRect:imageRect operation:NSCompositeSourceOver fraction:1.0]; }}
The image is now oriented bottom left.
27 May 2008 | Introduction to Cocoa | 34
Orient to top left
Flip coordinate system:
ImageView.m
- (BOOL)isFlipped{ return YES;}
27 May 2008 | Introduction to Cocoa | 35
Use a transformation to flip the image
Update drawRect in ImageView.m
- (void)drawRect:(NSRect)rect{ if ([self image]) { NSRect imageRect; imageRect.origin = NSZeroPoint; imageRect.size = [[self image] size]; NSAffineTransform* transform = [NSAffineTransform transform]; [transform translateXBy:0.0 yBy:1.0 * imageRect.size.height]; [transform scaleXBy:[zoomFactor floatValue] yBy:-[zoomFactor floatValue]]; [transform concat]; NSRect drawRect = imageRect; [[self image] drawInRect:drawRect fromRect:imageRect operation:NSCompositeSourceOver fraction:1.0]; }}
27 May 2008 | Introduction to Cocoa | 36
Store zoom factor in image view
ImageView.h
@interface ImageView : NSImageView { NSNumber* zoomFactor;}
ImageView.m
- (void)setZoomFactor:(NSNumber*)newZoomFactor{ [newZoomFactor retain]; [zoomFactor release]; zoomFactor = newZoomFactor; [self setNeedsDisplay:YES];}- (void)dealloc{ [self setZoomFactor:nil]; [super dealloc];}- (id)initWithFrame:(NSRect)frame { if (![super initWithFrame:frame]) { return nil; } [self setZoomFactor:[NSNumber numberWithFloat:1]]; return self;}
27 May 2008 | Introduction to Cocoa | 37
Connect the slider value to the image size
Replace updateSliderValue in AppController.m
- (IBAction)updateSliderValue:(id)sender{ [imageView setZoomFactor:[sender objectValue]];}
Update drawRect in ImageView.m
[transform translateXBy:0.0 yBy:[zoomFactor floatValue] * imageRect.size.height];
27 May 2008 | Introduction to Cocoa | 38
Getting the image size
Using NSNotification messages
ImageView.m
- (void)notifyImageUpdated{ [[NSNotificationCenter defaultCenter] postNotificationName:@"imageUpdated" object:[self imageSize]];}- (NSValue*)imageSize{ NSSize imageSize = [[self image] size]; imageSize.width *= [zoomFactor floatValue]; imageSize.height *= [zoomFactor floatValue]; return [NSValue valueWithSize:imageSize];}
Add to setZoomFactor:
[self notifyImageUpdated];
27 May 2008 | Introduction to Cocoa | 39
Receiving the notification
Add to awakeFromNib in AppController.m
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleImageUpdated:) name:@"imageUpdated" object:nil];
Unsubscribe before AppController is destroyed:
- (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; [self setImageFilePath:nil]; [super dealloc];}
Update the text field
- (void)handleImageUpdated:(NSNotification*)note{ NSSize size = [[note object] sizeValue]; [imageSizeText setStringValue:[NSString stringWithFormat:@"%.0f x %.0f", size.width, size.height]];}
27 May 2008 | Introduction to Cocoa | 40
Update the text field when the image is loaded
Override to setImage in ImageView.m
- (void)setImage:(NSImage *)image{ [super setImage:image]; [self notifyImageUpdated];}
27 May 2008 | Introduction to Cocoa | 41
Update the file path when the image is dragged
Update concludeDragOperation in ImageView.m
- (void)concludeDragOperation:(id <NSDraggingInfo>)sender{ [super concludeDragOperation:sender]; NSPasteboard *pboard = [sender draggingPasteboard]; NSString* draggedFilePath = nil; if ( [[pboard types] containsObject:NSFilenamesPboardType] ) { NSArray *files = [pboard propertyListForType:NSFilenamesPboardType]; draggedFilePath = [files objectAtIndex:0]; } [[NSGraphicsContext currentContext] setImageInterpolation:NSImageInterpolationHigh]; [[NSNotificationCenter defaultCenter] postNotificationName:@"imageDragged" object:draggedFilePath];}
Register for notifications in AppController.m
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleImageDragged:) name:@"imageDragged" object:nil];
- (void)handleImageDragged:(NSNotification*)note{ NSString* imagePath = [note object]; [self setImageFilePath:imagePath];}
27 May 2008 | Introduction to Cocoa | 42
Export the image: Categories
Categories are the prototypes of Cocoa.
Extend a class without subclassing
PrettyPrintCategory.h
@interface NSArray (PrettyPrintElements)- (NSString *)prettyPrintDescription;@end
PrettyPrintCategory.m
#import "PrettyPrintCategory.h"
@implementation NSArray (PrettyPrintElements)- (NSString *)prettyPrintDescription { // implementation code here...}
@end
Create new Cocoa class ImageViewAdditions (m and h files)
27 May 2008 | Introduction to Cocoa | 43
A category on NSImageView
ImageViewAdditions.h
@interface NSImageView (ImageViewAdditions)- (NSImage*)imageOfSize:(NSSize)size;@end
ImageViewAdditions.m
@implementation NSImageView (ImageViewAdditions)
- (NSImage*)imageOfSize:(NSSize)size{
NSImage* sourceImage = [self image];NSRect scaledRect;scaledRect.origin = NSZeroPoint;scaledRect.size.width = size.width;scaledRect.size.height = size.height;NSImage* copyOfImage = [[[NSImage alloc] initWithSize:size] autorelease];[copyOfImage lockFocus];[[NSGraphicsContext currentContext] setImageInterpolation:NSImageInterpolationHigh];[sourceImage drawInRect:scaledRect
fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
[copyOfImage unlockFocus];return copyOfImage;
}
@end
27 May 2008 | Introduction to Cocoa | 44
Export the image
In AppController.m:
- (IBAction)exportImage:(id)sender{ NSSize size = [[imageView imageSize] sizeValue]; NSString* path = [self createFilePath:imageFilePath size:size]; NSImage* imageCopy = [imageView imageOfSize:size]; [self saveImage:imageCopy toPath:path];}
- (NSString*)createFilePath:(NSString*)imageFilePath size:(NSSize)size{ NSString *pathExtension = [imageFilePath pathExtension]; NSString* barePath = [imageFilePath stringByDeletingPathExtension]; return [NSString stringWithFormat:@"%@_%.0fx%.0f.png", barePath, size.width, size.height];}
- (BOOL)saveImage:(NSImage*)image toPath:(NSString*)path{
NSData *imageAsData = [image TIFFRepresentation];NSBitmapImageRep *imageRep = [NSBitmapImageRep imageRepWithData:imageAsData];NSData* fileData = [imageRep representationUsingType:NSPNGFileType properties:nil];NSString* filePath = [path stringByExpandingTildeInPath];BOOL success = [fileData writeToFile:[path stringByExpandingTildeInPath] atomically:YES];return YES;
}
27 May 2008 | Introduction to Cocoa | 45
Result