You are on page 1of 53

CS193P - Lecture 6

iPhone Application Development

More Views
Autorelease
User Defaults
Today’s Topics
• Questions from previous lectures or assignments?
• More view topics
■ Additional view types
• Advanced memory management - autorelease
■ aka, “why don’t I have to release that object?”
• User Defaults
■ Easily store and retrieve small bits of data
More View Stuff
Constructing Views
• What’s the right way to
implement this?
• Goal
■ Single PolygonView that displays
shape as well as name
Constructing Views
• What’s the right way to
implement this?
• Goal
■ Single PolygonView that displays
shape as well as name
• Initial thought
■ Simply have PolygonView draw
the text
■ Inefficient if you want to animate

■ Views would have to redraw


Constructing Views
• What’s the right way to
implement this?
• Goal
■ Single PolygonView that displays
shape as well as name
• Initial thought
■ Simply have PolygonView draw
the text
■ Inefficient if you want to animate

■ Views would have to redraw

• Instead use UILabel as subview


■ CA can animate without redraw
Drawing Other Things
• Images
• Text
Drawing Text
• Generally don’t draw text manually
■ Instead, use UILabels and insert as subviews
• But, if you really have to draw text....
■ NSString functionality
@interface NSString
- (CGSize)drawAtPoint:(CGPoint)point withFont:(UIFont *)font;

- (CGSize)sizeWithFont:(UIFont *)font
minFontSize:(CGFloat)minSize
actualFontSize:(CGFloat *)actualSize
forWidth:(CGFloat)width
lineBreakMode:(UILineBreakMode)mode;
@end

• Additional methods in NSString UIKit Additions Reference


Drawing Text
- (void)drawRect:(CGRect)rect {
CGRect bounds = [self bounds];
NSString *string = @"Hunting The Snark";
UIFont *font = [UIFont boldSystemFontOfSize:32];
CGSize size = [string sizeWithFont:font];

// center vertically and horizontally


bounds.origin.x = (bounds.size.width – size.width) / 2.0;
bounds.origin.y = (bounds.size.height – size.height) / 2.0;

[string drawAtPoint: bounds.origin withFont: font];


}
Wait a minute...
• NSString, a Foundation model-level class, knows how to draw?
■ Send in the MVC Police!
Wait a minute...
• NSString, a Foundation model-level class, knows how to draw?
■ Send in the MVC Police!
• Welcome to world of Objective-C categories
■ Categories allow you to add methods to classes
■ Without having access to source of original class
■ Access instance variables of original class
■ ...but can’t add any new ones
■ Let’s you partition a large class across multiple .m files
Declaring Categories
• Similar to regular class syntax
■ Interface (.h file)
■ Implementation (.m file)

• Minor differences
■ No superclass declaration
■ No instance variables
Interface Declaration
In UIStringDrawing.h
Category name

#import <Foundation/NSString.h>

@interface NSString (UIStringDrawing)

- (CGSize)sizeWithFont:(UIFont *)font;
- (CGSize)drawAtPoint:(CGPoint *)point withFont:(UIFont *)font;

@end
Implementation Declaration
In UIStringDrawing.m
Category name

#import “UIStringDrawing.h”

@implementation NSString (UIStringDrawing)

- (CGSize)sizeWithFont:(UIFont *)font {
....
}
- (CGSize)drawAtPoint:(CGPoint *)point withFont:(UIFont *)font {
....
}

@end
Images
• UIImage
■ Object representation of an image
• UIImageView
■ A view that contains an image, displays a UIImage
Creating Images
• Include in project using Xcode
■ Use +[UIImage imageNamed:(NSString *)name]
■ Include file extension in file name, e.g. @”myImage.jpg”

• Read from file on disk


■ Use -[UIImage initWithContentsOfFile:(NSString *)path]
• From data in memory
■ Use -[UIImage initWithData:(NSData *)data]
Drawing Images
• Drawing at point
CGRect bounds = [self bounds];

UIImage *myImage;

myImage = [UIImage imageNamed:@"image.jpg"];

[myImage drawAtPoint: bounds.origin];

• Drawing into rectangle


UIImage * myImage = [UIImage imageNamed:@"myImage.jpg"];

[myImage drawInRect: bounds];

• Drawing as pattern
UIImage * myImage = [UIImage imageNamed:@"myImage.jpg"];

[myImage drawAsPatternInRect: bounds];


View Tags
• Want to access a view but don’t have an outlet to it directly
• Views have a tag property
■ Simple int value on UIView, default is 0
■ Set in IB or in code

• Later when you need to find a tagged view


@interface UIView
- (UIView *)viewWithTag:(int)tag;
@end
• Returns nil if view not found
• Recursively searches receiving view
Creating Bitmap in Memory
• Need to dynamically generate a bitmap image
• Leverage same code used for drawing anything else
• General steps
■ Create a special CGGraphicsContext with a size
■ Invoke drawing code

■ Capture the current bitmap image

■ Clean up the context


Bitmap Image Example
- (UIImage *)polygonImageOfSize:(CGSize)size {
UIImage *result = nil;

UIGraphicsBeginImageContext (size);

// call your drawing code...

result = UIGraphicsGetImageFromCurrentContext();

UIGraphicsEndImageContext();

return result;
}
Getting Image Data
• Given UIImage, want PNG or JPG representation
NSData *UIImagePNGRepresentation (UIImage * image);
NSData *UIImageJPGRepresentation (UIImage * image);
• UIImage also has a CGImage property which will give you a
CGImageRef to use with CG calls
User Defaults
User Defaults
• Simple system for storing and retrieving preferences
• Only used for “small” amounts of data
■ Don’t store things like documents or images here
• What can you store in defaults?
■ Any property list types
■ NSString, NSArray, NSDictionary, NSNumber, NSDate, NSData

• For other objects, encode as NSData


■ For example, NSColors
Storing Simple Values
• For example, a number or boolean value
• First get a user defaults object
@interface NSUserDefaults
+ (NSUserDefaults *)standardUserDefaults;
@end
• NSUserDefaults look and feel a lot like an NSDictionary
- (id)objectForKey:(NSString *)key;
- (void)setObject:(id)object forKey:(NSString *)key;
- (void)removeObjectForKey:(NSString *)key;
• Set and get objects for keys
■ Additional convenience methods for common types
Storing Simple Values
• Additional convenience methods for common types
- (void)setObject:(id)object forKey:(NSString *)key;
- (void)setBool:(BOOL)bool forKey:(NSString *)key;
- (void)setInteger:(int)value forKey:(NSString *)key;
- (void)setFloat:(float)value forKey:(NSString *)key;

- (id)objectForKey:(NSString *)key;
- (BOOL)boolForKey:(NSString *)key;
- (int)integerForKey:(NSString *)key;
- (float)floatForKey:(NSString *)key;
User Defaults Example - Saving
• At an appropriate time, save the changed values
■ Commonly right where the change happens
■ Alternatively in delegate’s applicationWillTerminate: method

■ Be mindful of performance

- (IBAction)showAdvancedOptions {
NSUserDefaults *defaults;
BOOL isOn = advancedOptions.isOn;

// show the advanced options...

defaults = [NSUserDefaults standardUserDefaults];


[defaults setBool:isOn forKey:@”ShowAdvancedOptions”];
}
User Defaults Example - Loading
• At an appropriate time, load the stored values
■ Commonly app delegate’s applicationDidFinishLaunching: method
■ Perhaps in awakeFromNib if loading additional nibs dynamically

- (void)applicationDidFinishLaunching:(NSNotification *)note {
NSUserDefaults *defaults;
BOOL isOn = NO;

defaults = [NSUserDefaults standardUserDefaults];


isOn = [defaults boolForKey:@”ShowAdvancedOptions”];

// update the UI accordingly...


}
Property List Types
- (void)saveColors {
NSUserDefaults *defaults;
NSDictionary *favorites;
NSArray *colors;

colors = [NSArray arrayWithObjects:@”Red”,


@”Green”, @”Blue”, nil];
favorites = [NSDictionary dictionaryWithObjectsAndKeys:
@”Blue”, @”FavoriteColor”,
@”Green”, @”LeastFavoriteColor”, nil];

defaults = [NSUserDefaults standardUserDefaults];


[defaults setObject:colors forKey:@”UserColors”];
[defaults setObject:favorites forKey:@”FavoriteColors”];
}
Autorelease
What Is autorelease
• autorelease flags an object to be sent release at some point in
the future
• Let’s you complete your retain/release obligations while
allowing an object some additional time to live
• Useful when returning newly created objects to a caller
■ Examples illustrate the issue...
Problem Cases
- (NSString *)fullName {
NSString *result;

result = [[NSString alloc] initWithFormat:@”%@ %@”,


firstName, lastName];

return result;
}
Problem Cases
- (NSString *)fullName {
NSString *result;

result = [[NSString alloc] initWithFormat:@”%@ %@”,


firstName, lastName];

return result;
}
Wrong: result is leaked!
Problem Cases
- (NSString *)fullName {
NSString *result;

result = [[NSString alloc] initWithFormat:@”%@ %@”,


firstName, lastName];

[result release];
return result;
}
Problem Cases
- (NSString *)fullName {
NSString *result;

result = [[NSString alloc] initWithFormat:@”%@ %@”,


firstName, lastName];

[result release];
return result;
}

Wrong: result is released too early!


Caller gets bogus object returned
Problem Cases
- (NSString *)fullName {
NSString *result;

result = [[NSString alloc] initWithFormat:@”%@ %@”,


firstName, lastName];

return result;
}
Problem Cases
- (NSString *)fullName {
NSString *result;

result = [[NSString alloc] initWithFormat:@”%@ %@”,


firstName, lastName];

[result autorelease];
return result;
}
Problem Cases
- (NSString *)fullName {
NSString *result;

result = [[NSString alloc] initWithFormat:@”%@ %@”,


firstName, lastName];

[result autorelease];
return result;
}

Just right: result is released, but not immediately


Caller gets valid object and could retain if needed
Non-alloc/copy Methods
■ Let’s revisit why you don’t have to release objects from non-alloc or
copy methods
NSMutableString *theString = [NSMutableString string];

// You don’t have to release theString because you didn’t


// alloc or copy it
Non-alloc/copy Methods
■ Let’s revisit why you don’t have to release objects from non-alloc or
copy methods
NSMutableString *theString = [NSMutableString string];

// You don’t have to release theString because you didn’t


// alloc or copy it

+ (NSMutableString *)string {
return [[[self alloc] init] autorelease];
}
What Happens In autorelease?
• Receiving object is added to current autorelease pool
• Autorelease pools collect objects scheduled to receive release
■ when pool itself is released, it sends release to all objects in pool
• UIKit wraps pool around every event dispatch
AutoreleasePools (in pictures)

a pp ed ib t t p
h i z n en en p
nc t ia l
ain re
v e v it a
Lau ni fo le Ex
p i
adm i t nd
Ap Lo Wa Ha
AutoreleasePools (in pictures)

Pool created

a pp ed ib t t p
h i z n en en p
nc t ia l
ain re
v e v it a
Lau ni fo le Ex
p i
adm i t nd
Ap Lo Wa Ha
AutoreleasePools (in pictures)

Objects autoreleased
here go into pool

Pool created

a pp ed ib t t p
h i z n en en p
nc t ia l
ain re
v e v it a
Lau ni fo le Ex
p i
adm i t nd
Ap Lo Wa Ha
AutoreleasePools (in pictures)

Objects autoreleased
here go into pool

Pool created

a pp ed ib t t p
h i z n en en p
nc t ia l
ain re
v e v it a
Lau ni fo le Ex
p i
adm i t nd
Ap Lo Wa Ha
AutoreleasePools (in pictures)

Objects autoreleased
here go into pool

[object
autorelease];

Pool created

a pp ed ib t t p
h i z n en en p
nc t ia l
ain re
v e v it a
Lau ni fo le Ex
p i
adm i t nd
Ap Lo Wa Ha
AutoreleasePools (in pictures)

Objects autoreleased
here go into pool

Pool created

a pp ed ib t t p
h i z n en en p
nc t ia l
ain re
v e v it a
Lau ni fo le Ex
p i
adm i t nd
Ap Lo Wa Ha
AutoreleasePools (in pictures)

Objects autoreleased
here go into pool

Pool created

a pp ed ib t t p
h i z n en en p
nc t ia l
ain re
v e v it a
Lau ni fo le Ex
p i
adm i t nd
Ap Lo Wa Ha
AutoreleasePools (in pictures)

Objects autoreleased
here go into pool

Pool released

Pool created

a pp ed ib t t p
h i z n en en p
nc t ia l
ain re
v e v it a
Lau ni fo le Ex
p i
adm i t nd
Ap Lo Wa Ha
AutoreleasePools (in pictures)
[object release];

Objects autoreleased
[object release]; here go into pool

[object release];
Pool released

Pool created

a pp ed ib t t p
h i z n en en p
nc t ia l
ain re
v e v it a
Lau ni fo le Ex
p i
adm i t nd
Ap Lo Wa Ha
AutoreleasePools (in pictures)

Objects autoreleased
here go into pool

Pool released

Pool created

a pp ed ib t t p
h i z n en en p
nc t ia l
ain re
v e v it a
Lau ni fo le Ex
p i
adm i t nd
Ap Lo Wa Ha
autorelease Conventions
• Methods that aren’t alloc/copy return autoreleased objects
■ They’re hanging out in the pool and will get a release later
• If you need to hold onto those objects you need to retain them
■ Bumps up the retain count before the release happens
Manual Autorelease Pools
• In some cases where lots of objects are created and
autoreleased quickly, may want a local pool
• Pools nest and objects get put into most recent pool
• Reduced peak memory usage
NSAutoreleasePool *pool;

while (10000) {
pool = [[NSAutoreleasePool alloc] init];

// do stuff that generates lots


// of autoreleased objects

[pool release];
}
Questions?

You might also like