私はこれを行う方法に関する情報を上から下まで検索してきました。素晴らしいチュートリアルにたどり着きました!だから私はまだこれにかなり初心者です。基本的に、マップ ビューの注釈を配列に格納しようとしています。注釈は、基本的にオーバーライドする/MKAnnotation
ピン注釈として機能する別のクラスです。次の 3 つのプロパティがあります。
- 注釈座標
- 注釈のタイトル
- 注釈字幕
この配列は に格納する必要がありNSUserDefaults
ます。問題に直面しました。ログは次のとおりです。
[UIMutableIndexPath setObject:forKey:]: 認識されないセレクターがインスタンス 0x1187b0 に送信されました
配列内に格納されている Annotation クラス オブジェクトをユーザー デフォルトに保存できませんでした。それで、この配列を変換しNSData
て保存する必要がありましたよね?
私はたくさんのコードを設定していますが、うまくいきません。これが私がこれをすべて試みる方法です:
コントローラ Class.m を表示:
- (void)syncMap { // this method is called in viewWillDissapear (for running tests) and applicationDidEnterBackground in App Delegate
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject: localOverlays]; // this is the array I was talking about
[defaults setObject:data forKey:@"overlays"];
[defaults synchronize];
}
- (void)initCircles { // called in AppDelegate UIApplicationDelegate method: applicationDidFinishLaunchingWithOptions
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *data = [defaults objectForKey: @"overlays"];
localOverlays = [NSKeyedUnarchiver unarchiveObjectWithData: data];
if (!localOverlays) {
// Either there is a problem or it is the first time opening the app
localOverlays = [[NSMutableArray alloc] init];
}
}
注: 配列内の 2 つの注釈を使用してテストしています ( localOverlays
)
だから、それlocalOverlays
は. ただし、Annotation クラスにさらにセットアップを追加する必要がありました。その .h では、次のように toと:を使用します。正しい用語を使用していない場合は申し訳ありません。これが私の.mです:NSCoder
NSArray
NSCoding
MKAnnotation
< NSCoding, MKAnnotation>
- (void)encodeWithCoder:(NSCoder *)aCoder { // should only be called when app enters background state, but since that cannot log in the console, like before I set it up so it should also be called in viewWillDissapear
NSLog(@"encodeCoder called in Annotation"); // gets called twice when the view will disappear... GOOD!
[aCoder encodeObject: title forKey: @"title"];
[aCoder encodeObject: subtitle forKey: @"subtitle"];
[aCoder encodeDouble: coordinate.latitude forKey: @"latitude"];
[aCoder encodeDouble: coordinate.longitude forKey: @"longitude"];
}
- (id)initWithCoder:(NSCoder *)aDecoder { // Should be called only at startup of app (not the first time you startup the app though... because data will be NULL)
NSLog(@"In the Annotation class, initWithCoder is called"); // Does get called at appropriate times twice... NICE!
self = [super init];
if (self) {
title = [aDecoder decodeObjectForKey: @"title"];
subtitle = [aDecoder decodeObjectForKey: @"subtitle"];
double lat = [aDecoder decodeDoubleForKey: @"latitude"];
double lon = [aDecoder decodeDoubleForKey: @"longitude"];
coordinate = CLLocationCoordinate2DMake(lat, lon);
}
return self;
}
ご覧のとおり、アーカイブ用のすべてのセットアップが完了していますよね? そうではないようです... ViewController の .m には、viewDidLoad にも次のコードがあるためです。
for (Annotation *pin in localOverlays) {
if (pin) {
NSLog(@"valid pin: _CMD updateCircles");
[mapView addAnnotation: pin];
}
}
このコードは、最初にアプリを開いてピンを追加したときにうまく機能します。さて、ビューを終了してアプリを終了し、マルチタスク バーから削除しました。もう一度開くと、高速列挙行でクラッシュします。
-[NSURL countByEnumeratingWithState:objects:count:]: unrecognized selector sent to instance 0xcd31140
そのため、アーカイブとエンコードの設定すべてに問題があります。ここで何が問題なのですか...これが長い質問であることはわかっていますが、うまく構成しようとしました。コードを完全に間違って設定していますか、コードにタイプミス/バグがありますか? 皆さんありがとう!
アップデート:
座標変数がエンコードされているため、ピンが正しい座標に表示された後にアプリを起動すると、ピンを押してタイトルとサブタイトルを表示しようとすると、次のクラッシュが発生します。
objc_msgSend
それで、何かが正しくリリースされます...推測ですが...メモリ管理が悪いのですか?私のコードでこのクラッシュが発生する原因は何ですか?
アップデート:
コードをさらに深く調べ、いくつかのrelease
ステートメントを変更し、メモリ管理を改善し、最適化を少し行いました。今、私はより具体的なクラッシュを取得します:
*** -[CFString length]: message sent to deallocated instance 0x147490
私のタイトルまたはサブタイトルの割り当てが解除されました...なぜですか? 特に座標が問題ないので、コードをチェックしましたが、絶対に問題ないはずです...
アップデート:
私はこの問題を解決しました!座標の 2 つの変数、緯度と経度は double であり、データ型はオブジェクトではありません! したがって、それらは参照されているオブジェクトとは異なり、コピーされているためだけに固執し、機能しています。簡単に言えば、私がする必要があったretain
. ちょうどこのような:
title = [[aDecoder decodeObjectForKey: @"titler"] retain];
subtitle = [[aDecoder decodeObjectForKey: @"subtitler"] retain];