Objective-C について開発に最低限必要な知識
3月からiOS 開発してます。
現場では、iOS のソースコードは全面Swift化の方向で進んでいるのですが、まだObjective-C のソースコードが多く残っている状態でして、まぁそういう現場は多いのではないかと思います。
僕としても本腰いれて勉強するつもりはないけど、卒なく一通りのことはできるようにしておきたいみたいな温度感です。
ここではObjective-C を扱う上で最低限の知識をまとめたいと思います。
型について
Objc では型については大きく分けて、値型と参照型の2つがあります。
Objc でいう参照型ってのは要はオブジェクトです。
参照型ってのはコピったときにメモリアドレスがはいる例のアレです。
Objc でいうと参照型であればもれなくオブジェクトだと思います(多分)
なので、メソッドが生えてたりプロパティを保持しています。
値型
※よく使うものに絞ります。
型名 | 意味 | 定義例 |
---|---|---|
int | 数値 | int num = 3; |
double | 小数 | double d = 123.45; |
char | 文字列 | char str = "hoge"; |
BOOL | 真偽値 | BOOL b = YES; |
NSInteger | 数値 intとほぼ同じ(*) |
NSInteger num = 3; |
NSInteger とint との違いはこちら
参照型
※よく使うものに絞ります。
型名 | 意味 | 定義例 |
---|---|---|
NSString | 文字列 | NSString *str = @"Hello"; |
NSMutableString | 変更可能文字列 | 初期値なし : NSMutableString *str = [NSMutableString string]; 初期値あり : NSMutableString *str = [NSMutableString stringWithString:@"Hoge"]; |
NSNumber | 数値 | NSNumber *num = [NSNumber numberWithInt:3]; |
NSArray | 配列 | 最後にnil を入れるの注意 NSArray *array = [[NSArray alloc] initWithObjects:@"hoge", @"fuga", @"piyo", nil]; |
NSMutableArray | 変更可能配列 | 初期値なし : NSMutableArray *array = [[NSMutableArray alloc] init]; 初期値あり : NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:@"aa", nil]; |
NSDictionary | 辞書 | 初期値なし : NSDictionary *dic = [[NSDictionary alloc] init]; 初期値あり : NSArray *vals = [NSArray arrayWithObjects: @"val1", @"val2", nil]; NSArray *keys = [NSArray arrayWithObjects: @"key1", @"key2", nil]; NSDictionary *dic = [NSDictionary dictionaryWithObjects:vals forKeys:keys]; |
型キャスト
NSString => NSInteger
NSString *numStr = @"123"; NSInteger num = [numStr intValue];
NSString => NSNumber
NSString *numStr = @"123"; NSInteger num = [numStr intValue]; NSNumber *numNSNum = [NSNumber numberWithInt:num];
NSInteger => NSString
NSInteger num = 123; NSString *str = [NSString stringWithFormat:@"%d", num];
NSNumber => NSInteger
NSNumber *nsNum = [NSNumber numberWithInt:3]; NSInteger nsInt = [num integerValue];
変数定義
上記の例をみてもらえれば分かるのですが、参照型は定義時にアスタリスク *
をつける必要があります。
char cStr = "hoge"; //値型 NSString *nsStr = @"hoge"; //参照型
ヘッダーファイル、実装ファイル
ObjectiveC ではヘッダーファイル(.h)と 実装ファイル(.m)ってのがあります。
何が違うのかといいますと、ヘッダーファイルってのは実装ファイルのほうで使う変数やメソッドなどを定義します。
それに対して実装ファイルにはメソッドの処理内容などを記述します。
例(具体的なメソッド定義法などは下記参考):
TestLib.h
#ifndef TestLib_h #define TestLib_h @interface TestLib: NSObject; // 書かないとプライベートメソッドになる -(NSString *) sampleMethod; -(void) sampleMethodWithArgs: (NSString *)hoge :(NSString *)fuga; @end #endif /* TestLib_h */
TestLib.m
#import <Foundation/Foundation.h> #import "TestLib.h" @interface TestLib () @end @implementation TestLib - (NSString *)sampleMethod { return @"Hello!"; } - (void) sampleMethodWithArgs: (NSString *)hoge :(NSString *)fuga { } @end
メソッド定義
分かりづらいです。
引数なし
- (NSString *)sampleMethod { return @"Hello!"; }
引数あり(1つ)
- (void) sampleMethodWithArgs: (NSString *)hoge { }
引数あり(2つ)
- (void) sampleMethodWithArgs: (NSString *)hoge :(NSString *)fuga { }
ただ、Objc では第二引数以降はラベルをつけるのが一般的なようです。
参考 : 【Xcode】第二引数以降はラベルをつける【Objective-C】
- (void) sampleMethodWithArgs: (NSString *)hoge fuga:(NSString *)fuga { }
メソッド実行
分かりづらいです。
以下の書式で行います。
引数なし
[obj method];
引数あり(1つ)
[obj method:arg];
引数あり(2つ)
[obj method:arg1 :arg2];
引数あり(2つ、ラベルあり)
[obj method:arg1 labelName:arg2];
デバッグ
基本的には Xcode上で break point を挟んで、po
コマンドでOKです。
ただ、ビルドをするのに時間がかかるので、新しくメソッドを実装するときや複雑なロジックを書くときは僕はpaiza を使います。
アウトプットを作るにはNSLog を使います。
#import <Foundation/Foundation.h> int main(void){ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; // Your code here! NSMutableString *s = @"hoge"; NSLog(@"%@", s); [pool release]; return 0; }
=> 2018-04-14 15:41:33.259 Main[10] hoge
クラスのimport
Xcode 上で試してみます。
Test プロジェクトの下に Library というディレクリを作成し、その下に TestLib.h
, TestLib.m
というファイルを作成しました。
プロジェクトを作成すると生成される main.m
に以下のように書きました。
#import <UIKit/UIKit.h> #import "AppDelegate.h" #import "TestLib.h" int main(int argc, char * argv[]) { @autoreleasepool { id testLibObj; testLibObj = [[TestLib alloc] init]; [testLibObj sampleMethod]; [testLibObj sampleMethodWithArgs:@"hoge" fuga:@"fuga"]; return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } }
まぁこんな感じでimport & 使用できます。
名前空間はないです。
思想的には、名前の前に接頭辞をつければ衝突しないっしょ?っていうスタンスらしいです。
NSHoge みたいに。
文字列操作
文字追加
NSMutableString *str = [NSMutableString string]; [str appendString:@"HogeFuga"]; NSLog(@"%@", str);
=> HogeFuga
置換
NSString *str = @"HogeFuga"; NSString *replacedStr = [str stringByReplacingOccurrencesOfString:@"Hoge" withString:@"Hige"]; NSLog(@"%@", replacedStr);
=> HigeFuga
削除
NSString *str = @"HogeFuga"; NSString *removedStr1 = [str substringToIndex:4]; // 最初から指定されたインデックスの1文字前まで NSString *removedStr2 = [str substringFromIndex:4]; // 指定されたインデックスから最後まで NSString *removedStr3 = [str substringWithRange:NSMakeRange(2, 4)]; // 指定されたインデックスから文字数分 NSLog(@"%@", removedStr1); NSLog(@"%@", removedStr2); NSLog(@"%@", removedStr3);
=> Hoge
=> Fuga
=> geFu
配列操作
取得
NSArray *array = [[NSArray alloc] initWithObjects:@"hoge", @"fuga", @"piyo", nil]; NSLog(@"%@", [array objectAtIndex:0]);
=> hoge
追加
NSMutableArray *array = [[NSMutableArray alloc] init]; [array addObject:@"Piyo"]; NSLog(@"%@", array]);
=> (Piyo)
削除
NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:@"hoge", @"piyo", nil]; [array removeObjectAtIndex:1]; NSLog(@"%@", array]);
=> (hoge)
ソート
NSArray *array = [NSArray arrayWithObjects:[NSNumber numberWithInt:11],[NSNumber numberWithInt:1],[NSNumber numberWithInt:23],[NSNumber numberWithInt:4],[NSNumber numberWithInt:2],nil]; NSMutableArray *sortedArray = [array sortedArrayUsingDescriptors: @[[NSSortDescriptor sortDescriptorWithKey:@"" ascending:YES]]];
=> (1, 2, 4, 11, 23)
※文字列だとうまくいかない
NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:@"2", @"3", @"1", @"7", @"15", nil]; NSMutableArray *sortedArray = [array sortedArrayUsingDescriptors: @[[NSSortDescriptor sortDescriptorWithKey:@"" ascending:YES]]];
=> (1, 15, 2, 3, 7)