NSUserDefaults - Cách nhận biết khóa có tồn tại không


208

Tôi đang làm việc trên một ứng dụng iPhone nhỏ và tôi đang sử dụng NSUserDefaultsnhư dữ liệu của mình. Nó chỉ phải theo dõi một vài điều, chẳng hạn như một số tên và một số con số để tôi có thể giữ cho nó đơn giản.

Tôi tìm thấy trang này để tham khảo, nhưng tôi không nghĩ nó có thể trả lời câu hỏi của tôi. Về cơ bản, tôi muốn có thể kiểm tra xem một giá trị (hoặc khóa) đã tồn tại trong NSUserDefaultsvà sau đó thực hiện một cái gì đó cho phù hợp.

Một số ví dụ: Ứng dụng khởi động, nếu đây là lần đầu tiên nó khởi động, nó sẽ đưa ra thông báo chào mừng. Để biết đây có phải là lần đầu tiên nó mở hay không, hãy đọc UserDefaultsvà kiểm tra.

Ví dụ 2: Nó nói, "Xin chào [Tên]", trong đó Tên là thứ bạn đã nhập. Nếu bạn đã mở ứng dụng và không có tên, nó sẽ hiện "Xin chào thế giới". Tôi cần kiểm tra xem bạn đã nhập tên chưa và hành động tương ứng. Tên sẽ được lưu trữ trong NSUserDefaults.

Một số giúp đỡ ở đây? Tôi thực sự đánh giá cao nó!

Câu trả lời:


381

objectForKey:sẽ trở lại nilnếu nó không tồn tại.


1
Tôi không nghĩ bạn có thể lưu trữ một kiểu dữ liệu nguyên thủy trong NSUserDefaults.
kender

12
Các tài liệu của Apple nói rằng "Nếu giá trị boolean được liên kết với defaultName trong mặc định của người dùng, giá trị đó được trả về. Nếu không, NO được trả về." Tôi không nghĩ câu trả lời trên là chính xác cho BOOL, bạn không thể xác định liệu nó được xác định KHÔNG hay không tồn tại. Tôi nghĩ rằng bạn phải sử dụng – dictionaryRepresentationvà kiểm tra chìa khóa.
zekel

40
@zekel Thay vì đoán, tôi đã thử nghiệm điều này (trên iOS 5.1.1) và nó chắc chắn đã phát hiện xem có phải là một BOOL hay không, không phụ thuộc vào giá trị của BOOL nói trên. "objectForKey" trở về con số không khi BOOL không có mặt vì nó chưa bao giờ được đặt.
DataGraham

8
Nếu bạn có BOOL và kiểm tra nó bằng boolForKey, thì @zekel đúng, bạn nhận được CÓ hoặc KHÔNG. Nếu bạn kiểm tra nó bằng objectForKey (như câu trả lời gợi ý), bạn sẽ nhận được nếu không đặt khóa.
Giuseppe Garassino

2
Điều này không còn hoạt động ít nhất là kể từ iOS 6.1 Simulator. objectForKey trả về cùng một giá trị nếu nó không có mặt và nếu nó hiện diện với BOOL là NO. Giải pháp của i.jameelkhan không hoạt động
lschult2

98

Như đã đề cập ở trên, nó sẽ không hoạt động đối với các kiểu nguyên thủy trong đó 0 / NO có thể là một giá trị hợp lệ. Tôi đang sử dụng mã này.

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

    NSLog(@"mykey found");
}

Điều này đã cứu tôi. Cảm ơn!
BalestraPatrick

Đây là câu trả lời đúng khi làm việc với người nguyên thủy như thế nào BOOL. Nó sẽ phân biệt chính xác giữa NOvà không được thiết lập, không giống như objectForKey:.
devios1

@ devios1 - Nếu khóa bị thiếu, objectForKey:sẽ trả về nilbất kể ý định của lập trình viên cuối cùng là lưu trữ một Boolhoặc bất kỳ loại dữ liệu nào khác. Khi có một nguyên thủy, objectForKey:không trả về nilngay cả khi khóa được liên kết với một giá trị nguyên thủy.
Ted Hopp

Đây là câu trả lời đúng: rõ ràng, câu trả lời được chấp nhận là sai vì objectForKey nhầm 0 với nil, vì vậy nó không hoạt động. Đã thử nghiệm thành công từ iOS 4.3 đến 10.2.1
Chrysotribax

Tôi biết điều này đã cũ, nhưng chỉ cần có thông tin này bây giờ, tôi cần chỉ ra rằng tham chiếu 'chứaObject:' chỉ có nghĩa là: đối tượng. KHÔNG phải là chìa khóa. IOW, trong tệp tiêu đề của bạn nếu bạn đã xác định: #define kMyKey @ "myKey", 'chứaObject' không tìm kiếm 'kMyKey', nó đang tìm kiếm 'myKey'. Sử dụng 'kMyKey' sẽ luôn trả về 'KHÔNG.'
Bill Norman

55

Các objectForKey:phương pháp sẽ trở lại nilnếu giá trị không tồn tại. Đây là một thử nghiệm IF / THEN đơn giản sẽ cho bạn biết nếu giá trị là 0:

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

6

" ObjectForKey sẽ trả về nil nếu nó không tồn tại. " Nó cũng sẽ trả về nil nếu nó tồn tại và nó là số nguyên hoặc boolean có giá trị bằng 0 (ví dụ FALSE hoặc NO cho boolean).

Tôi đã thử nghiệm điều này trong trình giả lập cho cả 5.1 và 6.1. Điều này có nghĩa là bạn không thể thực sự kiểm tra các số nguyên hoặc booleans đã được đặt bằng cách yêu cầu "đối tượng". Bạn có thể thoát khỏi điều này đối với số nguyên nếu bạn không quan tâm đến việc "không được đặt" như thể nó được "đặt thành không".

Những người đã kiểm tra điều này dường như đã bị đánh lừa bởi khía cạnh tiêu cực sai, tức là kiểm tra điều này bằng cách xem liệu objectForKey có trả về không khi bạn biết khóa chưa được đặt nhưng không nhận thấy rằng nó cũng trả về nil nếu khóa đã được đặt nhưng đã được đặt thành NO.

Đối với vấn đề của riêng tôi, điều đó đã gửi tôi đến đây, cuối cùng tôi đã thay đổi ngữ nghĩa của boolean để mặc định mong muốn của tôi phù hợp với giá trị được đặt thành NO. Nếu đó không phải là một tùy chọn, bạn sẽ cần lưu trữ dưới dạng boolean và đảm bảo rằng bạn có thể cho biết sự khác biệt giữa CÓ, KHÔNG và "không được đặt".


Tôi đã xác nhận điều này, nhưng có một giải pháp dễ dàng; chỉ cần sử dụng các đối tượng mới bằng chữ hoặc một biểu thức đóng hộp. @0thay vì 0, @NOthay vì NO, hoặc đơn giản @(variable). Đọc về họ ở đây.
kaka

1
Một chút muộn màng, nhưng vì lợi ích của người mới: điều này không chính xác. đối tượng (forKey) trên các giá trị UserDefault của các số nguyên được đặt thành 0 và Bools được đặt thành false, sẽ trả về chính xác không phải là số không. Nếu bạn sử dụng bool (forKey) để kiểm tra xem giá trị có được đặt hay không, bạn có thể gặp sự cố (vì nếu giá trị được đặt thành Sai, bool (forKey) sẽ trả về 'false', mặc dù bạn đang mong đợi 'true'.)
thecloud_of_unknowing

5

Swift 3/4:

Dưới đây là một tiện ích mở rộng đơn giản cho các loại giá trị khóa Int / Double / Float / Bool bắt chước hành vi trả về tùy chọn của các loại khác được truy cập thông qua UserDefaults.

( Chỉnh sửa ngày 30 tháng 8 năm 2018: Được cập nhật với cú pháp hiệu quả hơn từ đề xuất của 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
    }
}

Bây giờ chúng phù hợp hơn với các phương thức get tích hợp khác (chuỗi, dữ liệu, v.v.). Chỉ cần sử dụng các phương thức get thay cho những cái cũ.

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
Tôi muốn return self.object(forKey: key) as? Inttìm kiếm giá trị chỉ một lần.
Leo

3

Tôi vừa trải qua điều này, và tất cả các câu trả lời của bạn đã giúp tôi hướng tới một giải pháp tốt, cho tôi. Tôi chống lại việc đi theo tuyến đường được đề xuất bởi, chỉ vì tôi thấy khó đọc và hiểu.

Đây là những gì tôi đã làm. Tôi đã có một BOOL được mang theo trong một biến gọi là "_talkative".

Khi tôi đặt đối tượng mặc định (NSUserDefaults), tôi đặt nó làm đối tượng, sau đó tôi có thể kiểm tra xem nó có phải là không:

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

Sau đó, khi tôi đi xem nó có tồn tại không, tôi đã sử dụng:

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

Sau đó, tôi đã sử dụng đối tượng như một BOOL:

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

Điều này dường như làm việc trong trường hợp của tôi. Nó chỉ làm cho ý nghĩa thị giác hơn với tôi.


Điều này làm việc cho tôi ([mặc định boolForKey: @ "nói chuyện"]
Vineesh TP

3

Hãy thử cái thùng nhỏ này:

-(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];
    }
}

Coi mọi thứ như một đối tượng Dường như làm việc cho tôi.


3

Phiên bản Swift để có được Bool?

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

1
Tại sao không sử dụng boolForKey? NSUserDefaults.standardUserDefaults().boolForKey(DefaultsIsGiver)
JAL

1
boolForKeysẽ trở lại Boolvà không Bool?, vì vậy nếu không có chìa khóa, bạn sẽ nhận được falsevà khôngnil
Ben

3

Mở rộng UserDefaultsmột lần để không sao chép-dán giải pháp này:

extension UserDefaults {

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

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

0

Trong Swift3, tôi đã sử dụng theo cách này

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

Câu trả lời là tuyệt vời nếu bạn sử dụng nhiều lần.

Tôi hy vọng nó sẽ giúp :)


-1

Swift 3.0

if NSUserDefaults.standardUserDefaults().dictionaryRepresentation().contains({ $0.0 == "Your_Comparison_Key" }){
                    result = NSUserDefaults.standardUserDefaults().objectForKey(self.ticketDetail.ticket_id) as! String
                }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.