70
Objective-C++ Vlad Mihaylenko. AvitoTech. Moscow. March 2016

"О некоторых особенностях Objective-C++" Влад Михайленко (Maps.Me)

Embed Size (px)

Citation preview

Objective-C++Vlad Mihaylenko. AvitoTech. Moscow. March 2016

Why Objective-C++1.Compile time 2.Efficiency 3.Aggregate initialization 4.Type safety 5.Powerful standard library 6.A lot of 3rdparty libraries1

1. https://github.com/fffaraz/awesome-cpp

Swift

Swift

:(

std::vector<T>• Continuos block in memory • Strong typing • nullptr safety • Stack or heap

std::vector<T>std::vector<CGPoint> v = …;

// C++98 for (std::vector<CGPoint>::const_iterator i = v.begin(); i != v.end(); ++i) { // do something with p }

// C++11 for (auto const & p : v) { // do something with p }

std::vector<T>// Warning: Incompatible pointer types sending 'NSNumber *' to parameter of type 'NSString * _Nonnull' NSMutableArray<NSString *> * a = [@[@""] mutableCopy]; [a addObject:@0];

std::vector<T>// Warning: Incompatible pointer types sending 'NSNumber *' to parameter of type 'NSString * _Nonnull' NSMutableArray<NSString *> * a = [@[@""] mutableCopy]; [a addObject:@0];

// Compile time error std::vector<NSString *> v = {@""}; v.push_back(@0);

std::vector<T>// Warning: Incompatible pointer types sending 'NSNumber *' to parameter of type 'NSString * _Nonnull' NSMutableArray<NSString *> * a = [@[@""] mutableCopy]; [a addObject:@0];

// Compile time error std::vector<NSString *> v = {@""}; v.push_back(@0);

// In .mm file: compile time error! // Cannot initialize a parameter of type 'NSString * _Nonnull' with an rvalue of type 'NSNumber *' NSMutableArray<NSString *> * a = [@[@""] mutableCopy]; [a addObject:@0];

std::array<T, size_t>• Fixed size • Strong typing • Compile time

std::array<T, size_t>static const NSArray<NSString *> * const kTypes = @[@"Fast Food", @"Pizza", @"Italian", @"Beer", @"Sushi"];

std::array<T, size_t>static const NSArray<NSString *> * const kTypes = @[@"Fast Food", @"Pizza", @"Italian", @"Beer", @«Sushi"];

static const std::array<NSString *, 5> kTypes = {{@«Fast Food", @"Pizza", @"Italian", @"Beer", @«Sushi"}};

Dictionary-like• std::map<Key, Value> // RB-Tree • std::unordered_map<Key, Value> // Hash Table (like NSDictionary) • std::multimap<Key, Value> • std::unordered_multimap<Key, Value> • boost::container::flat_map<Key, Value>2

2. http://scottmeyers.blogspot.com.by/2015/09/should-you-be-using-something-instead.html

std::pair<T, T> & std::tuple<T>- (void)getLat:(double &)lat lon:(double &)lon;

double lat, lon = 0; [self getLat:lat lon:lon];

std::pair<T, T> & std::tuple<T>- (void)getLat:(double &)lat lon:(double &)lon azimut:(double &)azimut;

double lat, lon, azimut = 0; [self getLat:lat lon:lon azimut:azimut];

std::pair<T, T> & std::tuple<T>- (void)getLat:(double &)lat lon:(double &)lon azimut:(double &)azimut;

double lat, lon, azimut = 0; [self getLat:lat lon:lon azimut:azimut];

std::pair<T, T> & std::tuple<T>- (void)getLat:(double &)lat lon:(double &)lon;

double lat, lon = 0; [self getLat:lat lon:lon];

- (std::pair<double, double>)getLatLon { return std::make_pair(lat, lon); }

const auto latLon = [self getLatLon]; const auto lat = latLon.first; const auto lon = latLon.second;

std::pair<T, T> & std::tuple<T>- (void)getLat:(double &)lat lon:(double &)lon azimut:(double &)azimut;

double lat, lon, azimut = 0; [self getLat:lat lon:lon azimut:azimut];

- (std::tuple<double, double, double>)getCoordinateAndAzimut { return std::make_tuple(lat, lon, azimut); }

const auto locationInfo = [self getCoordinateAndAzimut]; const auto lat = std::get<0>(locationInfo); const auto lon = std::get<1>(locationInfo); const auto azimut = std::get<2>(locationInfo);

smart pointersvector<Dog *> v {droopy, goofy, pluto};

for (const auto & d : v) { d->bark(); delete d; }

smart pointersvector<shared_ptr<Dog>> v {make_shared<Dog>(droopy), make_shared<Dog>(goofy), make_shared<Dog>(pluto)};

for (const auto & d : v) { d->bark(); }

smart pointersvector<shared_ptr<Dog>> v {make_shared<Dog>(droopy), make_shared<Dog>(goofy), make_shared<Dog>(pluto)};

for (const auto & d : v) { d->bark(); }

auto p1 = make_shared<Dog>(droopy); auto p2 = p1;

smart pointersvector<unique_ptr<Dog>> v {make_unique<Dog>(droopy), make_unique<Dog>(goofy), make_unique<Dog>(pluto)};

for (const auto & d : v) { d->bark(); }

smart pointersvector<unique_ptr<Dog>> v {make_unique<Dog>(droopy), make_unique<Dog>(goofy), make_unique<Dog>(pluto)};

for (const auto & d : v) { d->bark(); }

auto p1 = make_unique<Dog>(droopy); auto p2 = p1; // Compile time error!

smart pointersvector<unique_ptr<Dog>> v {make_unique<Dog>(droopy), make_unique<Dog>(goofy), make_unique<Dog>(pluto)};

for (const auto & d : v) { d->bark(); }

auto p1 = make_unique<Dog>(droopy); auto p2 = move(p1); // Ok

moveclass Pasteboard { public: Pasteboard() = default; Pasteboard(const string t) : text(t) {} private: string text; };

moveclass Pasteboard { public: Pasteboard() = default; Pasteboard(const string t) : text(t) {} Pasteboard(string && t) : text(move(t)) {} private: string text; };

movevector<unique_ptr<Dog>> getDogs() { // Create and return vector return v; }

auto v = getDogs();

autoint x;

autoint x;

- (CGFloat)getY { // determine y return y; }

float y = self.getY;

autoauto x; // Compile time error!

- (CGFloat)getY { // determine y return y; }

float y = self.getY;

autoauto x = 0; // Compile time error!

- (CGFloat)getY { // determine y return y; }

auto y = self.getY; // y is CGFloat

auto^ UIImage * (NSData * result, NSUInteger resultCode, NSDictionary * info) { // do something with data // return image return image; };

autoUIImage * (^b)(NSData * result, NSUInteger resultCode, NSDictionary * info) = ^ UIImage * (NSData * result, NSUInteger resultCode, NSDictionary * info) { // do something with data // return image return image; };

autoid b = ^ UIImage * (NSData * result, NSUInteger resultCode, NSDictionary * info) { // do something with data // return image return image; };

autoid b = ^ UIImage * (NSData * result, NSUInteger resultCode, NSDictionary * info) { // do something with data // return image return image; };

b(result, code, info); // compile time error!

autoauto b = ^ UIImage * (NSData * result, NSUInteger resultCode, NSDictionary * info) { // do something with data // return image return image; };

b(result, code, info); // everything is fine :)

LambdasNSString * s;

const vector<pair<NSString *, NSString *>> v;

LambdasNSString * s;

const vector<pair<NSString *, NSString *>> v;

auto it = find_if(v.begin(), v.end(), [s](const pair<NSString *, NSString *> & p) { return [p.first isEqualToString:s]; });

LambdasNSString * s;

const vector<pair<NSString *, NSString *>> v;

auto it = find_if(v.begin(), v.end(), [s](const auto & p) { return [p.first isEqualToString:s]; });

Lambdas :: mapvector<NSUInteger> v {1, 2, 3};

vector<NSUInteger> v2 (3);

transform(v.begin(), v.end(), v2.begin(), [](auto i) { return ++i; });

// v2 : 2, 3, 4

Lambdas :: filtervector<NSUInteger> v {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

auto const end = remove_if(v.begin(), v.end(), [](auto i) { return i % 2 == 0; });

for (auto i = v.begin(); i != end; ++i) { NSLog(@"%@", @(*i)); } // 1 3 5 7 9

Lambdas[ capture ] ( params ) -> ret { body }

[] - capture nothing

[&] - capture all by reference

[=] - capture all by making copy

[&a] - capture a by reference

[a] - capture a by copy

Lambdastypedef void (^Block) ();

@interface B : NSObject

@property (copy) Block b;

@end

@implementation B

- (void)foo { self.b = ^{ // do something with self NSLog(@"%@", self); }; }

@end

Lambdastypedef void (^Block) ();

@interface B : NSObject

@property (copy) Block b;

@end

@implementation B

- (void)foo { __weak typeof(self) wself = self; self.b = ^{ // do something with wself NSLog(@"%@", wself); }; }

@end

Lambdastypedef void (^Block) ();

@interface B : NSObject

@property (copy) Block b;

@end

@implementation B

- (void)foo { __weak typeof(self) wself = self; self.b = ^{ __strong typeof(self) sself = wself; // do something with sself NSLog(@"%@", sself); }; }

@end

Lambdastypedef void (^Block) ();

@interface B : NSObject

@property (copy) Block b;

@end

@implementation B

- (void)foo { __weak typeof(self) wself = self; self.b = ^{ __strong typeof(self) self = wself; // do something with self NSLog(@"%@", self); }; }

@end

Lambdasusing Lambda = std::function<void()>;

@interface B : NSObject

@property (assign) Lambda l;

@end

@implementation B

- (void)foo { self.l = [self] { //do something with self NSLog(@"%@", self); }; }

@end

ExamplesCGPoint addPoints(CGPoint lhs, CGPoint rhs) { return CGPointMake(lhs.x + rhs.x, lhs.y + rhs.y); }

CGPoint substractPoints(CGPoint lhs, CGPoint rhs) { return CGPointMake(lhs.x - rhs.x, lhs.y - rhs.y); }

CGPoint multiplyPoints(CGPoint lhs, CGPoint rhs) { return CGPointMake(lhs.x * rhs.x, lhs.y * rhs.y); }

CGPoint addValueToPoint(CGPoint lhs, CGFloat rhs) { return CGPointMake(lhs.x + rhs, lhs.y + rhs); }

CGPoint multiplyPointAndValue(CGPoint lhs, CGFloat rhs) { return CGPointMake(lhs.x * rhs, lhs.y * rhs); }

ExamplesCGSize addSizes(CGSize lhs, CGSize rhs) { return CGSizeMake(lhs.width + rhs.width, lhs.height + rhs.height); }

CGSize substractSizes(CGSize lhs, CGSize rhs) { return CGSizeMake(lhs.width - rhs.width, lhs.height - rhs.height); }

CGSize addValueToSize(CGSize lhs, CGFloat rhs) { return CGSizeMake(lhs.width + rhs, lhs.height + rhs); }

CGSize multiplySizes(CGSize lhs, CGSize rhs) { return CGSizeMake(lhs.width * rhs.width, lhs.height * rhs.height); }

CGSize multiplySizeAndValue(CGSize lhs, CGFloat rhs) { return CGSizeMake(lhs.width * rhs, lhs.height * rhs); }

Examplesconst CGPoint p3 = multiplyPointAndValue(addValueToPoint(addPoints(p1, p2), 4), 2);

Examplesinline CGPoint operator+(const CGPoint & lhs, const CGPoint & rhs) { return {lhs.x + rhs.x, lhs.y + rhs.y}; }

inline CGPoint operator-(const CGPoint & lhs, const CGPoint & rhs) { return {lhs.x - rhs.x, lhs.y - rhs.y}; }

inline CGPoint operator*(const CGPoint & lhs, const CGPoint & rhs) { return {lhs.x * rhs.x, lhs.y * rhs.y}; }

template<class T> inline CGPoint operator*(const CGPoint & lhs, const T rhs) { return {lhs.x * rhs, lhs.y * rhs}; }

template<class T> inline CGPoint operator+(const CGPoint & lhs, const T rhs) { return {lhs.x + rhs, lhs.y + rhs}; }

Examplesconst CGPoint p3 = ((p1 + p2) + 4) * 2;

Examples[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] ]];

Examples[CKStackLayoutComponent newWithStyle:{ .direction = CKStackLayoutComponentDirectionVertical, } children:{ {[HeaderComponent newWithArticle:article]}, {[MessageComponent newWithArticle:article]}, {[FooterComponent newWithArticle:article]}, }];

Examples@interface Point : NSObject

@property (nonatomic, readonly) CLLocationCoordinate2D coordinate; @property (nonatomic, readonly) NSString * identifier; @property (nonatomic, readonly) BOOL isMyPosition;

- (instancetype)initWithCoordinate:(CLLocationCoordinate2D)coordinate identifier:(NSString *)identifier isMyPosition:(BOOL)isMyPosition;

- (instancetype)initWithCoordinate(CLLocationCoordinate2D)coordinate;

- (BOOL)isEqual:(Point *)object;

+ (Point *)zeroPoint;

@end

@protocol RoutingProtocol <NSObject>

- (void)buildRouteFrom:(Point *)from to:(Point *)to;

@end

@interface Point : NSObject

@property (nonatomic, readonly) CLLocationCoordinate2D coordinate; @property (nonatomic, readonly) NSString * identifier; @property (nonatomic, readonly) BOOL isMyPosition;

- (instancetype)initWithCoordinate:(CLLocationCoordinate2D)coordinate identifier:(NSString *)identifier isMyPosition:(BOOL)isMyPosition;

- (instancetype)initWithCoordinate:(CLLocationCoordinate2D)coordinate;

- (BOOL)isEqual:(Point *)object;

+ (Point *)zeroPoint;

@end

@protocol RoutingProtocol <NSObject>

- (void)buildRouteFrom:(Point *)from to:(Point *)to;

@end

Point * myPosition = [[Point alloc] initWithCoordinate:firstCoordinate]; Point * second = [[Point alloc] initWithCoordinate:secondCoordinate identifier:secondIdentifier isMyPosition:isSecondMyPosition]; [self.delegate buildRouteFrom:myPosition to:second];

After rename file to .mmclass Point { CLLocationCoordinate2D coordinate; NSString * identifier; BOOL isMyPosition;

BOOL ArePointsEqual(const Point & rhs) { return coordinate.latitude == rhs.coordinate.longitude && coordinate.longitude == rhs.coordinate.longitude && [identifier isEqualToString:rhs.identifier] && isMyPosition == rhs.isMyPosition; }

static Point zeroPoint() { return {{0, 0}, @"", NO}; } };

@protocol RoutingProtocol <NSObject>

- (void)buildRouteFrom:(const Point &)from to:(const Point &)to;

@end

const Point first = {firstCoordinate, firstIdentifier, isFirstMyPosition}; const Point second = {secondCoordinate, secondIdentifier, isSecondMyPosition};

[self.delegate buildRouteFrom:first to:second];

After rename file to .mmclass Point { CLLocationCoordinate2D coordinate; NSString * identifier; BOOL isMyPosition;

BOOL operator ==(const Point & rhs) { return coordinate.latitude == rhs.coordinate.longitude && coordinate.longitude == rhs.coordinate.longitude && [identifier isEqualToString:rhs.identifier] && isMyPosition == rhs.isMyPosition; }

BOOL operator !=(const Point & rhs) { return !(*this == rhs); }

static Point zeroPoint() { return {{0, 0}, @"", NO}; } };

class Point { public: BOOL operator ==(const Point & rhs) const { return coordinate.latitude == rhs.coordinate.longitude && coordinate.longitude == rhs.coordinate.longitude && [identifier isEqualToString:rhs.identifier] && isMyPosition == rhs.isMyPosition; }

BOOL operator !=(const Point & rhs) const { return !(*this == rhs); }

static Point zeroPoint() { return {{0, 0}, @"", NO}; }

CLLocationCoordinate2D coordinate; NSString * identifier; BOOL isMyPosition; };

class Point { public:

BOOL operator ==(const Point & rhs) const { return _coordinate.latitude == rhs.coordinate().longitude && _coordinate.longitude == rhs.coordinate().longitude && [_identifier isEqualToString:rhs.identifier()] && _isMyPosition == rhs.isMyPosition(); }

BOOL operator !=(const Point & rhs) const { return !(*this == rhs); }

static Point zeroPoint() { return {{0, 0}, @"", NO}; }

CLLocationCoordinate2D const & coordinate() const { return _coordinate; }

NSString * identifier() const { return _identifier; }

BOOL isMyPosition() const { return _isMyPosition; }

private: CLLocationCoordinate2D _coordinate; NSString * _identifier; BOOL _isMyPosition; };

class Point { public: Point(const CLLocationCoordinate2D & c, NSString * i, BOOL p) : _coordinate(c), _identifier(i), _isMyPosition(p) {}

BOOL operator ==(const Point & rhs) const { return _coordinate.latitude == rhs.coordinate().longitude && _coordinate.longitude == rhs.coordinate().longitude && [_identifier isEqualToString:rhs.identifier()] && _isMyPosition == rhs.isMyPosition(); }

BOOL operator !=(const Point & rhs) const { return !(*this == rhs); }

static Point zeroPoint() { return {{0, 0}, @"", NO}; }

CLLocationCoordinate2D const & coordinate() const { return _coordinate; }

NSString * identifier() const { return _identifier; }

BOOL isMyPosition() const { return _isMyPosition; }

private: CLLocationCoordinate2D _coordinate; NSString * _identifier; BOOL _isMyPosition; };

class Point { public: Point(const CLLocationCoordinate2D & c, NSString * i, BOOL p) : _coordinate(c), _identifier(i), _isMyPosition(p) {} Point(const CLLocationCoordinate2D & c) : _coordinate(c), _identifier(@"My position"), _isMyPosition(YES) {}

BOOL operator ==(const Point & rhs) const { return _coordinate.latitude == rhs.coordinate().longitude && _coordinate.longitude == rhs.coordinate().longitude && [_identifier isEqualToString:rhs.identifier()] && _isMyPosition == rhs.isMyPosition(); }

BOOL operator !=(const Point & rhs) const { return !(*this == rhs); }

static Point zeroPoint() { return {{0, 0}, @"", NO}; }

CLLocationCoordinate2D const & coordinate() const { return _coordinate; }

NSString * identifier() const { return _identifier; }

BOOL isMyPosition() const { return _isMyPosition; }

private: CLLocationCoordinate2D _coordinate; NSString * _identifier; BOOL _isMyPosition; };

class Point { public: Point(const CLLocationCoordinate2D & c, NSString * i, BOOL p) : _coordinate(c), _identifier(i), _isMyPosition(p) {} Point(const CLLocationCoordinate2D & c) : _coordinate(c), _identifier(@"My position"), _isMyPosition(YES) {} Point() = default;

BOOL operator ==(const Point & rhs) const { return _coordinate.latitude == rhs.coordinate().longitude && _coordinate.longitude == rhs.coordinate().longitude && [_identifier isEqualToString:rhs.identifier()] && _isMyPosition == rhs.isMyPosition(); }

BOOL operator !=(const Point & rhs) const { return !(*this == rhs); }

static Point zeroPoint() { return Point(); }

CLLocationCoordinate2D const & coordinate() const { return _coordinate; }

NSString * identifier() const { return _identifier; }

BOOL isMyPosition() const { return _isMyPosition; }

private: CLLocationCoordinate2D _coordinate; NSString * _identifier; BOOL _isMyPosition = false; };

BeforePoint * myPosition = [[Point alloc] initWithCoordinate:firstCoordinate]; Point * second = [[Point alloc] initWithCoordinate:secondCoordinate identifier:secondIdentifier isMyPosition:isSecondMyPosition]; [self.delegate buildRouteFrom:myPosition to:second];

After[self.delegate buildRouteFrom:{myPositionCoordinate} to:{secondCoordinate, secondIdentifier, isSecondMyPosition}];

BeforePoint * myPosition = [[Point alloc] initWithCoordinate:firstCoordinate]; Point * second = [[Point alloc] initWithCoordinate:secondCoordinate identifier:secondIdentifier isMyPosition:isSecondMyPosition]; [self.delegate buildRouteFrom:myPosition to:second];

Shoot yourself in the foot1.Property 2.Default constructor 3.Сopying 4.Aggregate initialization after reordering

Popular projects• Objective-C Runtime • Facebook Pop • Facebook ComponentKit • Realm

Popular projects• Objective-C Runtime • Facebook Pop • Facebook ComponentKit • Realm

And another one…

Thanks!