ทำไม NSUserDefaults จึงไม่สามารถบันทึก NSMutableDictionary ใน iOS ได้


145

ฉันต้องการที่จะบันทึกวัตถุในNSMutableDictionary NSUserDefaultsชนิดที่สำคัญในการNSMutableDictionaryมีNSStringประเภทค่าเป็นซึ่งมีรายชื่อของวัตถุที่นำไปปฏิบัติNSArray NSCodingต่อเอกสารNSStringและทั้งสองมีความสอดคล้องกับNSArrayNSCoding

ฉันได้รับข้อผิดพลาดนี้:

[NSUserDefaults setObject: forKey:]: พยายามแทรกค่าที่ไม่ใช่คุณสมบัติ .... ของคลาส NSCFDictionary

คำตอบ:


230

ฉันพบทางเลือกหนึ่งก่อนที่จะบันทึกผมเข้ารหัสวัตถุราก ( NSArrayวัตถุ) โดยใช้ซึ่งจะสิ้นสุดลงด้วยNSKeyedArchiver NSDataจากนั้นใช้ UserDefaults NSDataประหยัด

เมื่อฉันต้องการข้อมูลฉันอ่านNSDataและใช้NSKeyedUnarchiverในการแปลงNSDataกลับไปเป็นวัตถุ

มันค่อนข้างยุ่งยากเพราะฉันต้องแปลงเป็น / จากNSDataทุกครั้ง แต่มันก็ใช้ได้

นี่คือตัวอย่างหนึ่งต่อคำขอ:

บันทึก:

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSMutableArray *arr = ... ; // set value
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:arr];
[defaults setObject:data forKey:@"theKey"];
[defaults synchronize];

โหลด:

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *data = [defaults objectForKey:@"theKey"];
NSArray *arr = [NSKeyedUnarchiver unarchiveObjectWithData:data];

องค์ประกอบในอาร์เรย์ใช้

@interface CommentItem : NSObject<NSCoding> {
    NSString *value;
}

จากนั้นในการดำเนินการCommentItemให้สองวิธี:

-(void)encodeWithCoder:(NSCoder *)encoder
{
    [encoder encodeObject:value forKey:@"Value"];
}

-(id)initWithCoder:(NSCoder *)decoder
{
    self.value = [decoder decodeObjectForKey:@"Value"];
    return self;
}

ใครมีทางออกที่ดีกว่า

ขอบคุณทุกคน


4
คุณมีตัวอย่างรหัสคุณสามารถแบ่งปันผมได้พยายามที่จะทำเช่นนี้ในการโพสต์ (537,044) แต่ไม่มีความสุข
แอนโธนีหลัก

มันทำงานได้ดีสำหรับฉัน ฉันพยายามเข้ารหัส NSArray ของวัตถุ NSDictionary ที่บางส่วนของคีย์ไม่ได้เป็นสตริง เพียงแค่ใช้ NSKeyedArchiver และ Unarchiver บน NSArray ได้กำจัดข้อผิดพลาด "พยายามแทรกค่าที่ไม่ใช่คุณสมบัติ"
John Wright

ฉันจะต้องปล่อยวัตถุที่โหลดเมื่อใด ไม่มีการจัดสรรถูกเรียกดังนั้นฉันคิดว่ามันถูกลบอัตโนมัติ
Marc

7
เราอาจต้องเพิ่ม [ค่าเริ่มต้นให้ตรงกัน] สำหรับการบันทึก
thanhbinh84

วิธีแก้ปัญหาที่โพสต์ที่นี่อาจใช้งานได้ระยะหนึ่ง แต่เมื่อคุณตัดสินใจที่จะลบหรือเปลี่ยนชั้นเรียนคุณจะพบว่าตัวคุณถูกล็อคอย่างไม่เป็นระเบียบ ทางออกที่ดีกว่าคือทำให้วัตถุของคุณเขียนสถานะโดยใช้ NSNumbers, Strings และอื่น ๆ ในพจนานุกรมจากนั้นเก็บไว้ พิสูจน์ได้ในอนาคต.
Tom Andersen

105

หากคุณกำลังบันทึกวัตถุในค่าเริ่มต้นของผู้ใช้วัตถุทั้งหมดที่เรียกใช้ซ้ำจะต้องเป็นวัตถุในรายการคุณสมบัติ การทำตาม NSCoding ไม่ได้หมายความว่าอะไรที่นี่ - NSUserDefaultsจะไม่เข้ารหัสโดยอัตโนมัติNSDataคุณต้องทำเอง หาก "รายการวัตถุที่ใช้งานNSCoding" ของคุณหมายถึงวัตถุที่ไม่ใช่วัตถุรายการคุณสมบัติคุณจะต้องทำบางสิ่งกับวัตถุเหล่านั้นก่อนบันทึกเป็นค่าเริ่มต้นของผู้ใช้

FYI คลาสรายการทรัพย์สินNSDictionary, NSArray, NSString, NSDate, และNSData NSNumberคุณสามารถเขียนคลาสย่อยที่ไม่แน่นอน (เช่นNSMutableDictionary) ไปยังการตั้งค่าผู้ใช้ แต่วัตถุที่คุณอ่านออกจะไม่เปลี่ยนรูปเสมอ


61
ฉันควรจะพูดถึงว่า NSDictionary เป็นเพียงวัตถุรายการคุณสมบัติถ้าคีย์เป็น NSStrings โดยทั่วไปคุณสามารถใช้วัตถุอื่น ๆ เป็นคีย์พจนานุกรมได้ แต่เมื่อต้องการรายการคุณสมบัติคีย์ต้องเป็นสตริง
Tom Harrington

ฉันเจอปัญหาเดียวกันเมื่อฉันต้องการเก็บ NSURL เป็นวัตถุใน NSDictionary และเก็บไว้ใน NSUserDefaults ฉันต้องเปลี่ยนเป็น NSString มากกว่าที่มันใช้ได้
NicTesla

1
ที่ดี! ในกรณีของฉันฉันพยายามใช้ NSNumber เป็นคีย์ของ NSDictionary ในค่าเริ่มต้นของผู้ใช้ ฉันต้องเปลี่ยนเป็น NSString
Joey

1
พฤติกรรมหน่วงดังกล่าวเป็นสิ่งที่นำไปสู่นักเขียนโค้ดที่ไม่มีประสบการณ์ซึ่งเขียนแบบจำลองข้อมูลทั้งหมดเป็นพจนานุกรมแทนที่จะสร้างวัตถุข้อมูลที่เหมาะสม มันยากแค่ไหนที่แอปเปิ้ลเขียนคลาสพื้นฐานที่ใช้ข้อเท็จจริงที่ว่า obj-c มีการวิปัสสนาและดูแลมวยและ unboxing สำหรับเรา
ArtOfWarfare

14

กุญแจทั้งหมดของคุณอยู่ในพจนานุกรมNSStringหรือไม่ ฉันคิดว่าพวกเขาจะต้องบันทึกพจนานุกรมลงในรายการทรัพย์สิน


1
กุญแจคือ NSString แต่ค่าคือ NSArray ซึ่งองค์ประกอบเป็นคลาสที่กำหนดเองซึ่งใช้ NSCoding ปรากฏว่าโซลูชันไม่ทำงานเนื่องจาก UserDefaults รองรับคลาสได้เพียง 6 ประเภทเท่านั้นไม่พิจารณาใช้ NSCoding
BlueDolphin

8

คำตอบที่ง่ายที่สุด:

NSDictionaryเป็นเพียงวัตถุ plistถ้าคีย์มี NSStrings ดังนั้นการจัดเก็บ"คีย์"เป็นด้วยNSStringstringWithFormat


สารละลาย :

NSString *key = [NSString stringWithFormat:@"%@",[dictionary valueForKey:@"Key"]];

ประโยชน์:

  1. มันจะเพิ่มString-Value
  2. มันจะเพิ่มที่ว่างเปล่า-ValueNULLเมื่อค่าของตัวแปรคือ

2
ฉันมีปัญหาที่คล้ายกัน: กุญแจของฉันคือ NSNumber ซึ่งเห็นได้ชัดว่าไม่ได้รับอนุญาตในกุญแจของพจนานุกรมที่มีการประนีประนอม
Mark Pauley

5

คุณเคยพิจารณาที่จะใช้NSCodingโปรโตคอลหรือไม่? นี้จะช่วยให้คุณสามารถเข้ารหัสและถอดรหัสบน iPhone NSCodingที่มีสองวิธีง่ายๆที่จะดำเนินการกับ ก่อนอื่นคุณต้องเพิ่มNSCodingคลาสของคุณ

นี่คือตัวอย่าง:

นี่คือไฟล์. h

@interface GameContent : NSObject <NSCoding>

จากนั้นคุณจะต้องใช้สองวิธีของโปรโตคอล NSCoding

    - (id) initWithCoder: (NSCoder *)coder
    {
        if (self = [super init])
        {
               [self setFoundHotSpots:[coder decodeObjectForKey:@"foundHotSpots"]];
        }
        return self;
    }

    - (void) encodeWithCoder: (NSCoder *)coder
    {
           [coder encodeObject:foundHotSpots forKey:@"foundHotSpots"];
    }

ตรวจสอบเอกสารใน NSCoder สำหรับข้อมูลเพิ่มเติม มีประโยชน์มากสำหรับโครงการของฉันที่ฉันต้องการบันทึกสถานะของแอปพลิเคชันบน iPhone หากแอปพลิเคชันถูกปิดและกู้คืนกลับสู่สถานะเมื่อกลับมาทำงานอีกครั้ง

NSCodingที่สำคัญคือการเพิ่มโปรโตคอลอินเตอร์เฟซและจากนั้นใช้สองวิธีที่เป็นส่วนหนึ่งของ

ฉันหวังว่านี่จะช่วยได้!


0

ไม่มีทางออกที่ดีกว่า อีกตัวเลือกหนึ่งคือเพียงบันทึกวัตถุที่เข้ารหัสแล้วลงในดิสก์ - แต่นั่นคือการทำสิ่งเดียวกัน พวกเขาทั้งสองจบลงด้วย NSData ที่ได้รับการถอดรหัสเมื่อคุณต้องการมันกลับมา

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.