2013-08-28 14 views
7

MKMapViewのセンターとスパンを状態保存のためにNSKeyedArchiverにエンコードしようとしました。私は便利な新しいMapKit NSValueの追加、valueWithMKCoordinate:valueWithMKCoordinate:を見つけました。NSKeyedArchiverでNSValueをエンコードできないのはなぜですか?

- (void)encodeRestorableStateWithCoder:(NSCoder *)coder 
{ 
    NSValue *mapCenterValue = [NSValue valueWithMKCoordinate:mapView.centerCoordinate]; 
    NSValue *mapSpanValue = [NSValue valueWithMKCoordinateSpan:mapView.region.span]; 
    [coder encodeObject:mapCenterValue forKey:kMapCenter]; 
    [coder encodeObject:mapSpanValue forKey:kMapSpan]; 
} 

がキャッチされない例外により 'NSInvalidArgumentException'、理由にアプリを終了:失敗したキー付きアーカイバにこれらをエンコードしようとしている ' - [NSKeyedArchiver encodeValueOfObjCType:で:]:このアーカイバエンコードすることができない構造体'

この問題の解決策は、個々のダブルスを4つの別々のキーにエンコードすることだと私は理解しています。

私の質問はなぜになるのですか? NSValueがオブジェクトであるので、なぜそれが

答えて

4

キー付きアーカイブは、アーカイブにエンコードされているすべてのオブジェクトおよび値の名前、またはキーを与えられているという点で、非キー付きアーカイブと異なります。 structの要素をアーカイブし、structの各フィールドがどこにあるか知っているメタデータが必要になり、それらNSKeyedArchiverへの鍵を与え、そして何のために

は、これらのフィールドの名前です。 NSValueと格納されている@encodeは、structのレイアウトに関する十分な情報を提供しますが、各フィールドの名前に関する情報はありません。

structにはフィールドの名前に関するメタデータがないため、適切なアーカイブ解除を保証する方法でデータをアーカイブすることは不可能です。そのため、NSKeyedArchiverは、埋め込みC structNSValueをアーカイブすることを拒否する必要があります。

+0

私は 'NSValue'が' NSData'のようなものをコード化していると仮定していましたが、そのフォーマットを知っていれば他端で解凍できるバイトのストリームです。これは間違っていると思いますか? –

+0

それは間違っていませんが、NSValueはそれをパックしてバイトから/から解凍できるように格納しているデータに関する十分な情報を知りません。 –

+1

@nevankingこれはNSArchiverを使うときには本当に当てはまります。しかし、 'NSKeyedArchiver'は、名前を持つためにデータ項目に追加の要件を置きます。その代わりに、キー付きアーカイバを使用すると、100%同一ではないオブジェクトにアーカイブを保存できます(https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Archiving/Articles/compatibility.html#//apple_ref/doc/uid/20001055-BCICFFGE)。 – dasblinkenlight

1

NSValue「このアーカイバは、構造体をエンコードすることはできません」私に言っているObjective-Cのオブジェクトに非オブジェクト(例えばCの構造体、int型など)をカプセル化するために使用されますが、それこれらのラップされた型のカスタムアーカイブ/シリアライゼーションルーチンを定義する方法はありません。これはちょうどそのインタフェースの一部ではありません。

構造体を含むNSValueをアーカイブしたい場合は、エンディアンのようなものを考慮し、ネストされたポインタやバイトとして書き出すことができないその他の型を処理する必要があります。 NSValueでこれを自動的に行う方法はありません。 NSKeyedArchiverクラスのドキュメントによれば

+0

私はあなたが内部的に( 'NSArrayの中のような値を使用することができ、なぜこれがあると思います')しかし外部的には(アーカイブの共有のように)。 –

2

私は同じ問題に遭遇し、最も簡単な解決策はただ退屈すると、個々のすべての値を符号化することであろうことを決めた:

- (void)encodeRestorableStateWithCoder:(NSCoder *)coder 
{ 
    MKCoordinateRegion region = [self.mapView region]; 
    [coder encodeDouble:region.center.latitude forKey:RWSMapCenterLatitude]; 
    [coder encodeDouble:region.center.longitude forKey:RWSMapCenterLongitude]; 
    [coder encodeDouble:region.span.latitudeDelta forKey:RWSMapCenterLatitudeDelta]; 
    [coder encodeDouble:region.span.longitudeDelta forKey:RWSMapCenterLongitudeDelta]; 

    [super encodeRestorableStateWithCoder:coder]; 
} 

- (void)decodeRestorableStateWithCoder:(NSCoder *)coder 
{ 
    MKCoordinateRegion region; 
    CLLocationCoordinate2D center; 
    center.latitude = [coder decodeDoubleForKey:RWSMapCenterLatitude]; 
    center.longitude = [coder decodeDoubleForKey:RWSMapCenterLongitude]; 
    region.center = center; 
    MKCoordinateSpan span; 
    span.latitudeDelta = [coder decodeDoubleForKey:RWSMapCenterLatitudeDelta]; 
    span.longitudeDelta = [coder decodeDoubleForKey:RWSMapCenterLongitudeDelta]; 
    region.span = span; 

    self.mapView.region = region; 

    [super decodeRestorableStateWithCoder:coder]; 
} 
関連する問題