📜 ⬆️ ⬇️

Xcode 6 Objective-C Modernization Tool

For quite some time now in Xcode there is an opportunity to check your code for compliance with the modern features of Objective-C (Edit> Refactor> Convert to Modern Objective-C Syntax ...). It has always been interesting to watch what Apple is promoting as a good practice; and even if you don’t trust Xcode to automatically change the code, this is an easy way to test it for potential improvements.

Xcode 6 introduces several innovations, and in addition, much more flexibility, allowing you to independently control which transformations to run:


')
Unfortunately, from the description of the transformation it is not always obvious what it does. Some useful details can be found in the Adopting Modern Objective-C manual, and also look at WWDC 2014 Session 417 What's New in LLVM . This article contains my notes on each of the transformations.


@Property syntax


The introduction of new syntax for properties can hardly be called news. Xcode 6 has expanded the list of innovations by adding two options for detecting properties along with control of their atomicity.



Selecting these options will search for the missing @property declaration by defining potential getter and setter methods in the class. For example, for such a class with two methods without the corresponding property:

 - (NSString *)name; - (void)setName:(NSString *)newName; 


Xcode will infer the need for the property and add it to the class interface:

 @property (nonatomic, copy) NSString *name; 


The property declaration clearly shows the purpose of the two methods and allows the compiler to automatically synthesize the accessor. You should be careful here, because the two existing methods will not be automatically deleted. If they describe non-standard behavior, this can be dangerous. In addition, Xcode can overdo it and offer a property for methods that are not getter or setter methods, which makes this conversion less useful.



This option allows you to choose whether you want the creation of an advertisement for the property that you just found to be atomic , nonatomic or the NS_NONATOMIC_IOSONLY macro. The latter is nothing more than a macro that takes nonatomic value for iOS and does nothing for OS X. If you write code for both systems, this will be useful to you. Otherwise, in most cases, it is worthwhile to dwell on nonatomic .

 @property (NS_NONATOMIC_IOSONLY, readonly, copy) NSDate *dueDate; 


Designated Designer (designated Initializer)


Infer designated initializer methods transform identifies and marks assigned constructors using NS_DESIGNATED_INITIALIZER . To understand what it is and why it is needed, it is worth remembering briefly how object initialization works in Objective-C. Creating an object in Objective-C takes place in two steps: memory allocation, and then initialization. Usually they are written in one line:

 MyObject *object = [[MyObject alloc] init]; 


The initialization method is responsible both for setting the value for any instance-variable, and for all other initial tasks for the object. A class can have many initialization methods, which by convention begin with the prefix init . For example, a class with an instance variable must always be defined; there may be an initialization method that includes the name:

 - (instancetype)init { return [self initWithName:@"Unknown"]; } - (instancetype)initWithName:(NSString *)name { self = [super init]; if (self) { _name = [name copy]; } return self; } 


A simple init in this case is a convenient (convenience) constructor, which is simply called the designated constructor initWithName: using the default value as a parameter. The assigned method ensures that the object is fully initialized by invoking inherited init .
If now this class has an heir, then the heir will be important details of the implementation of the superclass. Rules for Designers Designated :



For a long time there was no way to show the compiler or the one who uses the class, which of the initialization methods is assigned (except in the comment). Now, to correct this situation, Clang has an objc_designated_initializer attribute. And in iOS 8 there is the NS_DESIGNATED_INITIALIZER macro defined in NSObjCRuntime.h, which makes it easier to apply this attribute to the method:

 #define NS_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer)) 


The example considered earlier in this case can be written as:

 - (instancetype)init; - (instancetype)initWithName:(NSString *)name NS_DESIGNATED_INITIALIZER; 


Now, if you have added a convenient constructor that the designated constructor does not call, you will receive a warning.
I saw people reporting problems with some UIKit classes, in which Apple had not yet marked the designated designers, so that, as usual, it would not hurt to test and send an error report in case of unexpected results.

Infer Instancetype for Method Result Type


Allows you to replace id with instancetype as the return type for the alloc , init and new methods. The factory methods of the class may have to be changed manually. More details on how to increase the reliability of the code using instancetype can be found in the article NSHipster .

Infer Protocol Conformance


This conversion, disabled by default, allows Xcode to add the missing protocol support declaration. For example, here is a simple controller that does not declare support for any protocol:

 @interface UYLViewController : UIViewController 


If this class implements two required methods for the UITableViewDataSource protocol -tableView:numberOfRowsInSection: and -tableView:cellForRowAtIndexPath: then the interface description will be changed as follows:

 @interface UYLViewController : UIViewController<UITableViewDataSource> 


From myself I can add that this happens only if all the required methods are implemented. I did not manage to achieve, for example, adding support for the UITableViewDelegate protocol if only optional methods were implemented.

Objective-C Literals


Literals and Objective-C indexing have already been introduced in Xcode, so I’ll just give a quick example:

 NSNumber *magicNumber = [NSNumber numberWithInteger:42]; NSDictionary *myDictionary = [NSDictionary dictionaryWithObject:magicNumber forKey:@"magic"]; 


Refactoring using literals and indexing Objective-C leads to more compact code:

 NSNumber *magicNumber = @42; NSDictionary *myDictionary = @{@"magic": magicNumber}; 


Transfers


The NS_ENUM and NS_OPTIONS .
Modern NS_ENUM and NS_OPTIONS are a quick and easy way to create enums with the type and size specified to the compiler. For example, enumerated type:

 enum { UYLTypeDefault, UYLTypeSmall, UYLTypeLarge }; typedef NSInteger UYLType; 


after refactoring using NS_ENUM turns into:

 typedef NS_ENUM(NSInteger, UYLType) { UYLTypeDefault, UYLTypeSmall, UYLTypeLarge }; 


Similarly, a set of bit masks:

 enum { UYLBitMaskA = 0, UYLBitMaskB = 1 << 0, UYLBitMaskC = 1 << 1, UYLBitMaskD = 1 << 2 }; typedef NSUInteger UYLBitMask; 


after refactoring using NS_OPTIONS turns into:

 typedef NS_OPTIONS(NSUInteger, UYLBitMask) { UYLBitMaskA = 0, UYLBitMaskB = 1 << 0, UYLBitMaskC = 1 << 1, UYLBitMaskD = 1 << 2 }; 


Add attribute annotations

Could not achieve any result by selecting this option. The explanation assumes that annotations will be added to properties and methods, but I could not determine which attributes will be added and under what conditions. Leave a comment if you know ...

Original Posted by: Keith Harrison.

Source: https://habr.com/ru/post/249029/


All Articles