第4回 Foundationフレームワーク

iPhoneアプリ開発講習会
第4回
Foundationフレームワーク
Copyright © 2012 Kazumasa Kojima All Rights Reserved.
前回の講義
Objective-C【後編】
• メモリ管理
• アウトレット
• プロトコル
• プロパティ
• セレクター
• 【参考】カテゴリー/エクステンション
2
今回の講義
Foundationフレームワーク
• Cocoa Touchフレームワーク
• Foundationフレームワーク
• 文字列
• コレクション
• 【参考】通知
3
Cocoa Touchフレームワーク
Cocoa Touchフレームワーク
Cocoa Touchフレームワークとは?
• iOSアプリ開発のために提供されているプログラ
ムの部品群
•
•
クラス、関数、型、定数 など
大部分がObjective-Cによって実装
• 多くのフレームワークから構成
•
Foundation、UIKit、Core Animation、Core Data
など
5
Cocoa Touchフレームワーク
Foundationフレームワークとは?
• アプリの基盤となる部品群から構成されている
フレームワーク
•
•
Mac OS X向けのアプリ開発でも利用
•
NSObject、文字列、コレクション、データ、通信の
ためのクラス など
部品の名前は「NS」から始まる
6
Cocoa Touchフレームワーク
UIKitフレームワークとは?
• iOS向けGUIアプリ開発のために提供されている
フレームワーク
•
部品の名前は「UI」から始まる
•
GUI部品(ラベル、ボタンなど)、アプリそのものを
表すクラス など
➡ 詳細は次回以降の講義にて
7
Foundationフレームワーク
Foundationフレームワーク
Immutable(不変) と Mutable(可変) クラス
• インスタンス作成後のデータ変更(追加、編
集、削除)の可否
• 可変なクラスは必要時にサイズが自動で拡大
• 一般的な規則
•
可変なクラスの名前にはMutableが含まれる
•
可変なクラスは不変なクラスのサブクラス
ex. NSString(不変) / NSMutableString(可変)
9
Foundationフレームワーク
• 目的に応じて使い分け
•
Immutableクラス:データの変更がない、データを
変更されると不都合な場合
•
Mutableクラス:データを変更して使用、データを
変更されることが前提の場合
10
Foundationフレームワーク
Foundationフレームワーク利用上の注意点
• NSObject以外のクラスのサブクラス化は可能
だが、一般的にしない
11
文字列
文字列
文字列クラス
• 文字列(String)データを扱うためのクラス
‣ NSString
•
不変な文字列データを扱うクラス
‣ NSMutableString
•
可変な文字列データを扱うクラス
•
NSStringのサブクラス
13
NSString
主なメソッドと使用例
▽ インスタンスの作成と初期化(1/3)
‣ - (id)init
‣ + (id)string
• 空の文字列を作成
• 後者はコンビニエンスコンストラクタ
NSString *string1 = [[NSString alloc] init];
NSString *string2 = [NSString string]; // クラスメソッド
14
NSString
【参考】コンビニエンスコンストラクタ
• 一時的に利用するためだけのオブジェクトを
作成するためのクラスメソッド
• 不変なクラス名の接頭語を除いたものから
メソッドの名前が始まる
ex. NSString
string...
• alloc + init + autoreleaseしたものに相当
➡ 所有が発生しない
15
NSString
▽ インスタンスの作成と初期化(2/3)
‣ - (id)initWithString:(NSString *)aString
‣ + (id)stringWithString:(NSString *)aString
• 文字列から文字列を作成
• aStringへのnilの指定は不可
NSString *string1 = [[NSString alloc] initWithString:@"Name"];
NSString *string2 = [NSString stringWithString:string1];
16
NSString
▽ インスタンスの作成と初期化(3/3)
‣ - (id)initWithFormat:(NSString *)format, ...
‣ + (id)stringWithFormat:(NSString *)format, ...
• printf()関数と同様に書式文字列と対応する変数(また
は定数)を指定して文字列を作成
• formatへのnilの指定は不可
float value1 = 3.0;
float value2 = 2.1;
NSString *string1 = [[NSString alloc] initWithWithFormat:@"Value1:%f
Value2:%f", value1, value2];
17
NSString
▽ 長さ
‣ - (NSUInteger)length
• 文字列に含まれる文字数を返す
NSString *string = [NSString string];
NSUInteger stringLength = [string length];
// 0
NSUInteger constantStringLength = [@"Name" length]; // 4
18
NSString
▽ 検索
‣ - (NSRange)rangeOfString:(NSString *)aString
• 文字列に最初に現れるaStringの範囲を返す
• aStringへのnilの指定は不可
• NSRange:(NSUInteger location, NSUInteger
length)の構造体
• 見つからない場合には(NSNotFound, 0)
NSString *string = @"ABCAAABC";
NSRange range1 = [string rangeOfString:@"ABC"]; // (0, 3)
NSRange range2 = [string rangeOfString:@"D"];
// (NSNotFound, 0)
19
NSString
▽ 比較
‣ - (NSComparisonResult)compare:(NSString *)aString
• ReceiverとaString(nilは不可)の文字列を比較し、辞
書的な前後関係を結果として返す
• NSComparisonResult
• NSOrderedSame (0): Receiver = aString
• NSOrderedAscending (-1): Receiver < aString
• NSOrderedDescending (1): Receiver > aString
[@"A" compare:@"B"]; // NSOrderedAscending
[@"B" compare:@"A"]; // NSOrderedDescending
20
NSString
▽ 結合
‣ - (NSString *)stringByAppendingFormat:(NSString *)format, ...
• 書式文字列を追加し、新しい文字列を返す
• formatへのnilの指定は不可
NSUInteger value = 10;
NSString *appendedString = [@"ABC" stringByAppendingFormat:@":%d
%@", value, @"kg"]; // ABC: 10 kg
21
NSString
▽ 置換
‣
-(NSString*)stringByReplacingOccurrencesOfString:
(NSString *)target withString:(NSString *)replacement
• 文字列中に含まれる全てのtargetをreplacementに
置換
• 置換した文字列を返す
NSString *replacedString = [@"AABBCC"
stringByReplacingOccurrencesOfString:@"A" withString:@"ZZ"];
// ZZZZBBCC
22
NSMutableString
主なメソッドと使用例
▽ インスタンスの作成と初期化
‣ - (id)initWithCapacity:(NSUInteger)capacity
‣ + (id)stringWithCapacity:(NSUInteger)capacity
• capacityで指定した長さの文字列を格納可能なインス
タンスを作成して返す
➡ 実行効率の向上のため
➡ 後から指定した以上の長さになっても問題ない
NSMutableString *mutableString = [NSMutableString stringWithCapacity:3];
23
NSMutableString
▽ 結合
‣ - (void)appendFormat:(NSString *)format, ...
• 書式文字列を既存の文字列に追加する
• formatへのnilの指定は不可
➡ NSStringのstringByAppendingFormat:メソッド
とは異なり、Receiverのデータ自体が更新される
NSMutableString *mutableString = [[NSMutableString alloc]
initWithString:@"AAA"];
[mutableString appendString:@": %d", 10]; // AAA: 10
24
NSMutableString
▽ 置換
‣ - (void)setString:(NSString *)aString
• Receiverの文字列をaStringに置換
• aStringへのnilの指定は不可
NSMutableString *mutableString = [NSMutableString stringWithCapacity:3];
[mutableString setString:@"AAA"]; // AAA
[mutableString setString:@"BBBBB"]; // BBBBB
25
コレクション
コレクション
コレクションとは?
• オブジェクトの集まりを格納するクラス
➡ オブジェクト以外の格納は不可(nilも不可)
➡ 格納されたオブジェクトはコレクションが所有
➡ コレクションの解放時にオブジェクトはコレクション
によって所有を放棄される
• 主なクラス
• 配列
• 辞書
• 集合 ※講義では扱わない
27
配列
配列とは?
• オブジェクトを順番に格納するコレクション
• 格納場所はインデックスで指定
‣ NSArray
•
不変な配列を扱うクラス
‣ NSMutableArray
•
•
可変な配列を扱うクラス
NSArrayのサブクラス
28
NSArray
主なメソッドと使用例
▽ インスタンスの作成と初期化(1/2)
‣ - (id)initWithObjects:(id)firstObj, ...
‣ + (id)arrayWithObjects:(id)firstObj, ...
• 引数で指定した可変個のオブジェクトを格納した配列
を作成して返す
• 引数はコンマで区切り、最後に必ずnilを指定
➡ nilは最後尾を表す目印で配列には格納されない
29
NSArray
▽ インスタンスの作成と初期化(2/2)
NSString *string1 = [[NSString alloc] initWithString:@"X"];
NSString *string2 = @"Y";
NSObject *object = [[NSObject alloc] init];
NSArray *array = [[NSArray alloc] initWithObjects:string1, string2, object, nil];
// 配列によって所有されたので所有を放棄してもいい
[string1 release];
[object release];
30
NSArray
▽ サイズ
‣ - (NSUInteger)count
• 配列に格納されているオブジェクトの個数を返す
NSArray *array = [NSArray arrayWithObjects:@"A", @"B", nil];
NSUInteger count = [array count]; // 2
31
NSArray
▽ オブジェクトの取得
‣ - (id)objectAtIndex:(NSUInteger)index
• indexに格納されたオブジェクトを取得
• 最後尾のインデックスを超えた値の指定は不可
NSArray *array = [NSArray arrayWithObjects:@"A", @"B", @"C", nil];
id object = [array objectAtIndex:0]; // A
object = [array objectAtIndex:2];
// C
object = [array objectAtIndex:3];
// エラー
32
NSArray
▽ ソート
‣ - (NSArray *)sortedArrayUsingSelector:(SEL)comparator
• 配列内のオブジェクトをcomparatorで昇順にソート
して返す
• comparatorには、2つのオブジェクトを比較し、
NSComparisonResultを返すメソッドのセレクター
を指定
NSArray *array = [NSArray arrayWithObjects:@"B", @"A", @"C", nil];
NSArray *sortedArray = [array
sortedArrayUsingSelector:@selector(compare:)]; // A, B, C
33
NSMutableArray
主なメソッドと使用例
▽ インスタンスの作成と初期化(1/2)
‣ - (id)init;
‣ + (id)array;
• 空の配列を作成して返す
NSMutableArray *mutableArray1 = [[NSMutableArray alloc] init];
NSMutableArray *mutableArray2 = [NSMutableArray array];
34
NSMutableArray
▽ インスタンスの作成と初期化(2/2)
‣ - (id)initWithCapacity:(NSUInteger)numItems
‣ + (id)arrayWithCapacity:(NSUInteger)numItems
• numItemsで指定した個数のオブジェクトを格納する
のに十分なメモリを割り当てた配列を作成して返す
➡ 後からこのサイズを超えても問題ない
NSMutableArray *mArray = [NSMutableArray arrayWithCapacity:3];
35
NSMutableArray
▽ オブジェクトの追加
‣ - (void)addObject:(id)anObject
• anObjectを配列の末尾に追加する
• anObjectへのnilの指定は不可
NSMutableArray *mArray = [NSMutableArray arrayWithCapacity:3];
[mArray addObject:@"A"]; // A
[mArray addObject:@"B"]; // A, B
[mArray addObject:@"C"]; // A, B, C
36
NSMutableArray
▽ オブジェクトの削除
‣ - (void)removeObjectAtIndex:(NSUInteger)index
• indexに格納されているオブジェクトを削除
• 最後尾のインデックスを超えた値の指定は不可
‣ - (void)removeAllObjects
• 配列内の全てのオブジェクトを削除
NSMutableArray *mArray = [[NSMutableArray alloc]
initWithObject:@"A", @"B", @"C", @"D", nil];
[mArray removeObjectAtIndex:1]; // A, C, D
[mArray removeObjectAtIndex:1]; // A, D
[mArray removeAllObjects];
// [Empty]
37
NSMutableArray
▽ ソート
‣ - (void)sortUsingSelector:(SEL)comparator
• 配列内のオブジェクトをcomparatorで昇順にソート
• NSArrayのsortedArrayUsingSelector:とは異な
り、Receiverの配列自体が更新される
NSMutableArray *mArray = [NSMutableArray arrayWithObjects:@"B",
@"A", @"C", nil];
[mArray sortUsingSelector:@selector(compare:)]; // A, B, C
38
辞書
辞書とは?(1/3)
• キーとそれに対応する値のペア(エントリー)を格
納するコレクション
➡ キーも値もオブジェクト (nilは不可)
• キーを用いて値を指定
39
辞書
辞書とは?(2/3)
• キーに関する注意点
•
NSCopyingプロトコルへの準拠が必須
➡ 文字列(NSString)を利用するのが一般的
•
辞書内に同一のキーは存在できない
➡ 同一性はNSObjectのisEqual:メソッドで判定
40
辞書
辞書とは?(3/3)
‣ NSDictionary
•
不変な辞書を扱うクラス
‣ NSMutableDictionary
•
•
可変な辞書を扱うクラス
NSDictionaryのサブクラス
41
NSDictionary
主なメソッドと使用例
▽ インスタンスの作成と初期化
‣ - (id)initWithObjectsAndKeys:(id)firstObject , ...
‣ + (id)dictionaryWithObjectsAndKeys:(id)firstObject , ...
• 引数で指定した可変個のエントリー(値、キーの順で
指定)を格納した辞書を作成して返す
• 引数はコンマで区切り、最後に必ずnilを指定
NSDictionary *dictionary = [[NSDictionary alloc]
initWithObjectsAndKeys:@"value1", @"key1", @"value2", @"key2", nil];
42
NSDictionary
▽ サイズ
‣ - (NSUInteger)count
• 辞書内のエントリーの個数を返す
NSDictionary *dictionary = [[NSDictionary alloc]
initWithObjectsAndKeys:@"value1", @"key1", @"value2", @"key2", nil];
NSUInteger count = [dictionary count]; // 2
43
NSDictionary
▽ オブジェクトの取得
‣ - (id)objectForKey:(id)aKey
• aKeyで指定したキーに対応する値を返す
• 対応する値がない場合にはnil
NSDictionary *dictionary = [[NSDictionary alloc]
initWithObjectsAndKeys:@"value1", @"key1", @"value2", @"key2", nil];
id object = [dictionary objectForKey:@"key1"];
// value1
object = [dictionary objectForKey:@"key3"];
// nil
44
NSMutableDictionary
主なメソッドと使用例
▽ インスタンスの作成と初期化(1/2)
‣ - (id)init;
‣ + (id)dictionary;
• 空の辞書を作成して返す
NSMutableDictionary *mDict = [NSMutableDictionary dictionary];
45
NSMutableDictionary
主なメソッドと使用例
▽ インスタンスの作成と初期化(2/2)
‣ - (id)initWithCapacity:(NSUInteger)numItems
‣ + (id)dictionaryWithCapacity:(NSUInteger)numItems
• numItemsで指定した個数のエントリーを格納するのに
十分なメモリを割り当てた辞書を作成して返す
➡ 後からこのサイズを超えても問題ない
NSMutableDictionary *mDict = [NSMutableDictionary
dictionaryWithCapacity:3];
46
NSMutableDictionary
▽ エントリーの追加
‣ - (void)setObject:(id)anObject forKey:(id)aKey
• 辞書にanObject, aKeyで指定したエントリーを追加
• nilの指定は不可
• 辞書内に既に存在するaKeyを指定した場合には、
対応する値を削除し、anObjectを追加
NSMutableDictionary *mDict = [NSMutableDictionary dictionary];
[mDict setObject:@"value1" forKey:@"key"];
[mDict setObject:@"value2" forKey:@"key"]; // value1はvalue2に置換
47
NSMutableDictionary
▽ エントリーの削除
‣ - (void)removeObjectForKey:(id)aKey
• aKeyで指定したキーに対応するエントリーを削除
• 対応するエントリーがない場合には何もしない
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc]
initWithObjectsAndKeys:@"value1", @"key1", @"value2", @"key2", nil];
[dictionary removeObjectForKey:@"key1"];
[dictionary removeObjectForKey:@"key3"]; // 何もしない
48
その他
コレクションに関連する仕組みとクラス
• for in 構文
• NSNull
• ラッパークラス
49
for in 構文
for in 構文とは?
• コレクション内のオブジェクトを高速に列挙
➡ 列挙:1つづつ取り出す
• NSFastEnumerationプロトコルに準拠した
クラスで使用可能
‣ NSArray
• 配列内のオブジェクトを先頭から順に列挙
‣ NSDictionary
• 辞書に格納されたキーを列挙(順序は不定)
50
for in 構文
書式
// オブジェクト型の変数を内部で宣言する場合
for(オブジェクト型 変数 in コレクション) {
// 変数を使用する文...
}
// オブジェクト型の変数を外部で宣言する場合
オブジェクト型 変数;
for(変数 in コレクション) {
// 変数を使用する文...
}
51
for in 構文
使用例
// NSArray
NSArray *array = [NSArray arrayWithObjects:@"A", @"B", @"C", nil];
for(NSString *string in array) {
NSLog(@"%@", string);
}
// NSDictionary
NSDictionary *dictionary = [[NSDictionary alloc]
initWithObjectsAndKeys:@"value1", @"key1", @"value2", @"key2", nil];
NSString *key;
for(key in dictionary) {
NSString *value = [dictionary objectForKey:key];
NSLog(@"%@", value);
}
52
NSNull
NSNullとは?
• 何もない(Null)ことを表すクラス
• コレクションに格納できないnilの代わりに使用
‣ + (id)null
•
NSNullのインスタンスを返す
•
常に同じインスタンスが返される
➡ NSNullかどうかをポインタ比較で判定可能
➡ alloc, initでの作成は不可
53
NSNull
使用例
NSArray *array = [NSArray arrayWithObjects:@"A", @"B", [NSNull null],
@"D", [NSNull null], nil];
for(id object in array) {
// 列挙されたオブジェクトがNSNullでなかったら出力
if(object != [NSNull null]) {
NSLog(@"%@", object);
}
}
54
ラッパークラス
ラッパー(Wrapper)クラスとは?
• オブジェクトではないデータ型をオブジェクト
して扱えるようにするためのクラス
➡ コレクション内に格納可能
• 主なラッパークラス
• NSNumber
• NSValue ※講義では扱わない
55
ラッパークラス
NSNumber
• 数値とそれに準ずるデータ型のためのラッパー
クラス
• 取り扱えるデータ型
BOOL, char, double, float, int, long, long long,
short, unsigned char, unsigned int, unsigned long,
unsigned long long, unsigned short, NSInteger,
NSUInteger
56
ラッパークラス
NSNumberのメソッド(int型の場合)
‣
- (id)initWithInt:(int)value
‣
+ (NSNumber *)numberWithInt:(int)value
•
‣
int型のvalueを指定してインスタンスを作成して返す
- (int)intValue
•
インスタンスに格納された値をint型の値として返す
➡ 取り扱えるデータ型のすべてに上記に相当するメソッド
がある
57
ラッパークラス
使用例
// 数値を辞書に格納して取得・出力
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
[dictionary setObject:[NSNumber numberWithInt:2] forKey:@"Key1"];
[dictionary setObject:[NSNumber numberWithInt:10] forKey:@"Key2"];
for(NSString *key in dictionary) {
NSNumber *number = [dictionary objectForKey:key];
int rawNumber = [number intValue];
NSLog(@"%d", rawNumber);
}
58
【参考】
通知
通知
通知とは?
• オブジェクトから他のオブジェクトへイベント
の発生を知らせること
• ex. データの更新完了、画面の回転 など
直接通知方式
• 必要なオブジェクト間で直接通知を行う
➡最も単純な通知方式
60
通知
直接通知方式の問題点
• 通知の送信側と受信側のオブジェクトを直接関
連付ける必要性
➡ オブジェクト間の独立性の低下
➡ プログラムの再利用性の低下
➡ プログラムの変更コストの増加
61
通知
通知センター方式(1/2)
• Foundationで採用されている通知方式
• 通知センターという第3者を介在させて通知
➡オブジェクト間の独立性を維持しつつ
通知を実施
62
通知
通知センター方式(2/2)
送信者
•
通知センターに通知を送信(ポスト)
監視者
•
•
通知センターから通知を受信
予め監視者として通知センターに登録
通知センター
•
通知を送信者から受信したら、その通
知の監視者に通知を送信
63
通知
NSNotification(1/2)
• 通知を表すクラス
‣
+ (id)notificationWithName:(NSString *)aName
object:(id)anObject userInfo:(NSDictionary *)userInfo
•
通知を表すインスタンスを作成して返す
•
aNameに通知名、anObjectに通知の送信者、userInfo
に通知の際に同時に送りたい情報を指定
•
anObject、userInfoはnilでも可
NSNotification *notification = [NSNotification
notificationWithName:@"NotificationName" object:self useInfo:nil];
64
通知
NSNotification(2/2)
‣
- (NSString *)name
‣
- (id)object
‣
- (NSDictionary *)userInfo
•
通知に格納されている通知名、送信者、userInfoをそ
れぞれ返す
65
通知
NSNotificationCenter
• 通知センターのクラス
▽ 通知センターの取得
‣ + (id)defaultCenter
•
通知センターのインスタンスを返す
➡ alloc, initなどは使用しない
➡ 所有は発生しない
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
66
通知
▽ 監視者の登録(1/3)
‣
- (void)addObserver:(id)notificationObserver
selector:(SEL)notificationSelector
name:(NSString *)notificationName
object:(id)notificationSender
•
監視に関する詳細を通知センターに登録(複数登録可)
•
notificationObserver:監視者のオブジェクト
•
notificationSelector:監視者が通知を受信した際に呼
ばれるメソッドのセレクター。メソッドは通知を表す
NSNotificationのオブジェクトを引数に持つ。
ex. - (void)notificationHandler:(NSNotification *)notification;
67
通知
▽ 監視者の登録(2/3)
•
notificationName:監視者が監視する通知名。nilを指
定可能(指定なしとみなされる)。
•
notificationSender:監視者が監視する通知の送信者。
nilを指定可能(指定なしとみなされる)。
通知名
送信者
監視者に通知される対象
指定あり
指定あり
特定の通知名、特定の送信者からの通知
指定あり
指定なし
特定の通知名を持つ全ての通知
指定なし
指定あり
特定の送信者からの全ての通知
指定なし
指定なし
全ての通知
68
通知
▽ 監視者の登録(3/3)
/* objectが -(void)notificationHandler:(NSNotification *)notification
メソッドを持つと仮定 */
// 任意の送信者からの NotificationName という通知名の通知を
// 受信する監視者objectを通知センターに登録
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:object selector:@selector(notificationHandler:)
name:@"NotificationName" object:nil];
69
通知
▽ 監視者の削除
‣
- (void)removeObserver:(id)notificationObserver name:
(NSString *)notificationName object:(id)notificationSender
‣
- (void)removeObserver:(id)notificationObserver
• 通知センターに登録した監視者を削除
• 後者は全ての登録を削除
※重要
• 通知センターは監視者として登録したオブジェクトを
所有しないので、監視者がメモリから解放される前に
必ず通知センターから監視者を削除すること!
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center removeObserver:self];
70
通知
▽ 通知のポスト
‣
- (void)postNotification:(NSNotification *)notification
‣
- (void)postNotificationName:(NSString *)notificationName
object:(id)notificationSender userInfo:(NSDictionary *)userInfo
•
通知センターに通知をポスト
•
前者は通知オブジェクトを指定
•
後者は通知の各種情報を指定
[[NSNotificationCenter defaultCenter]
postNotificationName:@"NotificationName" object:self userInfo:nil];
71