There are many cases in which macOS applications should take advantage of historical processes and existing code, and there are many cases that cannot be completed using Swift alone. Therefore, Objective-C code and C/C++ code coexist.
When writing code in such a situation where multiple languages coexist, I strongly feel that we should brush up the coexisting Objective-C code to make it easier to use from Swift, and put in precautions to prepare it for use from Swift and for when it is incorporated into other projects.
Declare that it is ARC compliant
This is a precautionary measure in case it is incorporated into another project.
If your code has been maintained since the days before macOS 10.6, some code is non-compliant with ARC (Automatic Reference Counting). Where we can say with confidence that this is not the case is in programs that have caught on quickly at a cost, or in small to medium-sized programs. For larger programs, it is difficult to implement ARC in the middle of a program.
In my case, I have not implemented ARC because it is a large program. However, an opportunity arose to port a small portion of the code to a program written in Swift. Most of the project to be ported is written in Swift, and some Objective-C code is also ARC-compatible. We could set it up so that only the source files to be ported are exempt from ARC, but that would be a bad idea for the future. We thought we had a good opportunity to brush up and modified the code to be ARC-compatible before incorporating it.
However, it is highly likely that this code will be ported again to some other project. It may be ported again to a project that does not support ARC. In case that happens, the following code should be written.
#if !__has_feature(objc_arc) #error This source file must be compiled with ARC. #endif
This code will cause a build error if you try to build in a project that does not support ARC. The source file will be built with ARC enabled in the project where the error occurred. Or, depending on the size of the project, the entire project may be ARC-enabled.
Even if you put it in a comment or something, they probably won’t see it. They won’t notice. They will only notice when an error occurs.
Conversely, incorporating non-ARC compliant code into an ARC compliant project will result in an error. Therefore, the reverse case can be noticed immediately.
Preparing for Swift’s Optional
Swift has a feature called “Optional”. It allows code to indicate whether a property, argument, or function return value can be
There is no “Optional” in Objective-C. Objective-C is a language characterized by the fact that anything you do to an instance that is
nil will be ignored. In a sense, it assumes that all instances will be
This is incompatible with Swift; it is an element that gets in the way when calling Objective-C methods from the Swift.
So Objective-C has been improved: you can now write on the Objective-C whether or not it can be
nil, so that when you use it from Swift, it will be mapped based on the code to an optional type and a non-optional type. This allows us to map between optional and non-optional types based on the code.
nonnull when there is no possibility of being
nullable when there is a possibility of being
The nullability can be specified as a return value, argument, property, etc. Of course, when you write this, be sure that the implementation of the method is as specified, rather than just writing it as is. If you specify
nil, Swift will have a problem with it. They are too bad.
@interface MyObject : NSObject // nilにならないプロパティ @property (nonnull, nonatomic, strong) NSString *firstName; @property (nonnull, nonatomic, strong) NSString *lastName; // nilになるかもしれないプロパティ @property (nullable, nonatomic, strong) NSString *middleName; // メソッドの戻り値や引数にも指定する - (nullable MyObject *)nextObject; - (nonnull NSString *)fullNameWithPrefix:(nullable NSString *)prefix suffix:(nullable NSString *)suffix; @end
About pointers and instances of C++ classes
For pointers and instances of C++ classes, use
_Nonnull instead of
_Nullable instead of
nullable. Also, the place to write the following.
Type * _Nonnull variable Type * _Nullable variable
For example, with a pointer in the block argument and
_Nullable, it would be written as follows.
typedef void (^ExampleBlock)(const char * _Nonnull ptr, const int * _Nullable);
For pointers to pointers such as handles, two must be written.
typedef void (^ExampleBlock)(const char * _Nonnull * _Nonnull handle, const int * _Nullable);
Write the type of the element in the collection
When you write collections such as
NSDictionary, you should also write the type of the element being stored. If you don’t write it, it becomes
Any in Swift, which is unwieldy.
The type of element can be declared with the following code. Of course, since it is Objective-C, you can store other things even if you have declared them. But don’t do it, because it will cause trouble.
// Array of NSString * NSArray<NSString *> *stringArray; // Dictionary with key is NSNumber * and value is NSString * NSDictionary<NSNumber *, NSString *> *mappingTable;