Objective-C で、読み取り専用になるメンバを用意したい
データを管理していて、外部からは変更不可能なメンバ変数(プロパティ)を用意したいと思ったことがあると思います。
通常は、データを内部に隠蔽して、getterを通して外部に公開するというアプローチをとりますね。
Objective-Cではどのようにして行うのか、調べました。
想定読者
- オブジェクト指向については知識がある
- C#, C++, JavaScript のいずれかで、読み取り専用のメンバを持つオブジェクトを作ったことがある
- Objective-C を始めてから日が浅い
例えば、書籍を表現するクラスがあったとします。
そこら辺に置いておいた本のタイトルなどはコロコロ変わってもらっては困るので、本が作られたときのタイトルから変化しない物とします。
すると、タイトルなどは読み取り専用である必要があります。
C#では
C#でしたら、以下のように実装します。
getter
構文を使うと綺麗に実装できます。
class Book { // 内部に隠しておくための変数 private String _title; private String _author; public String Title { get { return this._title; } } public String Author { get { return this._author; } } // コンストラクタでデータをセット public Book(String title, String author) { this._title = title; this._author = author; } }
このように定義する事で、外部からは Book.Title
と Book.Author
は読み取り専用になります。
Book aBook = new Book("アジャイルサムライ", "Jonathan Rasmusson"); // 読み取りは可能 String title = aBook.Title; // 書き込みは不可能(コンパイルエラーになる) aBook.Title = "アート・オブ・プロジェクトマネジメント";
Objective-Cでは
.h ファイルと .m ファイルにファイルを分けて実現します。
まずは、外部に公開する定義ファイル Book.h
。
@interface Book // .hファイルの方では、属性に readonly を付ける @property (strong, readonly) NSString *title; @property (strong, readonly) NSString *author; // イニシャライザもついでに公開しておく -(instancetype) initWithTitle: (NSString *)title author: (NSString *)author; @end
次は実装ファイル Book.m
。
// ()が必要 @interface Book () // .mファイルの方では、属性に readwrite を付ける @property (strong, readwrite) NSString *title; @property (strong, readwrite) NSString *author; @end @implementation Book -(instancetype) initWithTitle: (NSString *)title author: (NSString *)author { self = [[super alloc] init]; if(self != nil) { self.title = title; self.author = author; } return self; } @end
これで外部からは読み取り専用のメンバを作ることができました。
この Book
クラスを使用するコードでは Book.h
をimportして使います。
Book *aBook = [[Book alloc] initWithTitle:@"アジャイルサムライ" author:@"Jonathan Rasmusson"]; // 読み取りは可能 NSString *title = aBook.title; // 書き込みは出来ない aBook.title = @"アート・オブ・プロジェクトマネジメント";