Successfully reported this slideshow.

Modern Objective-C

832 views

Published on

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

Published in: Technology
  • Be the first to comment

  • Be the first to like this

Modern Objective-C

  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

×