1

In my case UserDefaults.standard.object() always returns nil. I don't understand why. Please, help. I use swift 4.2 and Xcode 9.x. My project has multiple files: swift and objC. If I set value from objC code (NSUserDefaults...), then all works fine. Value exist.

My class B at Swift-file:

import Foundation
@objc class Preferences : NSObject{

    /**
     Сохранение в локальном хранилище данных
     :param: key ключ (название параметра
     :param: value значение - любой тип данных
     */
    public static func saveValue (key:String, value:Any) -> (){
        UserDefaults.standard.set(value, forKey: key)
        UserDefaults.standard.synchronize()
    }

    /**
     Получить данные из локального хранилища
     :param: key ключ (название параметра)
     :returns: Any значение - любой тип данных
     */
    public static func getValue (key:String) -> (Any?){
        let val = UserDefaults.standard.object(forKey: key)
        return val // ------- always NIL
//        if let type1 = val as? String{
//            return type1
//        }else if let type2 = val as? Int{
//            return type2
//        }else if let type3 = val as? Double{
//            return type3
//        }else{
//            return val;
//        }
    }
}

From objC class I calling first swift-func.

objC (check values):

if (![[Preferences getValueWithKey:@"surname_"] isEqualToString:@""]){
    [surnameF setText:[Preferences getValueWithKey:@"surname_"]];
    [nameF setText:[Preferences getValueWithKey:@"name_"]];
    [patronymicF setText:[Preferences getValueWithKey:@"patronymic_"]];
}

objC (set values by calling swift-class):

[DataManager saveDataWithSurname:surname name:name patronymic:patronymic];

Class A at Swift-file:

@objc class DataManager : NSObject{

public static func saveData(surname: String, name: String, patronymic: String){
    //Сохранить локально
    Preferences.saveValue(key: surname, value1: "surname_")
    Preferences.saveValue(key: name, value1: "name_")
    Preferences.saveValue(key: patronymic, value1: "patronymic_")

    let sCommand = SimpleCommand()
    sCommand.command = "setUserData"
    var userData = [String:String]()
    userData["user_surname"] = surname
    userData["user_name"] = name
    userData["user_patronymic"] = patronymic
    sCommand.params["userData"] = userData

    NetHelper.sendJSONPureRequest(
        sCommand: sCommand,
        onSuccess: { (sAnswer) in
            EasyDialog.showAlert(title: "Уведомление", message: sAnswer.messageText!)
    }) { (errMsg) in
        EasyDialog.showAlert(title: "Ошибка", message: errMsg)
    }
}
РСИТ _
  • 325
  • 1
  • 14

4 Answers4

0

As the discussion of func set(_ value: Any?, forKey defaultName: String):

The value parameter can be only property list objects: NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary. For NSArray and NSDictionary objects, their contents must be property list objects.

So a default object must be a property list - that is, an instance of (or for collections, a combination of instances of) NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary. If you want to store any other type of object, you should typically archive it to create an instance of NSData.

Try the solution here.

Đinh Quân
  • 71
  • 2
  • 8
0

Stupid mistake:

public static func saveData(surname: String, name: String, patronymic: String){
    //Сохранить локально
    Preferences.saveValue(key: surname, value1: "surname_")
    Preferences.saveValue(key: name, value1: "name_")
    Preferences.saveValue(key: patronymic, value1: "patronymic_")

Key <-> Value. :)

РСИТ _
  • 325
  • 1
  • 14
0

Swift 5 Very Easy Way

Attempt to set a non-property-list object as an NSUserDefaults

https://stackoverflow.com/questions/19720611/attempt-to-set-a-non-property-list-object-as-an-nsuserdefaults/56625605#56625605
Shakeel Ahmed
  • 5,361
  • 1
  • 43
  • 34
-1

You should return simple object instead of closure. Also,synchronize will be deprecated and you can remove it.

Try this fixed code.

public static func saveValue (key: String, value: Any) {
    UserDefaults.standard.set(value, forKey: key)
}

public static func getValue (key:String) -> Any? {
    let val = UserDefaults.standard.object(forKey: key)
    return val
}
Vadim Kozak
  • 420
  • 3
  • 11
  • OP is not returning a closure. He is returning a single element tuple, which basically means he is returning an object of that type. – Losiowaty Sep 17 '18 at 18:13
  • I get "nil" already on line `let val = UserDefaults.standard.object(forKey: key)`. And function returns single object. Thanks for answer! – РСИТ _ Sep 17 '18 at 18:22
  • How you set this? I just checked code with strings and works good, could you provide an example of usage? – Vadim Kozak Sep 17 '18 at 18:25
  • 5 minutes ago I was try to save value from another class and all saves fine. So, I have ***class A*** with `public static func saveFullData` which calls static func from ***class B*** (`public static func saveValue (key:String, value:Any) -> ()`) where I try to save value at UserDefaults. And I can't save it in ***class B*** – РСИТ _ Sep 17 '18 at 18:27
  • But I already try to change funcs from ***class B*** to non-static and no results. Maybe it's not working because I call func of ***class A*** from objC code and after that this func call ***class B***' funcs? – РСИТ _ Sep 17 '18 at 18:31