Modern Objective-C

62
Pragma Night @ Talent Garden Modern Objective-C Giuseppe Arici

description

Slides from Modern Objective-C by Giuseppe Arici @ Pragma Night

Transcript of Modern Objective-C

Page 1: Modern Objective-C

Pragma Night @ Talent Garden

Modern Objective-C

Giuseppe Arici

Page 2: Modern Objective-C

Pragma Night

It’s All About ...

Syntactic Sugar

Page 3: Modern Objective-C

Pragma Night

Unordered Method Declarations

Page 4: Modern Objective-C

Pragma Night

Public & Private Method Ordering

@interface SongPlayer : NSObject- (void)playSong:(Song *)song;

@end

@implementation SongPlayer- (void)playSong:(Song *)song { NSError *error; [self startAudio:&error]; /* ... */}

- (void)startAudio:(NSError **)error { /* ... */ }@endWarning:

instance method '-startAudio:' not found (return type defaults to 'id')

Page 5: Modern Objective-C

Pragma Night

Wrong Workaround

@interface SongPlayer : NSObject- (void)playSong:(Song *)song;- (void)startAudio:(NSError **)error;@end

@implementation SongPlayer- (void)playSong:(Song *)song { NSError *error; [self startAudio:&error]; /* ... */}

- (void)startAudio:(NSError **)error { /* ... */ }@end

In the public interface

Page 6: Modern Objective-C

Pragma Night

Okay Workaround 1

@interface SongPlayer ()

- (void)startAudio:(NSError **)error;@end

@implementation SongPlayer- (void)playSong:(Song *)song { NSError *error; [self startAudio:&error]; /* ... */}

- (void)startAudio:(NSError **)error { /* ... */ }@end

In a class extension

Page 7: Modern Objective-C

Pragma Night

Okay Workaround 2

@interface SongPlayer : NSObject- (void)playSong:(Song *)song;

@end

@implementation SongPlayer- (void)startAudio:(NSError **)error { /* ... */ }- (void)playSong:(Song *)song { NSError *error; [self startAudio:&error]; /* ... */}

@end

Reorder methods

Page 8: Modern Objective-C

Pragma Night

Best Solution

@interface SongPlayer : NSObject- (void)playSong:(Song *)song;

@end

@implementation SongPlayer- (void)playSong:(Song *)song { NSError *error; [self startAudio:&error]; /* ... */}

- (void)startAudio:(NSError **)error { /* ... */ }@end

Parse the @implementation declarations then bodies

Xcode 4.4+

Page 9: Modern Objective-C

Pragma Night

Enum with Fixed Underlying Type

Page 10: Modern Objective-C

Pragma Night

Enum with Indeterminate Type

typedef enum { NSNumberFormatterNoStyle, NSNumberFormatterDecimalStyle, NSNumberFormatterCurrencyStyle, NSNumberFormatterPercentStyle, NSNumberFormatterScientificStyle, NSNumberFormatterSpellOutStyle} NSNumberFormatterStyle;

//typedef int NSNumberFormatterStyle;

Before OS X v10.5 and iOS

Page 11: Modern Objective-C

Pragma Night

Enum with Explicit Type

enum { NSNumberFormatterNoStyle, NSNumberFormatterDecimalStyle, NSNumberFormatterCurrencyStyle, NSNumberFormatterPercentStyle, NSNumberFormatterScientificStyle, NSNumberFormatterSpellOutStyle};

typedef NSUInteger NSNumberFormatterStyle;

After OS X v10.5 and iOS

• Pro: 32-bit and 64-bit portability

• Con: no formal relationship between type and enum constants

Page 12: Modern Objective-C

Pragma Night

Enum with Fixed Underlying Type

typedef enum NSNumberFormatterStyle : NSUInteger { NSNumberFormatterNoStyle, NSNumberFormatterDecimalStyle, NSNumberFormatterCurrencyStyle, NSNumberFormatterPercentStyle, NSNumberFormatterScientificStyle, NSNumberFormatterSpellOutStyle} NSNumberFormatterStyle;

LLVM 4.2+ Compiler

• Stronger type checking

• Better code completion

Xcode 4.4+

Page 13: Modern Objective-C

Pragma Night

Enum with Fixed Underlying Type

typedef NS_ENUM(NSUInteger, NSNumberFormatterStyle) { NSNumberFormatterNoStyle, NSNumberFormatterDecimalStyle, NSNumberFormatterCurrencyStyle, NSNumberFormatterPercentStyle, NSNumberFormatterScientificStyle, NSNumberFormatterSpellOutStyle};

NS_ENUM macro

• Foundation declares like this

Xcode 4.4+

Page 14: Modern Objective-C

Pragma Night

Enum with Fixed Underlying Type

NSNumberFormatterStyle style = NSNumberFormatterRoundUp; // 3

Stronger type checking (-Wenum-conversion)

warning:implicit conversion from enumeration type 'enum NSNumberFormatterRoundingMode' to different enumeration type 'NSNumberFormatterStyle' (aka 'enum NSNumberFormatterStyle')

Page 15: Modern Objective-C

Pragma Night

Enum with Fixed Underlying Type

- (void) printStyle:(NSNumberFormatterStyle) style{ switch (style) { case NSNumberFormatterNoStyle: break; case NSNumberFormatterSpellOutStyle: break; }}

Handling all enum values (-Wswitch)

warning: 4 enumeration values not handled in switch: 'NSNumberFormatterDecimalStyle', 'NSNumberFormatterCurrencyStyle', 'NSNumberFormatterPercentStyle'...

Page 16: Modern Objective-C

Pragma Night

@Synthesize by Default

Page 17: Modern Objective-C

Pragma Night

Properties Simplify Classes

@interface Person : NSObject { NSString *_name;}@property(strong) NSString *name;@end

@implementation Person

@synthesize name = _name;

@end

@interface instance variables

Page 18: Modern Objective-C

Pragma Night

Properties Simplify Classes

@interface Person : NSObject

@property(strong) NSString *name;@end

@implementation Person { NSString *_name;}

@synthesize name = _name;

@end

@implementation instance variables

Page 19: Modern Objective-C

Pragma Night

Properties Simplify Classes

@interface Person : NSObject

@property(strong) NSString *name;@end

@implementation Person

@synthesize name = _name;

@end

Synthesized instance variables

Page 20: Modern Objective-C

Pragma Night

@Synthesize by Default

@interface Person : NSObject

@property(strong) NSString *name;@end

@implementation Person

@end

LLVM 4.2+ Compiler

Xcode 4.4+

Page 21: Modern Objective-C

Pragma Night

Instance Variable Name !?

@interface Person : NSObject

@property(strong) NSString *name;@end

@implementation Person- (NSString *)description { return _name;}/* as if you'd written: @synthesize name = _name; */

@end

Instance variables now prefixed with “_”

Xcode 4.4+

Page 22: Modern Objective-C

Pragma Night

Backward Compatibility !?

@interface Person : NSObject

@property(strong) NSString *name;@end

@implementation Person

@synthesize name;/* as if you'd written: @synthesize name = name; */@end

Be careful, when in doubt be fully explicit

Page 23: Modern Objective-C

Pragma Night

To ⇒ @Synthesize by Default

• Warning: @Synthesize by Default will not synthesize a property declared in a protocol

• If you use custom instance variable naming convention, enable this warning( -Wobjc-missing-property-synthesis )

Page 24: Modern Objective-C

Pragma Night

Core Data NSManagedObject

/* NSManagedObject.h */

NS_REQUIRES_PROPERTY_DEFINITIONS@interface NSManagedObject : NSObject {

Opts out of synthesize by default

• NSManagedObject synthesizes properties

• Continue to use @property to declare typed accessors

• Continue to use @dynamic to inhibit warnings

Page 25: Modern Objective-C

Pragma Night

NSNumbers Literals

Page 26: Modern Objective-C

Pragma Night

NSNumber Creation

NSNumber *value;

value = [NSNumber numberWithChar:'X'];

value = [NSNumber numberWithInt:42];

value = [NSNumber numberWithUnsignedLong:42ul];

value = [NSNumber numberWithLongLong:42ll];

value = [NSNumber numberWithFloat:0.42f];

value = [NSNumber numberWithDouble:0.42];

value = [NSNumber numberWithBool:YES];

Page 27: Modern Objective-C

Pragma Night

NSNumber Creation

NSNumber *value;

value = @'X';

value = @42;

value = @42ul;

value = @42ll;

value = @0.42f;

value = @0.42;

value = @YES;

Xcode 4.4+

Page 28: Modern Objective-C

Pragma Night

Backward Compatibility !?

#define YES (BOOL)1 // Before iOS 6, OSX 10.8

#define YES ((BOOL)1) // After iOS 6, OSX 10.8

@(YES) // Use parentheses around BOOL Macros

Workarounds

#if __IPHONE_OS_VERSION_MAX_ALLOWED < 60000#if __has_feature(objc_bool)#undef YES#undef NO#define YES __objc_yes#define NO __objc_no#endif#endif

// Redefine BOOL Macros

Page 29: Modern Objective-C

Pragma Night

Boxed Expression Literals

Page 30: Modern Objective-C

Pragma Night

Boxed Expression Literals

NSNumber *orientation = [NSNumber numberWithInt:UIDeviceOrientationPortrait];

NSNumber *piOverSixteen = [NSNumber numberWithDouble:( M_PI / 16 )]; NSNumber *parityDigit = [NSNumber numberWithChar:"EO"[i % 2]]; NSString *path = [NSString stringWithUTF8String:getenv("PATH")];

NSNumber *usesCompass = [NSNumber numberWithBool: [CLLocationManager headingAvailable]];

Page 31: Modern Objective-C

Pragma Night

Boxed Expression Literals

NSNumber *orientation = @( UIDeviceOrientationPortrait );

NSNumber *piOverSixteen = @( M_PI / 16 ); NSNumber *parityDigit = @( "OE"[i % 2] ); NSString *path = @( getenv("PATH") );

NSNumber *usesCompass = @( [CLLocationManager headingAvailable] );

Xcode 4.4+

Page 32: Modern Objective-C

Pragma Night

Array Literals

Page 33: Modern Objective-C

Pragma Night

Array Creation

More choices, and more chances for errors

NSArray *array;

array = [NSArray array];

array = [NSArray arrayWithObject:a];

array = [NSArray arrayWithObjects:a, b, c, nil];

id objects[] = { a, b, c };NSUInteger count = sizeof(objects) / sizeof(id);array = [NSArray arrayWithObjects:objects count:count];

Page 34: Modern Objective-C

Pragma Night

// if you write:id objects[] = { nil, @"hello", @42 };NSUInteger count = sizeof(objects)/ sizeof(id);NSArray *array = [NSArray arrayWithObjects:objects count:count];

Nil Termination

// if you write:id a = nil, b = @"hello", c = @42;NSArray *array = [NSArray arrayWithObjects:a, b, c, nil];

Inconsistent behavior

Array will be empty

Exception: attempt to insert nil object from objects[0]

Page 35: Modern Objective-C

Pragma Night

Array Creation

NSArray *array;

array = [NSArray array];

array = [NSArray arrayWithObject:a];

array = [NSArray arrayWithObjects:a, b, c, nil];

id objects[] = { a, b, c };NSUInteger count = sizeof(objects) / sizeof(id);array = [NSArray arrayWithObjects:objects count:count];

Page 36: Modern Objective-C

Pragma Night

Array Creation

NSArray *array;

array = @[];

array = @[ a ];

array = @[ a, b, c ];

array = @[ a, b, c ];

Xcode 4.4+

Page 37: Modern Objective-C

Pragma Night

// compiler generates:

id objects[] = { a, b, c };NSUInteger count = sizeof(objects)/ sizeof(id);NSArray *array = [NSArray arrayWithObjects:objects count:count];

How Array Literals Work

// when you write this:

NSArray *array = @[ a, b, c ];

Page 38: Modern Objective-C

Pragma Night

Dictionary Literals

Page 39: Modern Objective-C

Pragma Night

NSDictionary *dict;

dict = [NSDictionary dictionary];

dict = [NSDictionary dictionaryWithObject:o1 forKey:k1];

dict = [NSDictionary dictionaryWithObjectsAndKeys: o1, k1, o2, k2, o3, k3, nil];

id objects[] = { o1, o2, o3 };id keys[] = { k1, k2, k3 };NSUInteger count = sizeof(objects) / sizeof(id);dict = [NSDictionary dictionaryWithObjects:objects forKeys:keys count:count];

Dictionary Creation

More choices, and more chances for errors

Page 40: Modern Objective-C

Pragma Night

Dictionary Creation

NSDictionary *dict;

dict = [NSDictionary dictionary];

dict = [NSDictionary dictionaryWithObject:o1 forKey:k1];

dict = [NSDictionary dictionaryWithObjectsAndKeys: o1, k1, o2, k2, o3, k3, nil];

id objects[] = { o1, o2, o3 };id keys[] = { k1, k2, k3 };NSUInteger count = sizeof(objects) / sizeof(id);dict = [NSDictionary dictionaryWithObjects:objects forKeys:keys count:count];

Page 41: Modern Objective-C

Pragma Night

Dictionary Creation

NSDictionary *dict;

dict = @{};

dict = @{ k1 : o1 }; // key before object

dict = @{ k1 : o1, k2 : o2, k3 : o3 };

dict = @{ k1 : o1, k2 : o2, k3 : o3 };

Xcode 4.4+

Page 42: Modern Objective-C

Pragma Night

// compiler generates:

id objects[] = { o1, o2, o3 };id keys[] = { k1, k2, k3 };NSUInteger count = sizeof(objects) / sizeof(id);NSDictionary *dict = [NSDictionary dictionaryWithObjects:objects orKeys:keys count:count];

How Dictionary Literals Work

// when you write this:

NSDictionary *dict = @{ k1 : o1, k2 : o2, k3 : o3 };

Page 43: Modern Objective-C

Pragma Night

static NSArray *thePragmers;

+ (void)initialize { if (self == [MyClass class]) { thePragmers = @[ @"Fra", @"Giu", @"Mat", @"Max", @"Ste" ]; }}

Container Literals Restriction

NSMutableArray *mutablePragmers = [@[ @"Fra", @"Giu", @"Mat", @"Max", @"Ste" ] mutableCopy];

All containers are immutable, mutable use: -mutableCopy

For constant containers, simply implement +initialize

Page 44: Modern Objective-C

Pragma Night

Object Subscripting

Page 45: Modern Objective-C

Pragma Night

Array Subscripting

New syntax to access object at index: nsarray[index]

@implementation SongList { NSMutableArray *_songs;}

- (Song *)replaceSong:(Song *)newSong atIndex:(NSUInteger)idx { Song *oldSong = [_songs objectAtIndex:idx]; [_songs replaceObjectAtIndex:idx withObject:newSong]; return oldSong;}@end

Page 46: Modern Objective-C

Pragma Night

Array Subscripting

New syntax to access object at index: nsarray[index]

@implementation SongList { NSMutableArray *_songs;}

- (Song *)replaceSong:(Song *)newSong atIndex:(NSUInteger)idx { Song *oldSong = _songs[idx]; _songs[idx] = newSong; return oldSong;}@end

Xcode 4.4+

Page 47: Modern Objective-C

Pragma Night

Dictionary Subscripting

New syntax to access object by key: nsdictionary[key]

@implementation Database{ NSMutableDictionary *_storage;}

- (id)replaceObject:(id)newObject forKey:(id <NSCopying>)key{ id oldObject = [_storage objectForKey:key]; [_storage setObject:newObject forKey:key]; return oldObject;}@end

Page 48: Modern Objective-C

Pragma Night

Dictionary Subscripting

New syntax to access object by key: nsdictionary[key]

@implementation Database{ NSMutableDictionary *_storage;}

- (id)replaceObject:(id)newObject forKey:(id <NSCopying>)key{ id oldObject = _storage[key]; _storage[key] = newObject; return oldObject;}@end

Xcode 4.4+

Page 49: Modern Objective-C

Pragma Night

- (elementType)objectForKeyedSubscript:(keyType)key;

- (void)setObject:(elementType)obj forKeyedSubscript:(keyType)key;

How Subscripting Works

- (elementType)objectAtIndexedSubscript:(indexType)idx

- (void)setObject:(elementType)obj atIndexedSubscript:(indexType)idx;

Array Style: Indexed subscripting methods

elementType must be an object pointer, indexType must be integral

elementType and keyType must be an object pointer

Dictionary Style: Keyed subscripting methods

iOS 6 OSX 10.8

iOS 6 OSX 10.8

Page 50: Modern Objective-C

Pragma Night

Indexed Subscripting

setObject:atIndexedSubscript:

@implementation SongList { NSMutableArray *_songs;}

- (Song *)replaceSong:(Song *)newSong atIndex:(NSUInteger)idx { Song *oldSong = _songs[idx]; _songs[idx] = newSong; return oldSong;}@end

Page 51: Modern Objective-C

Pragma Night

Indexed Subscripting

setObject:atIndexedSubscript:

@implementation SongList { NSMutableArray *_songs;}

- (Song *)replaceSong:(Song *)newSong atIndex:(NSUInteger)idx { Song *oldSong = _songs[idx]; [_songs setObject:newSong atIndexedSubscript:idx]; return oldSong;}@end

Page 52: Modern Objective-C

Pragma Night

Keyed Subscripting

setObject:atIndexedSubscript:

@implementation Database{ NSMutableDictionary *_storage;}

- (id)replaceObject:(id)newObject forKey:(id <NSCopying>)key{ id oldObject = _storage[key]; _storage[key] = newObject; return oldObject;}@end

Page 53: Modern Objective-C

Pragma Night

Keyed Subscripting

setObject:atIndexedSubscript:

@implementation Database{ NSMutableDictionary *_storage;}

- (id)replaceObject:(id)newObject forKey:(id <NSCopying>)key{ id oldObject = _storage[key]; [_storage setObject:newObject forKey:key]; return oldObject;}@end

Page 54: Modern Objective-C

Pragma Night

Backward Compatibility !?

#if __IPHONE_OS_VERSION_MAX_ALLOWED < 60000@interface NSDictionary(BCSubscripting)- (id)objectForKeyedSubscript:(id)key;@end

@interface NSMutableDictionary(BCSubscripting)- (void)setObject:(id)obj forKeyedSubscript:(id )key;@end

@interface NSArray(BCSubscripting)- (id)objectAtIndexedSubscript:(NSUInteger)idx;@end

@interface NSMutableArray(BCSubscripting)- (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx;@end#endif

To deploy back to iOS 5 and iOS 4 you need ARCLite: use ARC or set explicit linker flag: “-fobjc-arc”

To make compiler happy, you should add 4 categories:

Page 55: Modern Objective-C

Pragma Night

Your Classes Can Be Subscriptable

@interface SongList : NSObject- (Song *)objectAtIndexedSubscript:(NSUInteger)idx;- (void) setObject:(Song *)song atIndexedSubscript:(NSUInteger)idx;@end

@implementation SongList { NSMutableArray *_songs;}- (Song *)objectAtIndexedSubscript:(NSUInteger)idx { return (Song *)_songs[idx];}- (void) setObject:(Song *)song atIndexedSubscript:(NSUInteger)idx { _songs[idx] = song;}@end

Page 56: Modern Objective-C

Pragma Night

Summary

Page 57: Modern Objective-C

Pragma Night

AvailabilityFeature Xcode 4.4+ iOS 6 OSX 10.8

Unordered Method Declarations ✓Enum With Fixed Underlying Type ✓

@Synthesize by Default ✓NSNumbers Literals ✓

Boxed Expression Literals ✓Array Literals ✓

Dictionary Literals ✓Object Subscripting ✓ ✓

* Partially Required

*

Page 58: Modern Objective-C

Pragma Night

Migration

Apple provides a migration tool which is build into Xcode: Edit ⇒ Refactor ⇒ Convert to Modern ...

Page 59: Modern Objective-C

Pragma Night

Demo

Page 61: Modern Objective-C

Pragma Night

Modern Objective-C Books