Objective-C++: What could possibly go wrong?

Objective-C++: What could possibly go wrong?

Talk for AltConf 2015 in San Francisco

We're digging into the beautiful madness called Objective-C++ and look at use cases where it's great, where it's terrible and how to not shoot yourself in the foot. Did you know that modern C++ has it's own version of ARC, weak and blocks? You'll learn to identify common performance bottlenecks and a small subset of C++ that will be a useful addition to your toolbox. This is based on a large codebase that shares a common core over iOS, Android and even runs on the Mac.

832ece085bfe2c7c5b0ed6be62d7e675?s=128

Peter Steinberger

June 09, 2015
Tweet

Transcript

  1. [Objective] C++ Peter Steinberger, @steipete AltConference, San Francisco, June 2015

  2. Audience — You've seen C++ before. — You care about

    elegant, performant code. — The world doesn't end with iOS. — You wanna come to the dark side.
  3. $ whoami @steipete

  4. $ whoami

  5. Every malloc is a mistake.

  6. What about Swift?

  7. C++ — Actively improved (C++11, C++14, C++17) — Great tooling,

    great compiler, great ecosystem — Cross-Platform — Really fast — Powerful standard library (STL) — Many 3rd-party libraries available0 0 https://github.com/fffaraz/awesome-cpp
  8. Cocoapods won't like you

  9. This is not your grandmother's C++! — auto — shared_ptr

    — weak — lambdas — move semantics
  10. auto & range-based for loops // C++98 for (vector<CGPoint>::iterator i

    = v.begin(), e = v.end(); i != e; ++i) { reticulateSpline(*i); } // C++11 for (CGPoint& point : v) { reticulateSpline(point); }
  11. auto & range-based for loops // C++98 for (vector<CGPoint>::iterator i

    = v.begin(), e = v.end(); i != e; ++i) { reticulateSpline(*i); } // C++11 for (auto& point : v) { reticulateSpline(point); }
  12. auto & range-based for loops // C++98 for (vector<CGPoint>::iterator i

    = v.begin(), e = v.end(); i != e; ++i) { reticulateSpline(*i); } // C++17 for (point : v) { reticulateSpline(point); }
  13. std::vector<CGPoint> — Continuous block of memory — Stack or Heap

    — Throws exceptions on access out of bounds — powerful mutators like rotate2 2 http://channel9.msdn.com/Events/GoingNative/2013/Cpp-Seasoning
  14. Initializer Lists // C++98 std::vector<int> v; v.push_back(1); // ... v.push_back(5);

    // C++11 std::vector<int> v = {1, 2, 3, 4, 5};
  15. Smart Pointers // Returns all developers. Delete when done. vector<Developer*>

    get_developers();
  16. Smart Pointers // Returns all developers. Delete when done. vector<Developer*>

    get_developers(); // cleanup for (vector<Developer*>::iterator i = v.begin(); i != v.end(); ++i) { delete *i; }
  17. Smart Pointers // Returns all developers (C++11) vector<unique_ptr<Developer>> get_developers();

  18. Smart Pointers // Returns all developers (C++11) vector<unique_ptr<Developer>> get_developers(); //

    adding a new element (C++11) devs.push_back(unique_ptr<Developer>(new Developer("steipete")));
  19. Smart Pointers // Returns all developers (C++11) vector<unique_ptr<Developer>> get_developers(); //

    adding a new element (C++11, more efficient) devs.emplace_back(unique_ptr<Developer>(new Developer("steipete")));
  20. Smart Pointers // Returns all developers (C++11) vector<unique_ptr<Developer>> get_developers(); //

    adding a new element (C++14) devs.emplace_back(make_unique<Developer>("steipete"));
  21. Smart Pointers — auto_ptr — unique_ptr — shared_ptr — weak_ptr

  22. Smart Pointers // Returns all developers. vector<unique_ptr<Developer>> get_developers(); // later

    on auto developers = get_developers(); shared_ptr<Developer> developer = developers[0];
  23. Move semantics // get all the points vector<CGPoint> points =

    get_points();
  24. Move semantics // get all the points vector<CGPoint> points =

    get_points(); vector(const vector& that) { size_t size = strlen(that.data) + 1; data = new char[size]; memcpy(data, that.data, size); }
  25. Move semantics // get all the points vector<CGPoint> points =

    get_points(); vector(vector&& that) { data = that.data; that.data = nullptr; }
  26. Move semantics auto a = b; // copy auto a

    = x + y; // move
  27. Lambdas std::sort(people.begin(), people.end(), [](const Person& p1, const Person& p2) {

    return p1.getId() < p2.getId(); } );
  28. Lambdas [] Capture nothing [&] Capture by reference [=] Capture

    by making a copy [this] Capture enclosing class [=, &foo] [bar]
  29. Lambdas void PSPDFParseFont(const char *key, CGPDFObjectRef value, void *info) {

    NSLog(@"key: %s", key); }; // later, in another function CGPDFDictionaryApplyFunction(fontDict, dictIterator, (__bridge void *)self);
  30. Lambdas auto parseFont = [] (const char *key, CGPDFObjectRef value,

    void *info) { NSLog(@"key: %s", key); }; CGPDFDictionaryApplyFunction(fontDict, parseFont, (__bridge void *)self);
  31. How do I start?

  32. Objective-C++ — Freely mix C++ and Objective-C3 — Enable by

    renaming files to .hpp and .mm 3 http://web.archive.org/web/20101203170217/http://developer.apple.com/library/mac/#/ web/20101204020949/http://developer.apple.com/library/mac/documentation/Cocoa/ Conceptual/ObjectiveC/Articles/ocCPlusPlus.html
  33. Objective-C++ Gotchas — Compile time — Properties — "Stricter" compiler

  34. Popular Projects using Objective-C++ — The Objective-C Runtime — WebKit

    — Realm — pop — ComponentKit — djinni
  35. Why Objective-C++4 [CKStackLayoutComponent newWithStyle:{ .direction = CKStackLayoutComponentDirectionVertical, } children:{ {[HeaderComponent

    newWithArticle:article]}, {[MessageComponent newWithArticle:article]}, {[FooterComponent newWithArticle:article]}, }]; 4 http://componentkit.org/docs/why-cpp.html
  36. Why Objective-C++ [CKStackLayoutComponent newWithStyle:[[CKStackLayoutComponentStyle alloc] initWithDirection:CKStackLayoutComponentDirectionVertical justifyContent:CKStackLayoutComponentJustifyContentStart alignItems:CKStackLayoutComponentAlignItemsStart spacing:0] children:@[

    [CKStackLayoutComponentChild childWithComponent:[HeaderComponent newWithArticle:article] topPadding:0 leftPadding:0 bottomPadding:0], [CKStackLayoutComponentChild childWithComponent:[MessageComponent newWithArticle:article] topPadding:0 leftPadding:0 bottomPadding:0], [CKStackLayoutComponentChild childWithComponent:[FooterComponent newWithArticle:article] topPadding:0 leftPadding:0 bottomPadding:0] ]];
  37. Aggregate Initialization CGPoint p1 = (CGPoint){ .x = 3 };

    CGPoint p2 = (CGPoint){3, 0};
  38. Type Safety — "Objective-C generics"

  39. Efficiency

  40. Nil Safety NSArray *array = @[@"a", @"b", (NSString *)nil, @"d"];

    auto vector = vector<NSString*>{@"a", @"b", nullptr, @"d"};
  41. Nil Safety auto vector = vector<NSString*>{@"a", @"b", nullptr, @"d"}; vector.erase(remove_if(begin(vector),

    end(vector), [](NSString *string) { return string == nullptr; }), end(vector));
  42. Nil Safety auto vector = vector<NSString*>{@"a", @"b", nullptr, @"d"}; vector.erase(remove(begin(vector),

    end(vector), nullptr), end(vector));
  43. Nil Safety children:{ headerComponent, messageComponent, attachmentComponent, footerComponent }

  44. Nil Safety NSMutableArray *children = [NSMutableArray array]; if (headerComponent) {

    [children addObject:headerComponent]; } if (messageComponent) { [children addObject:messageComponent]; } if (attachmentComponent) { [children addObject:attachmentComponent]; } if (footerComponent) { [children addObject:footerComponent]; }
  45. Inline blocks void (^handler)(NSData *data, NSURLResponse *response, NSError *error) =

    ^(NSData *data, NSURLResponse *response, NSError *error) { // parse data }; [NSURLSession sharedSession] dataTaskWithURL:URL completionHandler:handler];
  46. Inline blocks auto handler = ^(NSData *data, NSURLResponse *response, NSError

    *error) { // parse data }; [NSURLSession sharedSession] dataTaskWithURL:URL completionHandler:handler];
  47. Universal comparison function for value types template <typename T> inline

    NSComparisonResult PSPDFCompare(const T value1, const T value2) { if (value1 < value2) return (NSComparisonResult)NSOrderedAscending; else if (value1 > value2) return (NSComparisonResult)NSOrderedDescending; else return (NSComparisonResult)NSOrderedSame; }
  48. Operator overloading for CGPoint inline CGPoint operator+(const CGPoint &p1, const

    CGPoint &p2) { return { p1.x + p2.x, p1.y + p2.y }; } inline CGPoint operator-(const CGPoint &p1, const CGPoint &p2) { return { p1.x - p2.x, p1.y - p2.y }; }
  49. Practical Example void CreatePathsForLineEndType(PSPDFLineEndType const endType, CGPoint const* points, NSUInteger

    const pointsCount, CGFloat const lineWidth, CGPathRef *storedFillPath, CGPathRef *storedStrokePath);
  50. Convert raw pointer to a vector reference void CreatePathsForLineEndType(PSPDFLineEndType const

    endType, std::vector<CGPoint> const& points, CGFloat const lineWidth, CGPathRef *storedFillPath, CGPathRef *storedStrokePath); // copy points into a vector auto vector = std::vector<CGPoint>(points, points+pointsCount); auto vector = std::vector<CGPoint>{point1, point2, point3};
  51. Improve the output tuple<CGPathRef, CGPathRef> FillAndStrokePathForLineEndType(PSPDFLineEndType endType, std::vector<CGPoint> const& points,

    CGFloat lineWidth);
  52. With custom auto pointers5 tuple<CFPointer<CGPathRef>, CFPointer<CGPathRef>> FillAndStrokePathForLineEndType(PSPDFLineEndType endType, std::vector<CGPoint> const&

    points, CGFloat lineWidth); 5 https://gist.github.com/steipete/0f65c234ee843ed514ff
  53. // old void CreatePathsForLineEndType(PSPDFLineEndType endType, CGPoint const* points, NSUInteger pointsCount,

    CGFloat lineWidth, CGPathRef *storedFillPath, CGPathRef *storedStrokePath); // new tuple<CFPointer<CGPathRef>, CFPointer<CGPathRef>> FillAndStrokePathForLineEndType(PSPDFLineEndType endType, std::vector<CGPoint> const& points, CGFloat lineWidth);
  54. Debugging works great

  55. Thanks! Peter Steinberger, @steipete References - http://blog.petrzemek.net/2014/12/07/improving-cpp98-code-with-cpp11 - http://componentkit.org/docs/why-cpp.html -

    http://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom - http://en.cppreference.com/w/cpp/language/aggregate_initialization - http://stackoverflow.com/questions/3106110/what-are-move-semantics - http://web.archive.org/web/20101203170217/http://developer.apple.com/library/ mac/#/web/20101204020949/http://developer.apple.com/library/mac/documentation/Cocoa/ Conceptual/ObjectiveC/Articles/ocCPlusPlus.html - http://channel9.msdn.com/Events/GoingNative/2013/Cpp-Seasoning - https://developer.apple.com/library/ios/documentation/DeveloperTools/ Conceptual/WhatsNewXcode/Articles/xcode_5_0.html - https://gist.github.com/steipete/0f65c234ee843ed514ff