Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Modern Objective-C @ Pragma Night

3,301 views

Published on

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

Published in: Technology

Modern Objective-C @ Pragma Night

  1. 1. Modern Objective-C Giuseppe Arici Pragma Night @ Talent Garden
  2. 2. It’s All About ...Syntactic Sugar Pragma Night
  3. 3. Unordered Method Declarations Pragma Night
  4. 4. 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 { /* ... */ } Warning: @end instance method -startAudio: not found (return type defaults to id) Pragma Night
  5. 5. Wrong WorkaroundIn the public interface @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 Pragma Night
  6. 6. Okay Workaround 1In a class extension @interface SongPlayer () - (void)startAudio:(NSError **)error; @end @implementation SongPlayer - (void)playSong:(Song *)song { NSError *error; [self startAudio:&error]; /* ... */ } - (void)startAudio:(NSError **)error { /* ... */ } @end Pragma Night
  7. 7. Okay Workaround 2Reorder methods @interface SongPlayer : NSObject - (void)playSong:(Song *)song; @end @implementation SongPlayer - (void)startAudio:(NSError **)error { /* ... */ } - (void)playSong:(Song *)song { NSError *error; [self startAudio:&error]; /* ... */ } @end Pragma Night
  8. 8. Best SolutionParse the @implementation declarations then bodies @interface SongPlayer : NSObject - (void)playSong:(Song *)song; @end @implementation SongPlayer - (void)playSong:(Song *)song { NSError *error; [self startAudio:&error]; Xcode 4.4+ /* ... */ } - (void)startAudio:(NSError **)error { /* ... */ } @end Pragma Night
  9. 9. Enum with FixedUnderlying Type Pragma Night
  10. 10. Enum with Indeterminate TypeBefore OS X v10.5 and iOS typedef enum { NSNumberFormatterNoStyle, NSNumberFormatterDecimalStyle, NSNumberFormatterCurrencyStyle, NSNumberFormatterPercentStyle, NSNumberFormatterScientificStyle, NSNumberFormatterSpellOutStyle } NSNumberFormatterStyle; //typedef int NSNumberFormatterStyle; Pragma Night
  11. 11. Enum with Explicit TypeAfter OS X v10.5 and iOS enum { NSNumberFormatterNoStyle, NSNumberFormatterDecimalStyle, NSNumberFormatterCurrencyStyle, NSNumberFormatterPercentStyle, NSNumberFormatterScientificStyle, NSNumberFormatterSpellOutStyle }; typedef NSUInteger NSNumberFormatterStyle; • Pro: 32-bit and 64-bit portability • Con: no formal relationship between type and enum constants Pragma Night
  12. 12. Enum with Fixed Underlying TypeLLVM 4.2+ Compiler typedef enum NSNumberFormatterStyle : NSUInteger { NSNumberFormatterNoStyle, NSNumberFormatterDecimalStyle, NSNumberFormatterCurrencyStyle, NSNumberFormatterPercentStyle, NSNumberFormatterScientificStyle, NSNumberFormatterSpellOutStyle } NSNumberFormatterStyle; Xcode 4.4+ • Stronger type checking • Better code completion Pragma Night
  13. 13. Enum with Fixed Underlying TypeNS_ENUM macro typedef NS_ENUM(NSUInteger, NSNumberFormatterStyle) { NSNumberFormatterNoStyle, NSNumberFormatterDecimalStyle, NSNumberFormatterCurrencyStyle, NSNumberFormatterPercentStyle, NSNumberFormatterScientificStyle, NSNumberFormatterSpellOutStyle }; Xcode 4.4+ • Foundation declares like this Pragma Night
  14. 14. Enum with Fixed Underlying TypeStronger type checking (-Wenum-conversion) NSNumberFormatterStyle style = NSNumberFormatterRoundUp; // 3warning:implicit conversion from enumeration type enumNSNumberFormatterRoundingMode to different enumeration typeNSNumberFormatterStyle (aka enum NSNumberFormatterStyle) Pragma Night
  15. 15. Enum with Fixed Underlying TypeHandling all enum values (-Wswitch) - (void) printStyle:(NSNumberFormatterStyle) style{ switch (style) { case NSNumberFormatterNoStyle: break; case NSNumberFormatterSpellOutStyle: break; } }warning:4 enumeration values not handled in switch:NSNumberFormatterDecimalStyle,NSNumberFormatterCurrencyStyle,NSNumberFormatterPercentStyle... Pragma Night
  16. 16. @Synthesize by Default Pragma Night
  17. 17. Properties Simplify Classes@interface instance variables @interface Person : NSObject { NSString *_name; } @property(strong) NSString *name; @end @implementation Person @synthesize name = _name; @end Pragma Night
  18. 18. Properties Simplify Classes@implementation instance variables @interface Person : NSObject @property(strong) NSString *name; @end @implementation Person { NSString *_name; } @synthesize name = _name; @end Pragma Night
  19. 19. Properties Simplify ClassesSynthesized instance variables @interface Person : NSObject @property(strong) NSString *name; @end @implementation Person @synthesize name = _name; @end Pragma Night
  20. 20. @Synthesize by DefaultLLVM 4.2+ Compiler @interface Person : NSObject @property(strong) NSString *name; @end @implementation Person Xcode 4.4+ @end Pragma Night
  21. 21. Instance Variable Name !?Instance variables now prefixed with “_” @interface Person : NSObject @property(strong) NSString *name; @end @implementation Person - (NSString *)description { return _name; Xcode 4.4+ } /* as if youd written: @synthesize name = _name; */ @end Pragma Night
  22. 22. Backward Compatibility !?Be careful, when in doubt be fully explicit @interface Person : NSObject @property(strong) NSString *name; @end @implementation Person @synthesize name; /* as if youd written: @synthesize name = name; */ @end Pragma Night
  23. 23. 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 ) Pragma Night
  24. 24. Core Data NSManagedObjectOpts out of synthesize by default /* NSManagedObject.h */ NS_REQUIRES_PROPERTY_DEFINITIONS @interface NSManagedObject : NSObject { • NSManagedObject synthesizes properties • Continue to use @property to declare typed accessors • Continue to use @dynamic to inhibit warnings Pragma Night
  25. 25. NSNumbers Literals Pragma Night
  26. 26. NSNumber CreationNSNumber *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]; Pragma Night
  27. 27. NSNumber CreationNSNumber *value;value = @X;value = @42;value = @42ul;value = @42ll;value = @0.42f; Xcode 4.4+value = @0.42;value = @YES; Pragma Night
  28. 28. Backward Compatibility !?#define YES (BOOL)1 // Before iOS 6, OSX 10.8#define YES ((BOOL)1) // After iOS 6, OSX 10.8Workarounds@(YES) // Use parentheses around BOOL Macros#if __IPHONE_OS_VERSION_MAX_ALLOWED < 60000#if __has_feature(objc_bool)#undef YES#undef NO // Redefine BOOL Macros#define YES __objc_yes#define NO __objc_no#endif#endif Pragma Night
  29. 29. Boxed Expression Literals Pragma Night
  30. 30. Boxed Expression LiteralsNSNumber *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]]; Pragma Night
  31. 31. Boxed Expression LiteralsNSNumber *orientation = @( UIDeviceOrientationPortrait );NSNumber *piOverSixteen = @( M_PI / 16 );NSNumber *parityDigit = @( "OE"[i % 2] );NSString *path = @( getenv("PATH") ); Xcode 4.4+NSNumber *usesCompass = @( [CLLocationManager headingAvailable] ); Pragma Night
  32. 32. Array Literals Pragma Night
  33. 33. Array CreationMore 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]; Pragma Night
  34. 34. Nil TerminationInconsistent behavior // if you write: id a = nil, b = @"hello", c = @42; NSArray *array = [NSArray arrayWithObjects:a, b, c, nil];Array will be empty // if you write: id objects[] = { nil, @"hello", @42 }; NSUInteger count = sizeof(objects)/ sizeof(id); NSArray *array = [NSArray arrayWithObjects:objects count:count];Exception: attempt to insert nil object from objects[0] Pragma Night
  35. 35. Array CreationNSArray *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]; Pragma Night
  36. 36. Array CreationNSArray *array;array = @[];array = @[ a ];array = @[ a, b, c ]; Xcode 4.4+array = @[ a, b, c ]; Pragma Night
  37. 37. How Array Literals Work// when you write this:NSArray *array = @[ a, b, c ];// compiler generates:id objects[] = { a, b, c };NSUInteger count = sizeof(objects)/ sizeof(id);NSArray *array = [NSArray arrayWithObjects:objects count:count]; Pragma Night
  38. 38. Dictionary Literals Pragma Night
  39. 39. Dictionary CreationMore choices, and more chances for errors 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]; Pragma Night
  40. 40. Dictionary CreationNSDictionary *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]; Pragma Night
  41. 41. Dictionary CreationNSDictionary *dict;dict = @{};dict = @{ k1 : o1 }; // key before objectdict = @{ k1 : o1, k2 : o2, k3 : o3 }; Xcode 4.4+dict = @{ k1 : o1, k2 : o2, k3 : o3 }; Pragma Night
  42. 42. How Dictionary Literals Work// when you write this:NSDictionary *dict = @{ k1 : o1, k2 : o2, k3 : o3 };// 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]; Pragma Night
  43. 43. Container Literals RestrictionAll containers are immutable, mutable use: -mutableCopy NSMutableArray *mutablePragmers = [@[ @"Fra", @"Giu", @"Mat", @"Max", @"Ste" ] mutableCopy];For constant containers, simply implement +initialize static NSArray *thePragmers; + (void)initialize { if (self == [MyClass class]) { thePragmers = @[ @"Fra", @"Giu", @"Mat", @"Max", @"Ste" ]; } } Pragma Night
  44. 44. Object Subscripting Pragma Night
  45. 45. Array SubscriptingNew 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 Pragma Night
  46. 46. Array SubscriptingNew syntax to access object at index: nsarray[index] @implementation SongList { NSMutableArray *_songs; } - (Song *)replaceSong:(Song *)newSong atIndex:(NSUInteger)idx { Xcode 4.4+ Song *oldSong = _songs[idx]; _songs[idx] = newSong; return oldSong; } @end Pragma Night
  47. 47. Dictionary SubscriptingNew 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 Pragma Night
  48. 48. Dictionary SubscriptingNew syntax to access object by key: nsdictionary[key] @implementation Database { NSMutableDictionary *_storage; } - (id)replaceObject:(id)newObject forKey:(id <NSCopying>)key { Xcode 4.4+ id oldObject = _storage[key]; _storage[key] = newObject; return oldObject; } @end Pragma Night
  49. 49. How Subscripting Works iOS 6Array Style: Indexed subscripting methods OSX 10.8 - (elementType)objectAtIndexedSubscript:(indexType)idx - (void)setObject:(elementType)obj atIndexedSubscript:(indexType)idx;elementType must be an object pointer, indexType must be integral iOS 6Dictionary Style: Keyed subscripting methods OSX 10.8 - (elementType)objectForKeyedSubscript:(keyType)key; - (void)setObject:(elementType)obj forKeyedSubscript:(keyType)key;elementType and keyType must be an object pointer Pragma Night
  50. 50. Indexed SubscriptingsetObject:atIndexedSubscript: @implementation SongList { NSMutableArray *_songs; } - (Song *)replaceSong:(Song *)newSong atIndex:(NSUInteger)idx { Song *oldSong = _songs[idx]; _songs[idx] = newSong; return oldSong; } @end Pragma Night
  51. 51. Indexed SubscriptingsetObject:atIndexedSubscript: @implementation SongList { NSMutableArray *_songs; } - (Song *)replaceSong:(Song *)newSong atIndex:(NSUInteger)idx { Song *oldSong = _songs[idx]; [_songs setObject:newSong atIndexedSubscript:idx]; return oldSong; } @end Pragma Night
  52. 52. Keyed SubscriptingsetObject:atIndexedSubscript: @implementation Database { NSMutableDictionary *_storage; } - (id)replaceObject:(id)newObject forKey:(id <NSCopying>)key { id oldObject = _storage[key]; _storage[key] = newObject; return oldObject; } @end Pragma Night
  53. 53. Keyed SubscriptingsetObject: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 Pragma Night
  54. 54. Backward Compatibility !?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: #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 Pragma Night
  55. 55. 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 Pragma Night
  56. 56. Summary Pragma Night
  57. 57. Availability Feature 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 Pragma Night
  58. 58. MigrationApple provides a migration tool which is build intoXcode: Edit Refactor Convert to Modern ... Pragma Night
  59. 59. Demo Pragma Night
  60. 60. Modern Objective-C References• Clang: Objective-C Literals• Apple: Programming with Objective-C• WWDC 2012 – Session 405 – Modern Objective-C• Mike Ash: Friday Q&A 2012-06-22: Objective-C Literals Pragma Night
  61. 61. Modern Objective-C Books Pragma Night
  62. 62. NSLog(@”Thank you!”); giuseppe.arici@pragmamark.org Pragma Night

×