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. Objective-C techniques for • Less bugs • Faster development •

    Higher quality of code • More flexibility
  2. 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
  3. 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]; }
  4. 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"]; }
  5. 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.
  6. 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];
  7. 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
  8. 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]]); ... }
  9. 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), }, }];
  10. 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; })
  11. 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.
  12. 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, ...);
  13. 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