NSUserDefaults - จะทราบได้อย่างไรว่ามีกุญแจอยู่หรือไม่


208

ฉันกำลังทำงานกับแอพเล็ก ๆ ของ iPhone และฉันใช้NSUserDefaultsเป็นข้อมูลอย่างต่อเนื่อง มันจะต้องติดตามสิ่งเล็ก ๆ น้อย ๆ อย่างเช่นชื่อบางชื่อและตัวเลขบางส่วนดังนั้นฉันจึงคิดว่าฉันอาจจะเข้าใจได้ง่าย

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

ตัวอย่างบางส่วน: แอปเริ่มต้นขึ้นหากนี่เป็นครั้งแรกที่แอปเริ่มส่งออกการแจ้งเตือนว่ายินดีต้อนรับ หากต้องการทราบว่านี่เป็นครั้งแรกที่เปิดขึ้นมาจะอ่านUserDefaultsและตรวจสอบ

ตัวอย่างที่ 2: มันบอกว่า "สวัสดี [ชื่อ]" โดยที่ชื่อคือสิ่งที่คุณป้อน หากคุณได้เปิดแอปและไม่มีชื่อมันควรจะพูดว่า "Hello World" ฉันต้องตรวจสอบว่าคุณป้อนชื่อแล้วและดำเนินการตามนั้น NSUserDefaultsชื่อที่จะถูกเก็บไว้ใน

ความช่วยเหลือที่นี่? ฉันซาบซึ้งจริงๆ!

คำตอบ:


382

objectForKey:จะกลับมาnilหากไม่มีอยู่


1
ฉันไม่คิดว่าคุณสามารถจัดเก็บประเภทข้อมูลดั้งเดิมใน NSUserDefaults
ทำลาย

12
เอกสารของ Apple บอกว่า "ถ้าค่าบูลีนสัมพันธ์กับ defaultName ในค่าเริ่มต้นของผู้ใช้ค่านั้นจะถูกส่งคืนมิฉะนั้นจะไม่มีการส่งคืน" ฉันไม่คิดว่าคำตอบข้างต้นนั้นถูกต้องสำหรับ BOOLs คุณไม่สามารถระบุได้ว่ามีการกำหนด NO หรือไม่มีอยู่จริง ฉันคิดว่าคุณต้องใช้– dictionaryRepresentationและตรวจสอบกุญแจ
zekel

40
@zekel แทนที่จะคาดเดาฉันทดสอบสิ่งนี้ (บน iOS 5.1.1) และตรวจพบอย่างแน่นอนว่ามี BOOL อยู่หรือไม่โดยขึ้นอยู่กับมูลค่าของ BOOL ที่กล่าวไว้ "objectForKey" คืนค่าศูนย์เมื่อไม่มี BOOL เนื่องจากไม่เคยตั้งค่าไว้
DataGraham

8
หากคุณมี BOOL และทดสอบด้วย boolForKey แสดงว่า @zekel ถูกต้องคุณจะได้รับใช่หรือไม่ ถ้าคุณทดสอบด้วย objectForKey (ตามคำแนะนำ) คุณจะได้รับถ้าไม่มีการตั้งค่าคีย์
Giuseppe Garassino

2
สิ่งนี้ไม่ทำงานอย่างน้อยใน iOS 6.1 Simulator objectForKey ส่งคืนค่าเดียวกันหากไม่มีอยู่และหากมีค่า BOOL เป็น NO วิธีการแก้ปัญหาของ i.jameelkhan ใช้งานได้
lschult2

98

ดังกล่าวข้างต้นมันจะไม่ทำงานสำหรับประเภทดั้งเดิมที่ 0 / NO อาจเป็นค่าที่ถูกต้อง ฉันใช้รหัสนี้

NSUserDefaults *defaults= [NSUserDefaults standardUserDefaults];
if([[[defaults dictionaryRepresentation] allKeys] containsObject:@"mykey"]){

    NSLog(@"mykey found");
}

สิ่งนี้ช่วยฉัน ขอบคุณ!
BalestraPatrick

BOOLนี่คือคำตอบที่ถูกต้องเมื่อต้องรับมือกับพื้นฐานเช่น มันถูกต้องจะแยกแยะความแตกต่างระหว่างและไม่ได้ตั้งค่าที่แตกต่างจากNO objectForKey:
devios1

@ devios1 - หากคีย์หายไปobjectForKey:จะส่งคืนnilโดยไม่คำนึงถึงความตั้งใจของโปรแกรมเมอร์ในการจัดเก็บBoolหรือชนิดข้อมูลอื่นใดในที่สุด เมื่อดั้งเดิมมีอยู่objectForKey:จะไม่ส่งคืนnilแม้ว่าคีย์จะเชื่อมโยงกับค่าดั้งเดิม
Ted Hopp

นี่คือคำตอบที่ถูกต้อง: แน่นอนว่าคำตอบที่ยอมรับนั้นผิดเนื่องจาก objectForKey สร้างความสับสนให้ 0 ด้วยศูนย์ดังนั้นจึงไม่สามารถใช้งานได้ ทดสอบสำเร็จจาก iOS 4.3 ถึง 10.2.1
Chrysotribax

ฉันรู้ว่ามันเก่า แต่มีเพียงแค่ตอนนี้ต้องการข้อมูลนี้ฉันต้องชี้ให้เห็นว่าการอ้างอิง 'containObject:' หมายถึง: วัตถุ ไม่ใช่กุญแจ IOW ในไฟล์ส่วนหัวของคุณหากคุณกำหนดไว้: #define kMyKey @ "myKey" the 'containObject' ไม่ได้มองหา 'kMyKey' มันกำลังมองหา 'myKey' การใช้ 'kMyKey' จะส่งคืน 'ไม่' เสมอ
Bill Norman

55

objectForKey:วิธีการจะกลับมาnilถ้าค่าไม่ได้อยู่ นี่คือการทดสอบ IF / TH แบบง่ายๆที่จะบอกคุณว่าค่าเป็นศูนย์หรือไม่:

if([[NSUserDefaults standardUserDefaults] objectForKey:@"YOUR_KEY"] != nil) {
    ...
}

6

" objectForKey จะคืนค่าศูนย์ถ้าไม่มีอยู่ " และจะคืนค่าศูนย์หากมีอยู่และเป็นจำนวนเต็มหรือบูลีนที่มีค่าเป็นศูนย์ (เช่น FALSE หรือ NO สำหรับบูลีน)

ฉันได้ทดสอบสิ่งนี้ในโปรแกรมจำลองสำหรับทั้ง 5.1 และ 6.1 ซึ่งหมายความว่าคุณไม่สามารถทดสอบจำนวนเต็มหรือบูลีนจริง ๆ ได้โดยตั้งคำถามว่า "วัตถุ" คุณสามารถหลีกเลี่ยงสิ่งนี้สำหรับจำนวนเต็มถ้าคุณไม่คิดว่าจะ "ไม่ได้ตั้งค่า" ราวกับว่ามันเป็น "ตั้งค่าเป็นศูนย์"

ผู้ที่ทดสอบสิ่งนี้ดูเหมือนจะถูกหลอกโดยแง่ลบที่ผิด ๆ นั่นคือการทดสอบโดยการดูว่า objectForKey คืนค่าศูนย์เมื่อคุณรู้ว่ายังไม่ได้ตั้งค่าคีย์ แต่ล้มเหลวที่จะสังเกตเห็นว่ามันคืนค่าศูนย์ด้วย ตั้งค่า แต่ตั้งค่าเป็น NO

สำหรับปัญหาของฉันเองที่ส่งฉันมาที่นี่ฉันเพิ่งจบการเปลี่ยนความหมายของบูลีนของฉันเพื่อให้ค่าเริ่มต้นที่ฉันต้องการสอดคล้องกับค่าที่ตั้งไว้เป็น NO หากไม่ใช่ตัวเลือกคุณจะต้องจัดเก็บเป็นอย่างอื่นนอกเหนือจากบูลีนและตรวจสอบให้แน่ใจว่าคุณสามารถบอกความแตกต่างระหว่าง YES, NO และ "ไม่ได้ตั้งค่า"


ฉันยืนยันสิ่งนี้แล้ว แต่มีวิธีแก้ปัญหาง่าย ๆ เพียงแค่ใช้ตัวอักษรของวัตถุใหม่หรือนิพจน์ชนิดบรรจุกล่อง @0แทน0, @NOแทนหรือเพียงNO อ่านเกี่ยวกับพวกเขาที่นี่ @(variable)
kaka

1
สายไปหน่อย แต่เพื่อประโยชน์ของมือใหม่: มันไม่ถูกต้อง object (forKey) บนค่า UserDefault ของจำนวนเต็มตั้งค่าเป็น 0 และ Bools ตั้งค่าเป็นเท็จจะส่งคืนค่าที่ไม่ใช่ศูนย์อย่างถูกต้อง หากคุณใช้บูล (forKey) เพื่อทดสอบว่ามีการตั้งค่าคุณสามารถทำงานเป็นปัญหาได้หรือไม่ (เพราะหากตั้งค่าเป็นเท็จบูล (forKey) จะส่งกลับ 'false' แม้ว่าคุณจะคาดหวังว่า 'จริง')
thecloud_of_unknowing

5

สวิฟท์ 3/4:

นี่คือส่วนขยายอย่างง่ายสำหรับชนิดคีย์ - ค่าของ Int / Double / Float / Bool ที่เลียนแบบพฤติกรรมการกลับมาของตัวเลือกประเภทอื่น ๆ ที่เข้าถึงผ่าน UserDefaults

( แก้ไข 30 ส.ค. 2018:อัปเดตด้วยไวยากรณ์ที่มีประสิทธิภาพมากขึ้นจากข้อเสนอแนะของ Leo)

extension UserDefaults {
    /// Convenience method to wrap the built-in .integer(forKey:) method in an optional returning nil if the key doesn't exist.
    func integerOptional(forKey: String) -> Int? {
        return self.object(forKey: forKey) as? Int
    }
    /// Convenience method to wrap the built-in .double(forKey:) method in an optional returning nil if the key doesn't exist.
    func doubleOptional(forKey: String) -> Double? {
        return self.object(forKey: forKey) as? Double
    }
    /// Convenience method to wrap the built-in .float(forKey:) method in an optional returning nil if the key doesn't exist.
    func floatOptional(forKey: String) -> Float? {
        return self.object(forKey: forKey) as? Float
    }
    /// Convenience method to wrap the built-in .bool(forKey:) method in an optional returning nil if the key doesn't exist.
    func boolOptional(forKey: String) -> Bool? {
        return self.object(forKey: forKey) as? Bool
    }
}

ขณะนี้พวกเขาสอดคล้องกันมากขึ้นพร้อมกับวิธีการรับอื่น ๆ (สตริงข้อมูล ฯลฯ ) เพียงใช้วิธีการรับแทนวิธีเก่า ๆ

let AppDefaults = UserDefaults.standard

// assuming the key "Test" does not exist...

// old:
print(AppDefaults.integer(forKey: "Test")) // == 0
// new:
print(AppDefaults.integerOptional(forKey: "Test")) // == nil

2
ฉันต้องการreturn self.object(forKey: key) as? Intค้นหามูลค่าเพียงครั้งเดียว
ลีโอ

3

ฉันเพิ่งจะผ่านสิ่งนี้และคำตอบทั้งหมดของคุณช่วยให้ฉันหาทางออกที่ดีสำหรับฉัน ฉันไม่ยอมไปตามเส้นทางที่แนะนำเพราะฉันพบว่ามันยากที่จะอ่านและเข้าใจ

นี่คือสิ่งที่ฉันทำ ฉันมี BOOL ถูกยกไปรอบ ๆ ในตัวแปรที่เรียกว่า "_talkative"

เมื่อฉันตั้งค่าเริ่มต้นวัตถุ (NSUserDefaults) ของฉันฉันตั้งเป็นวัตถุที่ฉันสามารถทดสอบเพื่อดูว่ามันเป็นศูนย์:

//converting BOOL to an object so we can check on nil
[defaults setObject:@(_talkative) forKey:@"talkative"];

จากนั้นเมื่อฉันไปดูว่ามีอยู่จริงฉันใช้:

if ([defaults objectForKey:@"talkative"]!=nil )
  {

จากนั้นฉันใช้วัตถุเป็นบูล:

if ([defaults boolForKey:@"talkative"]) {
 ...

ดูเหมือนว่าจะทำงานในกรณีของฉัน มันทำให้ฉันเห็นภาพมากขึ้น


สิ่งนี้ใช้ได้กับฉัน ([ค่าเริ่มต้น boolForKey: @ "talkative"]
Vineesh TP

3

ลองเสียงแตรเล็ก ๆ นี้:

-(void)saveUserSettings{
NSNumber*   value;

value = [NSNumber numberWithFloat:self.sensativity];
[[NSUserDefaults standardUserDefaults] setObject:value forKey:@"sensativity"];
}
-(void)loadUserSettings{
    NSNumber*   value;
    value = [[NSUserDefaults standardUserDefaults] objectForKey:@"sensativity"];
    if(value == nil){
        self.sensativity = 4.0;
    }else{
        self.sensativity = [value floatValue];
    }
}

ปฏิบัติต่อทุกสิ่งเป็นวัตถุ ดูเหมือนว่าจะทำงานให้ฉัน


3

รุ่นที่รวดเร็วเพื่อรับ Bool?

NSUserDefaults.standardUserDefaults().objectForKey(DefaultsIsGiver) as? Bool

1
ทำไมไม่ใช้boolForKey? NSUserDefaults.standardUserDefaults().boolForKey(DefaultsIsGiver)
JAL

1
boolForKeyจะกลับมาBoolและไม่Bool?ดังนั้นถ้าคีย์ไม่อยู่ที่นั่นคุณจะได้รับfalseและไม่nil
Ben

3

ขยายUserDefaultsหนึ่งครั้งเพื่อไม่คัดลอกวางโซลูชันนี้:

extension UserDefaults {

    func hasValue(forKey key: String) -> Bool {
        return nil != object(forKey: key)
    }
}

// Example
UserDefaults.standard.hasValue(forKey: "username")

0

ใน Swift3 ฉันได้ใช้วิธีนี้

var hasAddedGeofencesAtleastOnce: Bool {
    get {
        return UserDefaults.standard.object(forKey: "hasAddedGeofencesAtleastOnce") != nil
    }
}

คำตอบที่ดีมากถ้าคุณมีการใช้งานที่หลายครั้ง

ฉันหวังว่ามันจะช่วย :)


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