"О некоторых особенностях Objective-C++" Влад Михайленко (Maps.Me)
Post on 13-Apr-2017
314 Views
Preview:
Transcript
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
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>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; };
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;
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); }
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}; }
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
And another one…
top related