最新の Objective-C の採用


長年にわたり、Objective-C 言語は成長し、進化してきました。コアの概念と実践は同じままですが、言語の部分が大幅な変更と改善をしてきました。これらの近代化は、あなたが簡単に正しいコードを書くために、型の安全性、メモリ管理、パフォーマンス、および Objective-C の他の側面を改善しています。それはより多くの一貫性があり、読みやすく、そして弾力性のあるように既存および将来のコードでこれらの変更を適用することが重要です。


Xcode はこれらの構造変化のいくつかを作る手助けになるツールを提供します。しかし、このツールを使用する前に、それがコードを作るために提供する変更内容を理解し、そしてそれがなぜかを考えて下さい。この文書では、コードベースの採用を、最も重要かつ有用な現代化のいくつかである事を強調しています。


instancetype


それらが呼び出されるクラスのインスタンス (またはそのクラスのサブクラス) を返すメソッドの戻り値の型として instancetype キーワードを使用して下さい。これらのメソッドは、alloc,init そして、クラスファクトリメソッドを含んでいます。


適切な場所で id の代わりに instancetype を使用すると、Objective-C コードの型の安全性を向上させます。たとえば、以下のコードを考えてみます。



@interface MyObject : NSObject
+ (instancetype)factoryMethodA;
+ (id)factoryMethodB;
@end
 
@implementation MyObject
+ (instancetype)factoryMethodA { return [[[self class] alloc] init]; }
+ (id)factoryMethodB { return [[[self class] alloc] init]; }
@end
 
void doSomething() {
    NSUInteger x, y;
 
    x = [[MyObject factoryMethodA] count]; // Return type of +factoryMethodA is taken
    					   // to be "MyObject *"
    y = [[MyObject factoryMethodB] count]; // Return type of +factoryMethodB is "id"
}



+ factoryMethodAinstancetype の戻り値の型は、そのメッセージ式の型が MyObject * であり、MyObject には -count メソッドがないため、コンパイラは、x 行についての警告を与えます:



main.m: ’MyObject’ may not respond to ‘count’



しかし、+factoryMethodBid 戻り値の型のため、コンパイラは、y 行についての警告を与えられきません。 id 型のオブジェクトは、どのクラスにもすることができるため、またいずれかのクラスのどこかに存在する -count と呼ばれるメソッドのため、コンパイラには、+factoryMethodB の戻り値はメソッドを実装している可能性があります。


必ず instancetype ファクトリメソッドが、正しいサブクラス化挙動を有するようにするには、クラス名を直接参照するのではなく、クラスを割り当てる時には、[self class] を必ず使用してください。この規則に従うと、コンパイラは正しくサブクラスの型を推論することが保証されます。たとえば、前の例からの MyObject のサブクラスでこれをしようと考えてみましょう。



@interface MyObjectSubclass : MyObject
@end
 
void doSomethingElse() {
        NSString *aString = [MyObjectSubclass factoryMethodA];
}



コンパイラは、このコードに関して以下の警告を与えます:



main.m: Incompatible pointer types initializing ’NSString *’ with an expression of 
type ’MyObjectSubclass *’



この例では、+factoryMethodA のメッセージは、受信者の型である MyObjectSubclass、型のオブジェクトを返します。コンパイラが適切に、+factoryMethodA の戻り値の型が、ファクトリメソッドが宣言されたスーパークラスのものではなく、サブクラス MyObjectSubclass のものであるべきと判断します。



どのように採用するか


あなたのコードで、戻り値としての id の発生を、適切な場所で instancetype と置き換えて下さい。これは、一般的には init メソッドとクラスファクトリメソッドの場合に当てはまります。コンパイラが "alloc","init",または "new" で始まるメソッド、そして id の戻り値の型を持つメソッドを自動的に instancetype を返すように変換したとしても、他のメソッドは変換しません。Objective-C の規則では、すべてのメソッドに対して明示的に instancetype を書くことになっています。


ただ戻り値だけで、コード内の他の場所ではなく、 instancetypeid を置き換える必要があることに注意してください。id とは異なり、 instancetype キーワードは、メソッド宣言で戻り値型としてのみ使用できます。


例えば:



@interface MyObject
- (id)myFactoryMethod;
@end



は以下のようになります:



@interface MyObject
- (instancetype)myFactoryMethod;
@end



代わりに、コードで自動的にこの変更を行うために Xcode で現代的な Objective-C へのコンバータを使用することができます。詳細については、Xcode を使用してコードをリファクタリング を参照してください。


プロパティ


Objective-C の プロパティ@property 構文で宣言した public または private メソッドです。



@property (readonly, getter=isBlue) BOOL blue;



プロパティは、オブジェクトの状態をキャプチャします。それは、オブジェクトの本質的な属性や他のオブジェクトとの関係を反映します。プロパティは、カスタムアクセサメソッドの設定を記述する必要なく、これらの属性と対話するための安全な、便利な方法を提供します。(プロパティはカスタムのゲッタとセッタを、必要に応じて許可しますが)


できるだけ多くの場所でインスタンス変数の代わりに、プロパティを使用するのは、多くの利点があります。


  • 自動同期するゲッタとセッタ。 プロパティを宣言すると、デフォルトでゲッタメソッドとセッタメソッドが作成されます。
  • メソッドの設定の意図をよりよく宣言。 アクセサメソッドの命名規則のため、ゲッタとセッタが何をしているかが正確に明らかになります。
  • 動作に関する追加情報を表現するプロパティのキーワード。 プロパティは、 assign (vs copy),weak,atomic (vs nonatomic) などの属性の宣言の可能性を提供します。

  • プロパティメソッドは、単純な命名規則に従います。ゲッタ は、プロパティの名前 (例えば、date)、セッタ はキャメルケース (例えば、setDate) で記述された set の接頭辞を持つプロパティの名前です。ブール型のプロパティの命名規則は、ゲッタは単語 "is" で始まる名前でそれらを宣言することです:



    @property (readonly, getter=isBlue) BOOL blue;



    その結果、以下に挙げたすべてはきちんと動きます:



    if (color.blue) { }
    if (color.isBlue) { }
    if ([color isBlue]) { }
    
    


    プロパティにできるものを決定する際に、以下の物はプロパティではないことに注意してください。


    加えて、あなたのコード内の潜在的なプロパティを識別するときには、以下の一連のルールを考慮してください。


    どのように採用するか


    プロパティに変換する資格を持つメソッドの一揃いを識別します。これらのような:



    - (NSColor *)backgroundColor;
    - (void)setBackgroundColor:(NSColor *)color;
    
    


    そして適切なキーワード(複数可)で @property 構文を使用してそれらを宣言します。



    @property (copy) NSColor *backgroundColor;
    
    


    プロパティのキーワードやその他の考慮事項については、 カプセル化データ を参照してください。


    代わりに、自動的にあなたのコードにこの変更を行うために Xcode で現代的な Objective-C のコンバータを使用することができます。詳細については、Xcode を使用してコードをリファクタリング を参照してください。


    列挙型マクロ


    NS_ENUMNS_OPTIONS マクロは、C ベースの言語で列挙型とオプションを定義する簡潔な、簡単な方法を提供します。これらのマクロは、Xcode でのコード補完を改善し、明示的に列挙型とオプションの型とサイズを指定します。さらに、この構文は古いコンパイラによって正しく評価されている方法で列挙型 (enums) を宣言し、基礎となる型情報を解釈できる新しいもので宣言します。


    相互に排他的である一揃いの値、列挙型 を定義するために NS_ENUM マクロを使用して下さい。



    typedef NS_ENUM(NSInteger, UITableViewCellStyle) {
            UITableViewCellStyleDefault,
            UITableViewCellStyleValue1,
            UITableViewCellStyleValue2,
            UITableViewCellStyleSubtitle
    };
    
    


    NS_ENUM マクロは NSInteger 型の UITableViewCellStyle という名前のこの場合は、名前と列挙型の両方を定義するのに役立ちます。列挙型の型は、NSInteger でなければなりません。


    一緒に組み合わせることができるビットマスク値の一揃いの オプション を定義するために NS_OPTIONS マクロを使用して下さい。



    typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
            UIViewAutoresizingNone                 = 0,
            UIViewAutoresizingFlexibleLeftMargin   = 1 << 0,
            UIViewAutoresizingFlexibleWidth        = 1 << 1,
            UIViewAutoresizingFlexibleRightMargin  = 1 << 2,
            UIViewAutoresizingFlexibleTopMargin    = 1 << 3,
            UIViewAutoresizingFlexibleHeight       = 1 << 4,
            UIViewAutoresizingFlexibleBottomMargin = 1 << 5
    };
    
    


    列挙型と同様に、NS_OPTIONS マクロは名前と型の両方を定義します。しかし、オプションの型は通常 NSUInteger でなければなりません。


    どのように採用するか


    以下のように、enum 宣言を、置き換えます:



    enum {
            UITableViewCellStyleDefault,
            UITableViewCellStyleValue1,
            UITableViewCellStyleValue2,
            UITableViewCellStyleSubtitle
    };
    typedef NSInteger UITableViewCellStyle;
    
    


    NS_ENUM 構文を使うと:



    typedef NS_ENUM(NSInteger, UITableViewCellStyle) {
            UITableViewCellStyleDefault,
            UITableViewCellStyleValue1,
            UITableViewCellStyleValue2,
            UITableViewCellStyleSubtitle
    };
    
    


    しかし、ビットマスクを定義する enum を使用すると、以下のようになります:



    enum {
            UIViewAutoresizingNone                 = 0,
            UIViewAutoresizingFlexibleLeftMargin   = 1 << 0,
            UIViewAutoresizingFlexibleWidth        = 1 << 1,
            UIViewAutoresizingFlexibleRightMargin  = 1 << 2,
            UIViewAutoresizingFlexibleTopMargin    = 1 << 3,
            UIViewAutoresizingFlexibleHeight       = 1 << 4,
            UIViewAutoresizingFlexibleBottomMargin = 1 << 5
    };
    typedef NSUInteger UIViewAutoresizing;
    
    


    NS_OPTIONS マクロを使用すると:



    typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
            UIViewAutoresizingNone                 = 0,
            UIViewAutoresizingFlexibleLeftMargin   = 1 << 0,
            UIViewAutoresizingFlexibleWidth        = 1 << 1,
            UIViewAutoresizingFlexibleRightMargin  = 1 << 2,
            UIViewAutoresizingFlexibleTopMargin    = 1 << 3,
            UIViewAutoresizingFlexibleHeight       = 1 << 4,
            UIViewAutoresizingFlexibleBottomMargin = 1 << 5
    };
    
    


    代わりに、自動的にあなたのコードにこの変更を行うための Xcode の現代的な Objective-C のコンバータを使用できます。詳細については、Xcode を使用してコードをリファクタリング を参照してください。


    オブジェクトの初期化


    Objective-C では、オブジェクトの初期化は 指定イニシャライザ と、そのスーパークラスのイニシャライザの1つを呼び出し、その後、独自のインスタンス変数を初期化する責任がある初期化メソッドの概念に基づいています。指定イニシャライザでないイニシャライザは、コンビニエンスイニシャライザ として知られています。コンビニエンスイニシャライザは、一般的に別のイニシャライザ - 初期化をそれ自身で実行するのではなく、最終的には指定イニシャライザで連鎖を終了してデリゲートします。


    指定イニシャライザパターンは、継承されたイニシャライザが適切にすべてのインスタンス変数を初期化することを保証します。重大な初期化を実行する必要があるサブクラスは、そのスーパークラスの指定イニシャライザのすべてをオーバーライドする必要がありますが、コンビニエンスイニシャライザをオーバーライドする必要はありません。イニシャライザの詳細については、オブジェクトの初期化 を参照してください。


    指定されたものと、指定イニシャライザの区別を明確にするために、それが指定イニシャライザである事を表すため、init ファミリー内の全てのメソッドに NS_DESIGNATED_INITIALIZER マクロを追加できます。このマクロを使用すると、いくつかの点が制限されます。


    これらの制限のいずれかに違反している場合は、コンパイラから警告を受けます。


    クラス内で NS_DESIGNATED_INITIALIZER マクロを使用する場合は、このマクロを使用して全ての指定イニシャライザをマークする必要があります。他のすべてのイニシャライザは、コンビニエンスイニシャライザとみなされます。


    どのように採用するか


    クラス内の指定イニシャライザを特定し、NS_DESIGNATED_INITIALIZER マクロでそれらをタグ付けします。例えば:



    - (instancetype)init NS_DESIGNATED_INITIALIZER;
    
    


    自動参照カウント (ARC)


    自動参照カウント (ARC) は、Objective-C のオブジェクトの自動メモリ管理を提供するコンパイラの機能です。retain,release そして autorelease を使う時期を覚える必要がある代わりに、ARC は、オブジェクトの有効期間の要件を評価し、自動的にコンパイル時にあなたのために適切なメモリ管理の呼び出しを挿入します。コンパイラはまた、適切な dealloc メソッドも生成します。


    どのように採用するか


    Xcode は ARC 変換の機械的な部分を自動化するツールを提供し、(retainrelease 呼び出しを削除するなど) 移行機が自動的に処理できない問題を修正するのを補助します。ARC 移行ツールを使用するには、 Edit > Refactor > Convert to Objective-C ARC を選択します。移行ツールは、ARC を使用する、プロジェクト内のすべてのファイルを変換します。


    詳細については、ARC への移行の公開ノート を参照してください。


    Xcode を使用してコードをリファクタリング


    Xcode は現代化プロセスで支援することができるように現代の Objective-C コンバータを提供しています。コンバータは、識別し、潜在的な近代化を適用するメカニズムに役立ちますが、それはコードの意味を解釈しません。例えば、それはあなたの -toggle メソッドが、オブジェクトの状態に影響を与える行動であることを検出しませんし、それは誤ってこのアクションを現代化してプロパティにすることを提案するかもしれません。手動で確認し、コンバータが、コードに提供するすべての変更を確認してください。


    前述の現代化の中で、コンバータは以下のことを提供します:


    これらの現代化に加えて、このコンバータは、以下に挙げたコードへの追加の変更をお勧めします。



    現代の Objective-C のコンバータを使用するには、Edit > Refactor > Convert to Modern Objective-C Syntax を選択します。






    目次
    Xcode 9 の新機能

  • 最新の Objective-C を採用
  • instancetype
    どのように採用するか
    プロパティ
    どのように採用するか
    列挙型マクロ
    どのように採用するか
    ブジェクトの初期化
    どのように採用するか
    自動参照カウント (ARC)
    Xcode を使用してコードをリファクタリング
    文書改訂履歴












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ