What I Learned From AFNetworking's GitHub Issues

What I Learned From AFNetworking's GitHub Issues

(Presented at NYC iOS Developer Meetup & CocoaConf Columbus 2012)

It can be said that GitHub Issues are the hacker's equivalent of the classical Greek forum. Like the ancient philosophers before us, here the leading minds in open source gather to discuss the programming topics of our day. In this talk, we'll dig through AFNetworking's backlog to discover and dissect the epic debates, lofty ideas, and occasionally-fierce rhetorical exchanges contained within those hallowed threads.

D29bb4d2d2f2ba2c2fb5a329e1e4651f?s=128

Mattt Thompson

August 11, 2012
Tweet

Transcript

  1. What I Learned From AFNetworking's GitHub Issues Mattt Thompson Mobile

    Lead, Heroku
  2. None
  3. None
  4. None
  5. Lessons Learned

  6. Lesson 1: Designing Great Software Means Saying No... A Lot

  7. Every Line of Code Needs to Justify its Own Existence

  8. Every Feature Adds Complexity

  9. • Ordered Query String Parameters • Customizable Query String Format

    • Property for DELETE Parameters to be in either Query String or Message Body • Retry Parameter for Operations • Option to Parse Top-Level JSON Fragments
  10. ARC w/Macros

  11. None
  12. Lesson 2: If You Can’t Give Them What They Want,

    Give Them Something Better
  13. None
  14. Feature Requests are Data Points to Understand What Should Be

    Improved
  15. Custom Mime Types

  16. None
  17. • application/json • application/javascript

  18. • application/json • application/javascript • text/javascript

  19. • application/json • application/javascript • text/javascript • text/x-javascript • text/x-json

    • application/x-javascript
  20. None
  21. application/vnd.github+json

  22. AFHTTPRequestOperation +addAcceptableContentTypes:

  23. JSON Libraries

  24. • JSONKit • yajl_json • SBJSON • TouchJSON • NextiveJSON

  25. None
  26. AFJSONUtilities.h AFJSONEncode() / AFJSONDecode()

  27. NSData * AFJSONEncode(id object, NSError **error) { NSData *data =

    nil; SEL _JSONKitSelector = NSSelectorFromString(@"JSONDataWithOptions:error:"); SEL _YAJLSelector = NSSelectorFromString(@"yajl_JSONString"); id _SBJsonWriterClass = NSClassFromString(@"SBJsonWriter"); SEL _SBJsonWriterSelector = NSSelectorFromString(@"dataWithObject:"); id _NXJsonSerializerClass = NSClassFromString(@"NXJsonSerializer"); SEL _NXJsonSerializerSelector = NSSelectorFromString(@"serialize:"); id _NSJSONSerializationClass = NSClassFromString(@"NSJSONSerialization"); SEL _NSJSONSerializationSelector = NSSelectorFromString(@"dataWithJSONObject:options:error:"); #ifdef _AFNETWORKING_PREFER_NSJSONSERIALIZATION_ if (_NSJSONSerializationClass && [_NSJSONSerializationClass respondsToSelector:_NSJSONSerializationSelector]) { goto _af_nsjson_encode; } #endif if (_JSONKitSelector && [object respondsToSelector:_JSONKitSelector]) { NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[object methodSignatureForSelector:_JSONKitSelector]]; invocation.target = object; invocation.selector = _JSONKitSelector; NSUInteger serializeOptionFlags = 0; [invocation setArgument:&serializeOptionFlags atIndex:2]; // arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation if (error != NULL) { [invocation setArgument:error atIndex:3]; } [invocation invoke]; [invocation getReturnValue:&data]; } else if (_SBJsonWriterClass && [_SBJsonWriterClass instancesRespondToSelector:_SBJsonWriterSelector]) { id writer = [[_SBJsonWriterClass alloc] init]; NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[writer methodSignatureForSelector:_SBJsonWriterSelector]]; invocation.target = writer; invocation.selector = _SBJsonWriterSelector; [invocation setArgument:&object atIndex:2]; // arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation [invocation invoke]; [invocation getReturnValue:&data]; [writer release];
  28. NSJSONSerialization

  29. ASINetworkQueue

  30. ASIHTTPRequest

  31. ASINetworkQueue

  32. AFHTTPClient -enqueueBatchOfHTTPRequestOperations: progressBlock: completionBlock:

  33. Lesson 3: Never Merge In Code That You Don’t Understand

  34. Lesson 3: Never Merge In Code That You Don’t Understand

  35. dispatch_group

  36. AFHTTPClient -enqueueBatchOfHTTPRequestOperations: progressBlock: completionBlock:

  37. 1 2 3 4 5 Batch

  38. 1 2 3 4 5 Batch

  39. 1 2 3 4 5 Batch 1 2 3 4

    5 1 2 3 4 5
  40. Thread Safety

  41. None
  42. None
  43. Lesson 4: Don’t Settle For Not Understanding Something

  44. Thread Safety

  45. MVC Networking

  46. None
  47. None
  48. None
  49. None
  50. None
  51. • dispatch_async pattern • Dedicated Network Thread • Custom Dispatch

    Queues for Background Processing
  52. “The Deallocation Problem”

  53. None
  54. When you start a secondary thread, it's common for that

    thread to retain the target object. If you don’t ensure that the thread releases that reference before the main thread releases its last reference to the object, bad things happen.
  55. - (void)setCompletionBlock:(void (^)(void))block { if (!block) { [super setCompletionBlock:nil]; }

    __block id _blockSelf = self; [super setCompletionBlock:^ { block(); [_blockSelf setCompletionBlock:nil]; }]; }
  56. API Consistency

  57. None
  58. AFHTTPClient -HTTPRequestOperationWithRequest: success: failure: AFHTTPRequestOperation -setCompletionBlockWithSuccess: failure:

  59. Lesson 5: The More You Put In, The More You

    Get Out
  60. •Be Present •Be Nice •Be Socratic 3 Rules for Project

    Ownership
  61. None
  62. Thanks!