Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Empower your Objective-C

Empower your Objective-C

Krzysztof Zabłocki

October 23, 2014
Tweet

More Decks by Krzysztof Zabłocki

Other Decks in Programming

Transcript

  1. Empower your Objective C Krzysztof Zabłocki @merowing_

  2. Swift?

  3. Objective-C techniques for • Less bugs • Faster development •

    Higher quality of code • More flexibility
  4. Technical Bits • Key Value Coding • Runtime • DSL

    • Macros • LLVM Attributes
  5. Key Value Coding • KVC gives us: • automatic boxing

    / unboxing of primitive types • collection operators like sum/avg/max, removing need to write them • more complex operators like unionOfObjects • can be applied to sub-objects eg. @sum.price • extracting only interesting attributes
  6. Key Value Coding - (CGFloat)before:(NSArray *)charts { CGFloat maxValue =

    CGFLOAT_MIN; for(HRBBarGraphChartDescriptor *chart in charts) { maxValue = fmaxf(chart.value.floatValue, maxValue); } return maxValue; } Turns into: - (CGFloat)after:(NSArray *)charts { return [[charts valueForKeyPath:@"@max.value"] floatValue]; }
  7. Key Value Coding - (id <NSFastEnumeration>)uniqueElementsBefore { NSMutableArray *allElements =

    [NSMutableArray new]; for (ShapeGroup *group in _shapeGroups) { for(CCSprite *element in group.elements) { if(![allElements containsObject: element]) { [allElements addObject:element]; } } } return [allElements copy]; } Turns into: - (id <NSFastEnumeration>)uniqueElementsAfter { return [_shapeGroups valueForKeyPath:@"@distinctUnionOfArrays.elements"]; }
  8. Runtime • Dynamically create / override functions and classes: •

    Automatically pick up classes implementing specific protocol. • Intercept methods to log or modify behavior eg. Aspects. • Implement similar functions without repetition: • eg. findBy{Field} • Store context data per instance.
  9. Runtime - examples • Adding guards around Apple API's misuses:

    • accessing UIKit methods from background threads • accessing CoreData context from wrong thread • Adding UIGestureRecognizer support to Cocos2D • Higher order messaging: [[windowsArray do] setHidesOnDeactivate:YES];
  10. DSL - Domain Specific Language • Simplify code by making

    it more readable or avoiding clutter, eg. • KZAsserts automatic NSError generation, assertions and graceful error handling with same line of code. • KZPropertyMapper implements compile time error checking, generates custom bindings, removing need for breakable code. • Testing/Mocking frameworks
  11. DSL - Domain Specific Language - (NSError*)method { NSParameterAssert([dataFromServer isKindOfClass:[NSDictionary

    class]]); if ([dataFromServer isKindOfClass:[NSDictionary class]]) { NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: @"Unable to satisfy condition [dataFromServer isKindOfClass:[NSDictionary class]]"}; return [NSError errorWithDomain:ErrorDomain code:InternalErrorCode userInfo:userInfo]; } NSParameterAssert([something isKindOfClass:[NSString class]]); if ([something isKindOfClass:[NSString class]]) { NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: @"Unable to satisfy condition [something isKindOfClass:[NSString class]]"}; return [NSError errorWithDomain:ErrorDomain code:InternalErrorCode userInfo:userInfo]; } ... } Into this: - (NSError*)method { AssertTrueOrReturnError([dataFromServer isKindOfClass:[NSDictionary class]]); AssertTrueOrReturnError([something isKindOfClass:[NSString class]]); ... }
  12. DSL - Domain Specific Language This is all it takes

    to map values with type conversion and validation: [KZPropertyMapper mapValuesFrom:dictionary toInstance:self usingMapping:@{ @"content_url" : KZBox(URL, contentURL).isRequired(), @"full_name" : KZProperty(fullName).lengthRange(5, 12), @"videoType" : KZProperty(type), @"sub_object" : @{ @"title" : KZProperty(uniqueID), }, }];
  13. DSL - Macros #define Macro(param) • Generate NSString - @#param

    turns into @"name" • Generate unique symbols by joining: NSString *local_##param = #@param; turns into NSString *local_name = @"name"; • Use gcc expression extension to execute few statements: ({ result = doSomething(param); result; })
  14. DSL - Macros #define Macro(param) • Generate compilation errors on

    misspelling of keyPaths/ properties: ({if(NO){ [self param]; }; #@param;}) np. Macro(name) will return NSString* for a keyPath but only if it exists, compile error otherwise.
  15. LLVM Attributes - Top 4 • constructor - similar to

    +load. • NS_REQUIRE_SUPER • nonnull - compiler error when trying to explicitly pass null • overloadable - multiple functions with same API prototype. void __attribute__((overloadable)) KZPShow(CGImageRef image); void __attribute__((overloadable)) KZPShow(UIImage *image); void __attribute__((overloadable)) KZPShow(NSString *format, ...);
  16. Playgrounds?

  17. None
  18. Summary • Advanced techniques can save you hours of work

    • Cleaner and more robust code • Easier to evolve • Fun! • With great power comes great responsibility: • Design with care • Any programming technique can be misused
  19. Questions?

  20. Thank you! Krzysztof Zabłocki Follow @merowing_