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 pointers
vector<Dog *> v {droopy, goofy, pluto};
for (const auto & d : v)
{
d->bark();
delete d;
}
smart pointers
vector<shared_ptr<Dog>> v {make_shared<Dog>(droopy),
make_shared<Dog>(goofy),
make_shared<Dog>(pluto)};
for (const auto & d : v)
{
d->bark();
}
smart pointers
vector<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 pointers
vector<unique_ptr<Dog>> v {make_unique<Dog>(droopy),
make_unique<Dog>(goofy),
make_unique<Dog>(pluto)};
for (const auto & d : v)
{
d->bark();
}
smart pointers
vector<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 pointers
vector<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
move
class Pasteboard
{
public:
Pasteboard() = default;
Pasteboard(const string t) : text(t) {}
private:
string text;
};
move
class Pasteboard
{
public:
Pasteboard() = default;
Pasteboard(const string t) : text(t) {}
Pasteboard(string && t) : text(move(t)) {}
private:
string text;
};
move
vector<unique_ptr<Dog>> getDogs()
{
// Create and return vector
return v;
}
auto v = getDogs();
auto
int x;
auto
int x;
- (CGFloat)getY
{
// determine y
return y;
}
float y = self.getY;
auto
auto x; // Compile time error!
- (CGFloat)getY
{
// determine y
return y;
}
float y = self.getY;
auto
auto 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;
};
auto
UIImage * (^b)(NSData * result, NSUInteger resultCode, NSDictionary * info) = ^
UIImage * (NSData * result, NSUInteger resultCode, NSDictionary * info)
{
// do something with data
// return image
return image;
};
auto
id b = ^ UIImage * (NSData * result, NSUInteger resultCode, NSDictionary * info)
{
// do something with data
// return image
return image;
};
auto
id b = ^ UIImage * (NSData * result, NSUInteger resultCode, NSDictionary * info)
{
// do something with data
// return image
return image;
};
b(result, code, info); // compile time error!
auto
auto b = ^ UIImage * (NSData * result, NSUInteger resultCode, NSDictionary * info)
{
// do something with data
// return image
return image;
};
b(result, code, info); // everything is fine :)
Lambdas
NSString * s;
const vector<pair<NSString *, NSString *>> v;
Lambdas
NSString * 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];
});
Lambdas
NSString * 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 :: map
vector<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 :: filter
vector<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
Lambdas
typedef void (^Block) ();
@interface B : NSObject
@property (copy) Block b;
@end
@implementation B
- (void)foo
{
self.b = ^{
// do something with self
NSLog(@"%@", self);
};
}
@end
Lambdas
typedef 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
Lambdas
typedef 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
Lambdas
typedef 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
Lambdas
using 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
Examples
CGPoint 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);
}
Examples
CGSize 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);
}
Examples
const CGPoint p3 = multiplyPointAndValue(addValueToPoint(addPoints(p1, p2), 4), 2);
Examples
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};
}
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};
}
Examples
const 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 .mm
class 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 .mm
class 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;
};
Before
Point * 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}];
Before
Point * 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 foot
1. 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!

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

  • 1.
  • 2.
    Why Objective-C++ 1. Compiletime 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
  • 3.
  • 4.
  • 5.
    std::vector<T> • Continuos blockin memory • Strong typing • nullptr safety • Stack or heap
  • 6.
    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 }
  • 7.
    std::vector<T> // Warning: Incompatiblepointer types sending 'NSNumber *' to parameter of type 'NSString * _Nonnull' NSMutableArray<NSString *> * a = [@[@""] mutableCopy]; [a addObject:@0];
  • 8.
    std::vector<T> // Warning: Incompatiblepointer 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);
  • 9.
    std::vector<T> // Warning: Incompatiblepointer 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];
  • 10.
    std::array<T, size_t> • Fixedsize • Strong typing • Compile time
  • 11.
    std::array<T, size_t> static constNSArray<NSString *> * const kTypes = @[@"Fast Food", @"Pizza", @"Italian", @"Beer", @"Sushi"];
  • 12.
    std::array<T, size_t> static constNSArray<NSString *> * const kTypes = @[@"Fast Food", @"Pizza", @"Italian", @"Beer", @«Sushi"]; static const std::array<NSString *, 5> kTypes = {{@«Fast Food", @"Pizza", @"Italian", @"Beer", @«Sushi"}};
  • 13.
    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
  • 14.
    std::pair<T, T> &std::tuple<T> - (void)getLat:(double &)lat lon:(double &)lon; double lat, lon = 0; [self getLat:lat lon:lon];
  • 15.
    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];
  • 16.
    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];
  • 17.
    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;
  • 18.
    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);
  • 19.
    smart pointers vector<Dog *>v {droopy, goofy, pluto}; for (const auto & d : v) { d->bark(); delete d; }
  • 20.
    smart pointers vector<shared_ptr<Dog>> v{make_shared<Dog>(droopy), make_shared<Dog>(goofy), make_shared<Dog>(pluto)}; for (const auto & d : v) { d->bark(); }
  • 21.
    smart pointers vector<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;
  • 22.
    smart pointers vector<unique_ptr<Dog>> v{make_unique<Dog>(droopy), make_unique<Dog>(goofy), make_unique<Dog>(pluto)}; for (const auto & d : v) { d->bark(); }
  • 23.
    smart pointers vector<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!
  • 24.
    smart pointers vector<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
  • 25.
    move class Pasteboard { public: Pasteboard() =default; Pasteboard(const string t) : text(t) {} private: string text; };
  • 26.
    move class Pasteboard { public: Pasteboard() =default; Pasteboard(const string t) : text(t) {} Pasteboard(string && t) : text(move(t)) {} private: string text; };
  • 27.
    move vector<unique_ptr<Dog>> getDogs() { // Createand return vector return v; } auto v = getDogs();
  • 28.
  • 29.
    auto int x; - (CGFloat)getY { //determine y return y; } float y = self.getY;
  • 30.
    auto auto x; //Compile time error! - (CGFloat)getY { // determine y return y; } float y = self.getY;
  • 31.
    auto auto x =0; // Compile time error! - (CGFloat)getY { // determine y return y; } auto y = self.getY; // y is CGFloat
  • 32.
    auto ^ UIImage *(NSData * result, NSUInteger resultCode, NSDictionary * info) { // do something with data // return image return image; };
  • 33.
    auto UIImage * (^b)(NSData* result, NSUInteger resultCode, NSDictionary * info) = ^ UIImage * (NSData * result, NSUInteger resultCode, NSDictionary * info) { // do something with data // return image return image; };
  • 34.
    auto id b =^ UIImage * (NSData * result, NSUInteger resultCode, NSDictionary * info) { // do something with data // return image return image; };
  • 35.
    auto id b =^ UIImage * (NSData * result, NSUInteger resultCode, NSDictionary * info) { // do something with data // return image return image; }; b(result, code, info); // compile time error!
  • 36.
    auto auto b =^ UIImage * (NSData * result, NSUInteger resultCode, NSDictionary * info) { // do something with data // return image return image; }; b(result, code, info); // everything is fine :)
  • 37.
    Lambdas NSString * s; constvector<pair<NSString *, NSString *>> v;
  • 38.
    Lambdas NSString * s; constvector<pair<NSString *, NSString *>> v; auto it = find_if(v.begin(), v.end(), [s](const pair<NSString *, NSString *> & p) { return [p.first isEqualToString:s]; });
  • 39.
    Lambdas NSString * s; constvector<pair<NSString *, NSString *>> v; auto it = find_if(v.begin(), v.end(), [s](const auto & p) { return [p.first isEqualToString:s]; });
  • 40.
    Lambdas :: map vector<NSUInteger>v {1, 2, 3}; vector<NSUInteger> v2 (3); transform(v.begin(), v.end(), v2.begin(), [](auto i) { return ++i; }); // v2 : 2, 3, 4
  • 41.
    Lambdas :: filter vector<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
  • 42.
    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
  • 43.
    Lambdas typedef void (^Block)(); @interface B : NSObject @property (copy) Block b; @end @implementation B - (void)foo { self.b = ^{ // do something with self NSLog(@"%@", self); }; } @end
  • 44.
    Lambdas typedef 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
  • 45.
    Lambdas typedef 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
  • 46.
    Lambdas typedef 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
  • 47.
    Lambdas using 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
  • 48.
    Examples CGPoint 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); }
  • 49.
    Examples CGSize 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); }
  • 50.
    Examples const CGPoint p3= multiplyPointAndValue(addValueToPoint(addPoints(p1, p2), 4), 2);
  • 51.
    Examples inline CGPoint operator+(constCGPoint & 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}; }
  • 52.
    Examples const CGPoint p3= ((p1 + p2) + 4) * 2;
  • 53.
    Examples [CKStackLayoutComponent newWithStyle: [[CKStackLayoutComponentStyle alloc] initWithDirection:CKStackLayoutComponentDirectionVertical justifyContent:CKStackLayoutComponentJustifyContentStart alignItems:CKStackLayoutComponentAlignItemsStart spacing:0] children: @[[CKStackLayoutComponentChildchildWithComponent:[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] ]];
  • 54.
    Examples [CKStackLayoutComponent newWithStyle:{ .direction = CKStackLayoutComponentDirectionVertical, } children:{ {[HeaderComponentnewWithArticle:article]}, {[MessageComponent newWithArticle:article]}, {[FooterComponent newWithArticle:article]}, }];
  • 55.
    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
  • 56.
    @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];
  • 57.
    After rename fileto .mm class 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];
  • 58.
    After rename fileto .mm class 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}; } };
  • 59.
    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; };
  • 60.
    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; };
  • 61.
    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; };
  • 62.
    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; };
  • 63.
    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; };
  • 64.
    Before Point * myPosition= [[Point alloc] initWithCoordinate:firstCoordinate]; Point * second = [[Point alloc] initWithCoordinate:secondCoordinate identifier:secondIdentifier isMyPosition:isSecondMyPosition]; [self.delegate buildRouteFrom:myPosition to:second];
  • 65.
    After [self.delegate buildRouteFrom:{myPositionCoordinate} to:{secondCoordinate, secondIdentifier,isSecondMyPosition}]; Before Point * myPosition = [[Point alloc] initWithCoordinate:firstCoordinate]; Point * second = [[Point alloc] initWithCoordinate:secondCoordinate identifier:secondIdentifier isMyPosition:isSecondMyPosition]; [self.delegate buildRouteFrom:myPosition to:second];
  • 66.
    Shoot yourself inthe foot 1. Property 2. Default constructor 3. Сopying 4. Aggregate initialization after reordering
  • 67.
    Popular projects • Objective-CRuntime • Facebook Pop • Facebook ComponentKit • Realm
  • 68.
    Popular projects • Objective-CRuntime • Facebook Pop • Facebook ComponentKit • Realm And another one…
  • 70.