はじめに
初めて、Objective-Cのコードを見たとき、呪文のようにしか見えずとても混乱しました。
C#(C++は少し)の経験はありSwiftの開発は比較的楽に出来たのですが、Objective-Cは難しく思えました。
iOSアプリのプロダクトでObjective-C実装されたものをコードリーディングするにあたり必要最低限のもの・理解すべきことを記載します。今回は、XCodeのコンソールアプリでテキスト(文字列)を扱うクラスを作成して簡単な例を紹介していきます。
今回の記事で、Objective-Cが少し特殊なだけであることを理解し開発の助力になればと思います。
(参考サイトがとてもわかりやすかったです。一部古い情報もありますがとても参考になる部分が多かったのでみて見てください。)
対象読者
- Objective-C 初心者の方!
- Objectiv-C に困惑している方!
Objective-C がなぜ呪文に感じるのか
オブジェクト指向における文法の考えた方は、Java/C++ 流が一般的です。しかしObjective-Cは、SmallTalkという言語の考え方をC言語に持ち込んで実装されています。イメージとしては、「C言語+SmallTalk = Objective-C」なります。なので、C言語やSmallTalkを学習していない私のような場合は、呪文のように感じて「一体全体どんな実装がされているんだ?」困惑してしまうのかもしれません。
簡単な例を作成しながら慣れていければと思います。
手順
今回は、XCodeのコンソールアプリでテキスト(文字列)を扱うクラスを作成して簡単な例を紹介していきます。
ステップ1 プロダクト Command Line Tool を作成
Create New Project < macOS < Command Line Tool を選択します。ProductNameを適当に入力、Language を Objective-Cを選択します。そして任意のフォルダにプロダクトを作成しましょう。
ステップ2 Main.m ファイルを確認
プロダクトを作成すると Main.mファイル がデフォルトで作成されています。
このファイルについて確認していきます。
.m 拡張子ファイル
.m が Objective-Cのソースコードファイルを示す拡張子です。
ちなみに、C言語のソースコードを表す拡張子は .c です。
Main.m の実装内容
このプロダクトにおいては、C言語と同様にプログラムを起動すると最初にMain関数が実行されます。
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
NSLog(@"Hello, World!");
}
return 0;
}
#import Foundation
Objective-Cでは、基本的な機能はすべて「Foundation」というフレームワークとして用意されています。#import ヘッダーファイル名
とすることで、その機能をこのクラス内で使用できます。
autoreleasepool
これは「オートリリースプール」と呼ばれる、オブジェクト管理のための仕組みを利用するための文です。
テキスト
Objective-C においては、テキストもオブジェクトとして扱います。
そのため、@"Hello, World!"
のように@
してObjective-C のテキストであると明確にする必要があります。そして、テキストをログ出力するNSLog
メソッド利用しています。
実行してみる
ウインドウ左上にある「Run」ボタンを押して、プログラムを実行してみましょう!
ログ出力で「Hello, World!」
が確認できると思います!
ステップ3 テキストを扱うクラスを作成
実際にログを扱うクラスを作成して、そのクラスをMain.mでインスタンス化して使用してみたいと思います。
.hファイル と .m ファイル
Objective-Cではクラスを作成する時、ヘッダー情報となる部分を、実際に実行する処理の記述をとを分けて実装することができるようになっています。(クラス定義するのが .h、定義したものを実装するのが .m ファイル)
ファイル作成
NewFile < Cocoa Class
を選択します。ここでは、Classを「MyMessage」、Subclass ofは「NSObject」、Language「Objective-C」
で作成します。すると、.hファイルと .mファイルの両方が作成されます。
MyMessage.h を定義する
まず、.hファイルにクラスを定義します。
#import <Foundation/Foundation.h>
@interface MyMessage : NSObject {
// ここに保管する変数などを記述
NSString* value;
}
// ここに用意する処理を記述
-(NSString*)get;
-(void)set:(NSString*)str;
-(void)print;
@end
ヘッダー部分には@interface
というもの後にクラス名
を記述されています。そして、: NSObject
というものが記述されています。これはNSObject
というものを実装クラスが継承していることを示しています。(クラスの作成時に、SubclassをNSObjectを指定したため。)
そして@interface
から始まり、@end
までの間に使用する変数と処理(関数・メソッド)を記述していきます。
ここまでの実装では、インスタンス変数 value
とインスタンスメソッドget・set・print
を定義しました。
- インスタンス変数
- value : テキストの内容
- インスタンスメソッド
- get: インスタンス変数valueのテキストを取得
- set: インスタンス変数valueにテキストを設定
- print: インスタンス変数messageを出力
(インスタンスというワードには後ほど触れていきます)
変数のタイプと変数名を宣言したので、次に .mファイルに実装します。
#import "MyMessage.h"
@implementation MyMessage {
// インスタンス変数 value の値を取得
-(NSString*) get {
return value;
}
// インスタンス変数 value の値を設定
-(void)set:(NSString*)str {
value = str;
}
// インスタンス変数 value の値をログ出力するインスタンスメソッド
-(void)print {
NSLog(@"%@", value);
}
}
@end
Main.mファイルに実装したクラスのmain関数内でインスタンス化して利用します。
#import "MyMessage.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
MyMsessage message = [MyMessage alloc];
message = [message init];
// または
// MyMessage message = [[MyMessage alloc]init];
// MyMessage message = [MyMessage new];
NSLog(@"%@", [message get]);
[message set:@"Hello New World"];
[message print]
}
return 0;
}
インスタンスについて
実装したクラスを別のクラスで扱いたい場合、「インスタンス」というものを作成します。
例ではMyMessage meesage
というMyMessageクラスのインスタンスを作成しています。ここで、自身のインスタン変数value
の値を変更しています。このvalue
の値はmessage
インスタンスの固有の値です。
(なので、MyMessage secoondMessage
をという別のインスタンス作成して、そのvalue
を変更したとしても、messageのvalueの値
は変わりません)
クラスのインスタンスの作成
Objectiv-Cでは、クラスのデータをコピーしたものをアドレスに割り当てるために [クラス名 alloc]
メソッドを実行します。そして、初期化するために[クラス名 init]
を実行する必要があります。
NSObject
alloc・initメソッドはNSObjectを継承しているため実行出来ています。
Objective-Cにおけるルートクラスです。
変数のインスタンスの定義
Object-Cにおいては、テキストを扱うとき NSString クラスを利用します。
テキストの変数定義はNSString*
と記載しました。
NSStitngのような参照型クラスの変数を定義する時は*(ポインタ)
を利用します。
値型である int などでは必要ありません。
*(ポインタ)の有無の一部例
// クラスのインスタンス (参照型)
NSString *text;
NSArray *array;
UIView *view;
NSObject *object;
// (値型)
int number;
CGRect frame;
メソッドの定義
Objective-Cにおけるメソッドの定義は、引数が2つ以上になると書き方が少し見慣れない形式になります。
-( 返値 ) キーワード;
-( 返値 ) キーワード:( タイプ ) 引数;
-( 返値 ) キーワード:( タイプ ) 引数 キーワード;
-( 返値 ) キーワード:( タイプ ) 引数 キーワード:( タイプ ) 引数;
インスタンスメソッド
メソッドの定義の最初の箇所に-
というものがあります。これはメソッドがインスタンスメソッドであることを表す記号になります。メソッドには、「インスタンスで利用するためのもの」と「クラスから直接利用できるもの」ものがあります。
インスタンスメソッドの呼び出し方法に関して (メッセージ式)
[インスタンス変数 メソッド名:引数の値]
が基本の形です。
レシーバー
である インスタンス変数に対して、セレクタ
であるメソッドに引数の値であるメッセージ
というものつけてを使用します。
- NSLogメソッドに関して
今回のprint
メソッドではNSLogを利用しています。第一引数に出力したいテキストを用意し、第2引数以降の値をそれに埋め込んで出力する働きを持ちます。ここでは「%@」という記号がテキストに書かれていますが、これは第二引数にある「インスタンス」を埋め込むためのものです。
まとめ
-
Objective-Cの特徴
- C言語にSmallTalkの考え方を組み込んだ言語
- NSObjectを継承することで基本的な機能が使える
- 文字列には@マークが必要
-
クラスの基本
- .hファイルでインターフェース定義
- .mファイルで実装
- メソッドは[-]でインスタンスメソッドを示す
-
インスタンス作成のポイント
- [クラス名 alloc]でメモリ確保
- [インスタンス init]で初期化
- 参照型(クラス)には*(ポインタ)が必要
これらの基本を理解することで、Objective-Cのコードリーディングが大分楽になると思います。
次の記事では、Ojective-Cにおけるクラスメソッドなどについて触れていければと思います!
項目
[次の項目入門2 クラスについて更に理解を深める 準備中]