objective-cの基礎を学ぶ
基本部分はこちら
こちらも参考になりますこちらも
ログをとるときはNSLog
ポインタ型、ポインタ変数
for ループ使うときはenumerateObjectsUsingBlock
がおすすめ?
NSSStringとString型の違い
.hファイル => ヘッダーファイル
.mファイル => メインファイル、メソッドファイル
ios フレームワークとバンドルの違い
具体的なこと
ヘッダーファイルと実装ファイル
objective-c以下の2つのファイルで構成される。(c++と同じ構成)
- ヘッダーファイル(.h)
- 実装ファイル(.m)
クラスの宣言(.h)
- Objective-Cで作成されるクラスは全て
NSObject
のサブクラスになる。(NSObject
がルートクラス)。NSString
やNSArray
も - Objective-Cでは親クラスを省略して記述できない
@interface クラス名 : 親クラス名
@end
例: Sample.h
@interface Sample : NSObject
@end
インポート
NSObject
はFoundation.framework
というフレームワーク部分で定義されている。
=> NSObject
はFoundation.framework
のインポートが必要となる
#import <Foundation/Foundation.h>
...
クラスの実装(.m)
クラスの定義やメソッドの実装は.mファイルで行う。
クラスの実装は以下のようになる
@implementation クラス名
@end
実装ファイルには、クラスを宣言したヘッダーファイルをインポートする必要がある。
例: Sample.m
#import "Sample.h"
@implementation Sample
@end
プロパティ
#import <Foundation/Foundation.h>
@interface Person : NSObject
{
// 名前
NSString *_name;
// 年齢
NSInteger _age;
}
// 名前を取得する
- (NSString *)name;
// 名前を設定する
- (void)setName:(NSString *)name;
// 年齢を取得する
- (NSInteger)age;
// 年齢を設定する
- (void)setAge:(NSInteger)age;
@end
#import "Person.h"
@implementation Person
// 名前を取得する
- (NSString *)name
{
return _name;
}
// 名前を設定する
- (void)setName:(NSString *)name
{
_name = name;
}
// 年齢を取得する
- (NSInteger)age
{
return _age;
}
// 年齢を設定する
- (void)setAge:(NSInteger)age
{
_age = age;
}
@end
ゲッター、セッター、アクセサー(メソッド)
このとき、インスタンス変数から値を取り出して返すメソッドを「ゲッター(Getter)」、インスタンス変数に値を代入するメソッドを「セッター(Setter)」と言います。そして、これらのメソッドをまとめて「アクセサー(メソッド)」とも呼びます。
-
(NSString *)name
メソッドは_name
のゲッター -
(void)setName:(NSString *)name
は_name
のセッター
@propertyでインスタンス変数とアクセサーの自動生成
見出しの通りobjective-cでは@property
を使用することで、インスタンス変数とアクセサーの自動生成ができる。
使い方
文末にセミコロンが必要
@property (オプション) 型 プロパティ名;
Person.h
、Person.m
を@property
を使って書き換え
#import <Foundation/Foundation.h>
@interface Person : NSObject
// 名前
@property (nonatomic) NSString *name;
// 年齢
@property (nonatomic) NSInteger age;
@end
#import "Person.h"
@implementation Person
@end
実装ファイルがかなりスッキリ。
- インスタンス変数は名前に
_
が付与されたものが自動生成される。(_name
と_age
) - ゲッターメソッドは、メソッド名にそのままプロパティ名が入る。(
- (NSString *)name
、- (NSInteger)age
) - セッターメソッドは、プロパティ名の頭にsetが付与され、プロパティ名の頭文字が大文字になる。(
- (void)setName:
、- (void)setAge:
)
プロパティへのアクセス
#import "ViewController.h"
#import "Person.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Personクラスのインスタンスを生成する
Person *aPerson = [Person new];
// nameに値を設定する
aPerson.name = @"山田太郎";
// nameから値を取得する
NSString *aName = aPerson.name;
NSLog(@"aName : %@", aName);
}
@end
アクセサーを自分で定義する場合
ゲッターNSString *)name
をカスタマイズする場合は以下のような感じになる。
_name
は自動生成されている。
#import "Person.h"
@implementation Person
- (NSString *)name
{
return [NSString stringWithFormat:@"%@ 様", _name];
}
@end
@propertyのオプション
引用
所有属性については、NSStringやNSArrayなどの既存のクラス、または独自に定義したクラスなどのオブジェクト型の場合はstrongが、それ以外の型の場合はassignがデフォルトで設定されるため、省略できます。
それ以外のオプションについては、スレッドセーフに関するオプションを省略した場合はatomicが、アクセス制御に関するオプションを省略した場合は、readwriteがデフォルトで設定されます。
以下2つは同じ
#import <Foundation/Foundation.h>
@interface Person : NSObject
// 名前
@property (nonatomic) NSString *name;
// 年齢
@property (nonatomic) NSInteger age;
@end
#import <Foundation/Foundation.h>
@interface Person : NSObject
// 名前
@property (strong, nonatomic, readwrite) NSString *name;
// 年齢
@property (assign, nonatomic, readwrite) NSInteger age;
@end
明示的にnonatomicを指定しているのは、atomicを指定してもパフォーマンスを悪化させるだけで、ほとんどの場合にメリットが無いためです。ですので、よほどのことが無い限りはnonatomicを指定しておきましょう。
メソッド
メソッドの定義
- (戻り値の型)メソッド名
{
// メソッドの実装
}
値を返す(return)
- (NSString *)name
メソッドは、「NSString
型の値を返すname
という名前のメソッド」
// 名前を取得する
- (NSString *)name
{
return _name;
}
戻り値はない場合はvoid
setName
メソッドは戻り値がないのでvoid
を指定
// 名前を設定する
- (void)setName:(NSString *)name
{
_name = name;
}
メソッドの引数とラベル
また、「- (void)setName:」メソッドでは、メソッド名の後に「コロン(:)」があります。これは、引数といって、メソッドに値を渡す必要がある場合に使用します。
引数が複数ある場合
ラベルは省略可能。
// 引数が3つの場合
- (戻り値の型)メソッド名:(引数の型)引数1 ラベル:(引数の型)引数2 ラベル:(引数の型)引数3
例
第一引数のラベルは省略されている。
- (BOOL)writeToFile:(NSString *)path atomically:(BOOL)useAuxiliaryFile encoding:(NSStringEncoding)enc error:(NSError **)error;
使う場合
NSString *str = @"文字列";
NSError *error = nil;
[str writeToFile:@"write/to/path"
atomically:YES
encoding:NSUTF8StringEncoding
error:&error];
プロパティとメソッドのスコープ
Objective-Cでは、他のクラスからプロパティへのアクセスやメソッドの呼び出しを行えるようにするために、それらの宣言をヘッダーファイルに記載します。
name
, age
プロパティとdisplayName
,displayAge
,displayProfile
の3つのメソッドは他のクラスから参照可能。
=> ヘッダーファイルに宣言されたプロパティやメソッドは他のクラスから参照可能(Public)になる。
#import <Foundation/Foundation.h>
@interface Person : NSObject
// 名前
@property (nonatomic) NSString *name;
// 年齢
@property (nonatomic) NSInteger age;
// 名前をログに出力する
- (void)displayName;
// 年齢をログに出力する
- (void)displayAge;
// 名前と年齢をログに出力する
- (void)displayProfile;
@end
プライペートなプロパティやメソッドの実装
実装ファイル側で宣言を行えばプライベートになる。
#import <Foundation/Foundation.h>
@interface Person : NSObject
// 名前
@property (nonatomic) NSString *name;
// 名前と年齢をログに出力する
- (void)displayProfile;
@end
#import <Foundation/Foundation.h>
@interface Person ()
// 年齢
@property (nonatomic) NSInteger age;
// 名前をログに出力する
- (void)displayName;
// 年齢をログに出力する
- (void)displayAge;
@end
@implementation Person
……
@end
こうすることで、「age」プロパティと「- displayName」メソッド、「- displayAge」メソッドは他のクラスから参照できなくなります。
クラスエクステンション
上の例の実装(.m)ファイルに書かれている@interface Person () …… @end
はクラスエクステンションと呼ばれる機能。
文字通りクラスを拡張する機能です。この機能を利用して疑似的にプライベートにすることが可能です。
なお、「@implementation …… @end」で実装されているメソッドに関しては、クラスエクステンション部分に宣言しなくてもヘッダーに記述しなければ、プライベート扱いになります。
selfとsuper
メソッド内で、自分自身のインスタンス変数やメソッドにアクセスするには、selfを使用します。JavaやC#でいうところの「this」のようなものです
- (void)displayProfile
{
NSLog(@"私の名前は%@です。年齢は%d歳です。", self.name, self.age);
}
また、親クラスのインスンタンス変数やメソッドにアクセスするときは、superを使用します。これは、Javaでは同じく「super」、C#でいうところの「base」のようなものです。
参考
メソッドの呼び出し方法2
メッセージ([]カッコで囲むアレ)でメソッドを呼び出すことも可能
=> @propertyを使った方がわかりやすそうなので、使わない方針でいきます
Dog *dog_A = [[Dog alloc] init];
[dog_A setHeight:100];
インスタンス生成方法について
// Before
UILabel *label = [[[UILabel] alloc] init];
// After
UILabel *label = [UILabel new];
UILabel *label = UILabel.new;
いずれも同じ意味です。newはalloc+init呼び出しの短縮メソッドです。またプロパティー呼び出しを行うことで[UILabel new]記法を回避し、UILabel.newというRuby風の記述を実現しています。
参考記事を読んで色々考えた結果
=> UILabel *label = [[[UILabel] alloc] init];
この形で良いかなと思いました。
参考
allocとinitについて
alloc
変数を生成するにあたってメモリを確保すること。
init
生成した変数にデータを保存できるようにすること。
delegateについて
プロトコル @ protocol
ARCとは
Automatic Reference Countingという名前通り、コンパイル時に(ここ重要)自動で参照をカウントする仕組みで、実行時のパフォーマンスロスが極めて小さい。というものでした。
NSNotificationCenter
ロギング NSLog
jsonのシリアライズ、デシリアライズ
NSDictionary
NSArray 配列の扱い
配列の扱い
型変換
nil、Nil、NULL、NSNullの違い