NSUserDefaults의 NSMutableArray에 사용자 지정 개체 저장
최근에 내 iPhone 앱의 검색 결과를 NSUserDefaults 컬렉션에 저장하려고했습니다. 또한 이것을 사용하여 사용자 등록 정보를 성공적으로 저장하지만 어떤 이유로 사용자 지정 위치 클래스의 NSMutableArray를 저장하려고하면 항상 비어있게됩니다.
이 게시물에서 NSMutableArray를 NSData 요소로 변환하려고 시도했지만 동일한 결과를 얻었습니다 ( iPhone에서 NSUserDefaults를 사용하여 정수 배열을 저장할 수 있습니까? ).
내가 시도한 코드 샘플은 다음과 같습니다.
저장:
[prefs setObject:results forKey:@"lastResults"];
[prefs synchronize];
또는
NSData *data = [NSData dataWithBytes:&results length:sizeof(results)];
[prefs setObject:data forKey:@"lastResults"];
또는
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:results];
[prefs setObject:data forKey:@"lastResults"];
하중:
lastResults = (NSMutableArray *)[prefs objectForKey:@"lastResults"];
또는
NSData *data = [prefs objectForKey:@"lastResults"];
memcpy(&lastResults, data.bytes, data.length);
또는
NSData *data = [prefs objectForKey:@"lastResults"];
lastResults = [NSKeyedUnarchiver unarchiveObjectWithData:data];
아래의 조언을 따르면 내 개체에 NSCoder를 구현했습니다 (임시 NSString의 남용 무시).
#import "Location.h"
@implementation Location
@synthesize locationId;
@synthesize companyName;
@synthesize addressLine1;
@synthesize addressLine2;
@synthesize city;
@synthesize postcode;
@synthesize telephoneNumber;
@synthesize description;
@synthesize rating;
@synthesize priceGuide;
@synthesize latitude;
@synthesize longitude;
@synthesize userLatitude;
@synthesize userLongitude;
@synthesize searchType;
@synthesize searchId;
@synthesize distance;
@synthesize applicationProviderId;
@synthesize contentProviderId;
- (id) initWithCoder: (NSCoder *)coder
{
if (self = [super init])
{
self.locationId = [coder decodeObjectForKey:@"locationId"];
self.companyName = [coder decodeObjectForKey:@"companyName"];
self.addressLine1 = [coder decodeObjectForKey:@"addressLine1"];
self.addressLine2 = [coder decodeObjectForKey:@"addressLine2"];
self.city = [coder decodeObjectForKey:@"city"];
self.postcode = [coder decodeObjectForKey:@"postcode"];
self.telephoneNumber = [coder decodeObjectForKey:@"telephoneNumber"];
self.description = [coder decodeObjectForKey:@"description"];
self.rating = [coder decodeObjectForKey:@"rating"];
self.priceGuide = [coder decodeObjectForKey:@"priceGuide"];
self.latitude = [coder decodeObjectForKey:@"latitude"];
self.longitude = [coder decodeObjectForKey:@"longitude"];
self.userLatitude = [coder decodeObjectForKey:@"userLatitude"];
self.userLongitude = [coder decodeObjectForKey:@"userLongitude"];
self.searchType = [coder decodeObjectForKey:@"searchType"];
self.searchId = [coder decodeObjectForKey:@"searchId"];
self.distance = [coder decodeObjectForKey:@"distance"];
self.applicationProviderId = [coder decodeObjectForKey:@"applicationProviderId"];
self.contentProviderId = [coder decodeObjectForKey:@"contentProviderId"];
}
}
- (void) encodeWithCoder: (NSCoder *)coder
{
[coder encodeObject:locationId forKey:@"locationId"];
[coder encodeObject:companyName forKey:@"companyName"];
[coder encodeObject:addressLine1 forKey:@"addressLine1"];
[coder encodeObject:addressLine2 forKey:@"addressLine2"];
[coder encodeObject:city forKey:@"city"];
[coder encodeObject:postcode forKey:@"postcode"];
[coder encodeObject:telephoneNumber forKey:@"telephoneNumber"];
[coder encodeObject:description forKey:@"description"];
[coder encodeObject:rating forKey:@"rating"];
[coder encodeObject:priceGuide forKey:@"priceGuide"];
[coder encodeObject:latitude forKey:@"latitude"];
[coder encodeObject:longitude forKey:@"longitude"];
[coder encodeObject:userLatitude forKey:@"userLatitude"];
[coder encodeObject:userLongitude forKey:@"userLongitude"];
[coder encodeObject:searchType forKey:@"searchType"];
[coder encodeObject:searchId forKey:@"searchId"];
[coder encodeObject:distance forKey:@"distance"];
[coder encodeObject:applicationProviderId forKey:@"applicationProviderId"];
[coder encodeObject:contentProviderId forKey:@"contentProviderId"];
}
배열에 사용자 지정 개체를로드하는 경우 다음과 같이 배열을 가져 왔습니다.
NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults];
NSData *dataRepresentingSavedArray = [currentDefaults objectForKey:@"savedArray"];
if (dataRepresentingSavedArray != nil)
{
NSArray *oldSavedArray = [NSKeyedUnarchiver unarchiveObjectWithData:dataRepresentingSavedArray];
if (oldSavedArray != nil)
objectArray = [[NSMutableArray alloc] initWithArray:oldSavedArray];
else
objectArray = [[NSMutableArray alloc] init];
}
You should check that the data returned from the user defaults is not nil, because I believe unarchiving from nil causes a crash.
Archiving is simple, using the following code:
[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:objectArray] forKey:@"savedArray"];
As f3lix pointed out, you need to make your custom object comply to the NSCoding protocol. Adding methods like the following should do the trick:
- (void)encodeWithCoder:(NSCoder *)coder;
{
[coder encodeObject:label forKey:@"label"];
[coder encodeInteger:numberID forKey:@"numberID"];
}
- (id)initWithCoder:(NSCoder *)coder;
{
self = [super init];
if (self != nil)
{
label = [[coder decodeObjectForKey:@"label"] retain];
numberID = [[coder decodeIntegerForKey:@"numberID"] retain];
}
return self;
}
I think you've gotten an error in your initWithCoder method, at least in the provided code you don't return the 'self' object.
- (id) initWithCoder: (NSCoder *)coder
{
if (self = [super init])
{
self.locationId = [coder decodeObjectForKey:@"locationId"];
self.companyName = [coder decodeObjectForKey:@"companyName"];
self.addressLine1 = [coder decodeObjectForKey:@"addressLine1"];
self.addressLine2 = [coder decodeObjectForKey:@"addressLine2"];
self.city = [coder decodeObjectForKey:@"city"];
self.postcode = [coder decodeObjectForKey:@"postcode"];
self.telephoneNumber = [coder decodeObjectForKey:@"telephoneNumber"];
self.description = [coder decodeObjectForKey:@"description"];
self.rating = [coder decodeObjectForKey:@"rating"];
self.priceGuide = [coder decodeObjectForKey:@"priceGuide"];
self.latitude = [coder decodeObjectForKey:@"latitude"];
self.longitude = [coder decodeObjectForKey:@"longitude"];
self.userLatitude = [coder decodeObjectForKey:@"userLatitude"];
self.userLongitude = [coder decodeObjectForKey:@"userLongitude"];
self.searchType = [coder decodeObjectForKey:@"searchType"];
self.searchId = [coder decodeObjectForKey:@"searchId"];
self.distance = [coder decodeObjectForKey:@"distance"];
self.applicationProviderId = [coder decodeObjectForKey:@"applicationProviderId"];
self.contentProviderId = [coder decodeObjectForKey:@"contentProviderId"];
}
return self; // this is missing in the example above
}
I use
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:results];
[prefs setObject:data forKey:@"lastResults"];
and
NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults];
NSData *dataRepresentingSavedArray = [currentDefaults objectForKey:@"lastResults"];
if (dataRepresentingSavedArray != nil)
{
NSArray *oldSavedArray = [NSKeyedUnarchiver unarchiveObjectWithData:dataRepresentingSavedArray];
if (oldSavedArray != nil)
objectArray = [[NSMutableArray alloc] initWithArray:oldSavedArray];
else
objectArray = [[NSMutableArray alloc] init];
}
and it works perfect for me.
With regards,
Stefan
I think it looks like the problem with your code is not saving the results array. Its loading the data try using
lastResults = [prefs arrayForKey:@"lastResults"];
This will return the array specified by the key.
See "Why NSUserDefaults failed to save NSMutableDictionary in iPhone SDK? " (Why NSUserDefaults failed to save NSMutableDictionary in iPhone SDK?)
If you want to (de)serialize custom objects, you have to provide the functions to (de)serialize the data (NSCoding protocol). The solution you refer to works with the int array because the array is not an object but a contiguous chunk of memory.
I would recommend against trying to store stuff like this in the defaults db.
SQLite is fairly easy to pick up and use. I have an episode in one of my screencasts (http://pragprog.com/screencasts/v-bdiphone) about a simple wrapper that I wrote (you can get the code without buying the SC).
It's much cleaner to store app data in app space.
All that said if it still makes sense to put this data into the defaults db, then see the post f3lix posted.
'Programming' 카테고리의 다른 글
sed가 모든 항목을 대체하지 않는 이유는 무엇입니까? (0) | 2020.08.17 |
---|---|
Android에서 고유 한 장치 하드웨어 ID를 얻는 방법은 무엇입니까? (0) | 2020.08.17 |
제약 이름으로 테이블 이름 가져 오기 (0) | 2020.08.17 |
Android에서 선택, 확인 및 활성화 된 상태의 차이점은 무엇입니까? (0) | 2020.08.17 |
grep은 어떻게 그렇게 빨리 실행됩니까? (0) | 2020.08.17 |