1. ホーム
  2. iphone

[解決済み] ObjectiveCの変数位置の宣言・定義?

2022-05-18 02:50:43

質問

iOS アプリケーションと objective C に取り組み始めて以来、変数を宣言したり定義したりする場所が異なることに、本当に困惑しています。一方では伝統的な C のアプローチがあり、他方ではその上に OO を追加する新しい ObjectiveC ディレクティブがあります。ベストプラクティスと、変数にこれらの場所を使用したい状況について理解するのを助けてくれませんか?

ここにサンプルクラス(.hと.m)があります。

#import <Foundation/Foundation.h>

// 1) What do I declare here?

@interface SampleClass : NSObject
{
    // 2) ivar declarations
    // Pretty much never used?
}

// 3) class-specific method / property declarations

@end

#import "SampleClass.h"

// 4) what goes here?

@interface SampleClass()

// 5) private interface, can define private methods and properties here

@end

@implementation SampleClass
{
    // 6) define ivars
}

// 7) define methods and synthesize properties from both public and private
//    interfaces

@end

  • 私の理解では、1 と 4 は C スタイルのファイルベースの宣言と定義であり、クラスの概念をまったく理解していませんので、C で使用されるのとまったく同じように使用しなければなりません。私が見逃している他の便利な使い方があるのでしょうか?
  • iOS で作業している私の考えでは、ivar は @synthesize ディレクティブの外ではほとんど完全に廃止され、したがって、ほとんど無視することができるようになりました。それは本当ですか?
  • 5 について: なぜプライベート インターフェイスでメソッドを宣言する必要があるのでしょうか。私のプライベートクラスのメソッドは、インターフェイスで宣言しなくてもうまくコンパイルできるようです。それはほとんど読みやすさのためですか?

みなさん、どうもありがとうございます。

どのように解決するのですか?

私はあなたの混乱を理解することができます。特に、Xcode の最近のアップデートと新しい LLVM コンパイラーによって、ivar とプロパティを宣言できる方法が変更されたからです。

"modern" Objective-C (in "old" Obj-C 2.0) 以前には、多くの選択肢がありませんでした。インスタンス変数は中括弧の間のヘッダで宣言されていました。 { } :

// MyClass.h
@interface MyClass : NSObject {
    int myVar;
}
@end

これらの変数にアクセスできるのは、自分の実装の中だけで、他のクラスからはアクセスできないようになっていました。そのためには、以下のようなアクセサメソッドを宣言する必要がありました。

// MyClass.h
@interface MyClass : NSObject {
    int myVar;
}

- (int)myVar;
- (void)setMyVar:(int)newVar;

@end


// MyClass.m
@implementation MyClass

- (int)myVar {
   return myVar;
}

- (void)setMyVar:(int)newVar {
   if (newVar != myVar) {
      myVar = newVar;
   }
}

@end

このようにして、他のクラスからもこのインスタンス変数を取得・設定することができました。メッセージを送る(メソッドを呼び出す)には、通常の角括弧の構文を使用します。

// OtherClass.m
int v = [myClass myVar];  // assuming myClass is an object of type MyClass.
[myClass setMyVar:v+1];

なぜなら、すべてのアクセッサメソッドを手作業で宣言し、実装するのはかなり面倒だったからです。 @property@synthesize が導入され、アクセッサメソッドが自動生成されるようになりました。

// MyClass.h
@interface MyClass : NSObject {
    int myVar;
}
@property (nonatomic) int myVar;
@end

// MyClass.m
@implementation MyClass
@synthesize myVar;
@end

その結果、より明確で短いコードになりました。アクセッサメソッドが実装され、以前と同様にブラケット構文を使用することができます。しかし、それに加えて、プロパティにアクセスするためにドット構文を使うこともできます。

// OtherClass.m
int v = myClass.myVar;   // assuming myClass is an object of type MyClass.
myClass.myVar = v+1;

Xcode 4.4以降では、インスタンス変数を自分で宣言する必要がなくなりました。 @synthesize も省略できます。もしivarを宣言しなければ、コンパイラがあなたのためにそれを追加してくれますし、また、あなたが @synthesize .

自動的に生成されるivarのデフォルトの名前は、アンダースコアで始まる名前またはあなたのプロパティです。生成されたivarの名前を変更するためには @synthesize myVar = iVarName;

// MyClass.h
@interface MyClass : NSObject 
@property (nonatomic) int myVar;
@end

// MyClass.m
@implementation MyClass
@end

これは上のコードと全く同じように動作します。互換性の理由から、あなたはまだヘッダで ivar を宣言することができます。しかし、そうしたい(プロパティを宣言しない)唯一の理由は、プライベート変数を作成することであるため、現在は実装ファイルでもそうすることができ、これが望ましい方法なのです。

An @interface ブロックは、実際には 拡張 であり、メソッドの宣言(もう必要ありません)やプロパティの(再)宣言に使用することができます。例えば readonly プロパティを宣言することができます。

@property (nonatomic, readonly) myReadOnlyVar;

として、実装ファイルの中で再宣言します。 readwrite として再宣言し、ivarへの直接アクセスだけでなく、プロパティ構文を使用して設定できるようにします。

の完全に外側で変数を宣言することについては @interface または @implementation ブロック、そう、これらはプレーンなC変数であり、全く同じように動作します。