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.
- Infer readonly properties (Yes by default)
- Infer readwrite properties (Yes by default)
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.
- Atomicity of inferred properties (default is NS_NONATOMIC_IOSONLY)
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 :
- designated constructor. must call (via super) the designated superclass constructor. For a class inheriting from NSObject, this will be just
[super init]
. - Any convenient constructor should call another constructor in its class, which will eventually lead to the designated constructor.
- A class with a designated constructor must implement all designated constructors of the superclass.
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.