Cocoa API解説(macOS/iOS)

iOS , Mac アプリケーション開発のために使われる主要フレームワークの日本語情報です。

目次

NSDictionary

INDEX>Foundation>NSDictionary

変更しない辞書クラス

編集時のバージョン OS X 10.8/iOS 10.6

解説

「辞書」と呼ばれるコレクションクラスの一つです。

継承 NSObject
準拠 NSCopying
  NSMutableCopying
  NSFastEnumeration
  NSSecureCoding
  NSObject (NSObject)
フレームワーク /System/Library/Frameworks/Foundation.framework
使用可能 Mac OS X v10.0 以降
iOS 2.0 以降
定義 NSDictionary.h
  NSFileManager.h
  NSKeyValueCoding.h

概要

NSDictionaryクラスは、辞書と呼ばれ、キーと対応する値(オブジェクト)を保持するコレクションオブジェクトです。
他言語でマップまたは連想配列と呼ばれるものです。
作成、初期化すると変更は出来ません。キーはNSDictionaryオブジェクトにコピーされるのでキーの内容を変更することは出来ませんが、値(オブジェクト)はどこにあるかが保持されるだけなのでNSMutableStringなどの変更可能なオブジェクトであれば、値自体の変更は可能です。
似たようなクラスで、キーで対応する値を保持するNSCacheクラスがありますが、こちらはキーがNSCacheオブジェクトに保持されないので、キーの変更が可能です。

NSDictionaryでオブジェクトを検索する際にキーを使うので、キーは同じものがあってはいけません。キーが同じかどうかはisEqual:メッセージが送信されて比較されます。

キーや値がなにもないことを表す場合はNSNullオブジェクトを使用します。

トールフリーブリッジ

NSDictionaryはCore FoundationのCFDictionaryRefとトールフリーブリッジです。
ARC環境の場合は__bridge、__bridge_retainedなどを使って変換しなければなりません。

#pragma mark NSDictionary TOOL FREE BRIDGE:
-(void)method004
{
    //元となるのNSDictionaryを作成
    NSDictionary *aDictionary = [NSDictionary dictionaryWithObjectsAndKeys:@"aaa",@"key1",@"bbb",@"key2",@"ccc",@"key3", nil];
    NSLog(@"%s aDictionary %p = %@",__FUNCTION__,aDictionary,[aDictionary description]);
    
    CFDictionaryRef dict = (__bridge_retained  CFDictionaryRef)aDictionary;
    CFShow(dict);
    //=><CFBasicHash 0x6c161d0 [0x145eb48]>{type = immutable dict, count = 3,
    //entries =>
	//0 : <CFString 0x4620 [0x145eb48]>{contents = "key2"} = <CFString 0x4610 [0x145eb48]>{contents = "bbb"}
	//1 : <CFString 0x4600 [0x145eb48]>{contents = "key1"} = <CFString 0x45f0 [0x145eb48]>{contents = "aaa"}
	//2 : <CFString 0x4640 [0x145eb48]>{contents = "key3"} = <CFString 0x4630 [0x145eb48]>{contents = "ccc"}
    //}
    
    NSDictionary *newDictionary = (__bridge NSDictionary*)dict;
    
    NSLog(@"%s newDictionary %p = %@",__FUNCTION__,newDictionary,[newDictionary description]);
    //=>-[OOOAppDelegate method004] newDictionary 0x6c161d0 = {key1 = aaa;key2 = bbb;key3 = ccc;}
    //ポインタの部分は毎回変わります。
    
}

本クラスについて

キーと値で構成されたペア(エントリーと呼ばれます)を持つ、辞書を呼ばれるクラスです。作成・初期化後は変更することができません。変更可能な辞書はNSMutableDictionaryを使用します。
辞書自体は変更できませんが、含まれる要素が変更可能なオブジェクトの場合(例えばNSMutableString)、そのオブジェクトの内容を変更することはできます。
辞書作成時にキーは辞書内にコピーされ、値は参照のみが保持されます。(一部のメソッドを除く)

C言語フレームワークである、Core FoundationのCFDictionaryRefとトールフリーブリッジです。ARC環境以外ではそのまま使用できます。
どちらかのフレームワークにしかないメソッド・関数を使いたい場合、キャストして使うことが出来ます。
ARC環境では、管理対象のオブジェクトのキャストに__bridge、__bridge_retained、__bridge_transferが必要になります。

作成

オブジェクトの配列とキーの配列で作成するメソッド(+ dictionaryWithObjects:forKeys+ dictionaryWithObjects:forKeys:count)、オブジェクト・キーの繰り返し(最後はnil)で作成するメソッド(+ dictionaryWithObjectsAndKeys)があります。
ファイルパスを指定してそのファイルから作成するメソッド(+ dictionaryWithContentsOfFile)、URLを指定してそのファイルから作成するメソッド(+ dictionaryWithContentsOfURL)があります。

初期化

オブジェクトの配列とキーの配列で初期化するメソッド(– initWithObjects:forKeys– initWithObjects:forKeys:count)、オブジェクト・キーの繰り返し(最後はnil)で作成するメソッド(– initWithObjectsAndKeys)があります。
ファイルパスを指定してそのファイルから初期化するメソッド(– initWithContentsOfFile)、URLを指定してそのファイルから作成するメソッド(– initWithContentsOfURL)があります。
初期化の際、通常キーはコピーされますが、値はコピーされません。値をコピーするオプションを持ったメソッド(– initWithDictionary:copyItems)を使い、copyItems:にYESを渡すことで値となるオブジェクトがコピーされるようになります。

エントリーのカウント

キーと値のペアからなるエントリーの数が辞書にいくつ含まれるかを知るには(– count)メソッドを使います。

辞書の比較

他の辞書を内容が同じかどうかを調べるには(– isEqualToDictionary)メソッドを使います。
他の辞書と同じかどうかの条件は、エントリの数が同数であり、かつ各キーに対して値が同じかどうかisEqual:でテストしてYESの場合に同じ辞書だと判断されます。

キーと値へのアクセス

すべてのキーを配列で返すメソッド(– allKeys)、すべての値を配列で返すメソッド(– allValues)、指定されたオブジェクトに対応するキーを配列で返すメソッド(– allKeysForObject)があります。
指定したキーに対応する値のオブジェクトを返すメソッド(– objectForKey)、複数の値に対応するキーを配列で返すメソッド(– objectsForKeys:notFoundMarker)、キーバリューコーディングで使用するメソッド(– valueForKey)があります。

– objectForKey– valueForKeyは、ほぼ同じ値を返すのですが、最初の文字が"@"の場合、– valueForKeyではキーバリューコーディングの演算子として違った挙動をしますので注意が必要です。
辞書からのオブジェクトを取り出しは– objectForKeyを使います。

#pragma mark NSDictionary valueForKey
-(void)method018
{
    NSDictionary *aDictionary = [NSDictionary dictionaryWithObjectsAndKeys:@"aaa",@"key1",@"bbb",@"key2",@"ccc",@"key3", nil];
    NSLog(@"%s %p %@",__FUNCTION__,aDictionary,[aDictionary objectForKey:@"@count"]);
    NSLog(@"%s %p %@",__FUNCTION__,aDictionary,[aDictionary valueForKey:@"@count"]);
    NSLog(@"%s %p %@",__FUNCTION__,aDictionary,[aDictionary objectForKey:@"@allKeys"]);
    NSLog(@"%s %p %@",__FUNCTION__,aDictionary,[aDictionary valueForKey:@"@allKeys"]);
   //=>-[OOOAppDelegate method018] 0x6a62d60 (null)
   //=>-[OOOAppDelegate method018] 0x6a62d60 3
   //=>-[OOOAppDelegate method018] 0x6a62d60 (null)
   //=>-[OOOAppDelegate method018] 0x6a62d60 (key2,key1,key3)
}

辞書の列挙

NSEnumeratorを返すメソッドとして(– keyEnumerator)(– objectEnumerator)がありますが、ブロックオブジェクトを使って列挙を行うメソッド(– enumerateKeysAndObjectsUsingBlock– enumerateKeysAndObjectsWithOptions:usingBlock)がiOS4.0から利用可能となっています。

#pragma mark NSDictionary  enumerateKeysAndObjectsWithOptions:usingBlock:
-(void)method020
{
    NSDictionary *aDictionary = [NSDictionary dictionaryWithObjectsAndKeys:@"aaa",@"key1",@"bbb",@"key2",@"ccc",@"key3", nil];
    [aDictionary enumerateKeysAndObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(id key, id obj,BOOL *stop) {
        NSLog(@"%s %p %@=%@",__FUNCTION__,aDictionary,key,obj);
        
        if ([obj isEqualToString:@"ccc"]) {
            *stop = YES;   
        }
    }];
    //=> 0x6a4f7a0 key2=bbb
    //=> 0x6a4f7a0 key1=aaa
    //=> 0x6a4f7a0 key3=ccc
}

辞書のソート

辞書をソートするには大きく分けて二つあります。一つはセレクタを使うメソッド(– keysSortedByValueUsingSelector)、もう一つはコンペレーターを使うメソッド(– keysSortedByValueUsingComparator)です。
オブジェクトをソートしてソートされたキーの配列を返します。

#pragma mark sortedArrayWithOptions:usingComparator:
-(void)method022
{
    NSDictionary *aDictionary = [NSDictionary dictionaryWithObjectsAndKeys:@"bbb",@"key2",@"ccc",@"key3",@"aaa",@"key1", nil];
    NSArray *sortedKeyArray = [aDictionary keysSortedByValueWithOptions:NSEnumerationConcurrent usingComparator:^(id obj1,id obj2){
        return [obj1 compare:obj2];
    }];
    
    NSLog(@"%s %p %@",__FUNCTION__,sortedKeyArray,[sortedKeyArray description]);
    //=>-[OOOAppDelegate method021] 0x6a3a1e0 (key1,key2,key3)
    
}

辞書のフィルタリング

条件に合うエントリのキーをNSSetオブジェクトにして返すメソッド(– keysOfEntriesPassingTest)があります。
NSSetクラスは、順序と重複がないコレクションクラスです。

#pragma mark indexOfObjectPassingTest:
-(void)method023
{
    NSDictionary *aDictionary = [NSDictionary dictionaryWithObjectsAndKeys:@"obj",@"key2",@"obj",@"key3",@"aaa",@"key1", nil];
    
    NSSet *aSet = [aDictionary keysOfEntriesPassingTest:^ BOOL (id key ,id obj,  BOOL *stop)
                      {
                         
                          if ([obj isEqualToString:@"obj"]) {
                              return YES;    
                          }else {
                              return NO;
                          }
                          
                      }];
    NSLog(@"%s %p %@",__FUNCTION__,aSet,[aSet description]);
    
}

辞書の保存

ファイルパスを使用するメソッド(– writeToFile:atomically)とURLを使用するメソッド(– writeToURL:atomically)があります。
atomically:にYESを渡すことで、一旦一時ファイルに書き出してその後リネームする方法で書き出されます。


サブクラス化

サブクラス化する必要はほとんどありませんが、以下の3つのメソッドをオーバーライドする必要があります。
- count
- objectForKey
- keyEnumerator


列挙

Mac OS X 10.5 以降ではNSFastEnumerationプロトコルをサポートします。
Mac OS X 10.6 以降、iOS4.0以降では、NSDictionaryはブロックオブジェクトを使って列挙をサポートします。

共有キーセットを作成

+ sharedKeySetForKeys

要素数

– count

辞書の比較

– isEqualToDictionary