11901

UserDefaults between Objective-C and Swift

Just trying to be extra careful here...

If I have an app that saved a value in UserDefaults like this in Objective-C:

NSString *newString = textField.text; [[NSUserDefaults standardUserDefaults] setObject: newString forKey:@"textKey"];

Would this be the proper way of checking whether this value exists when I release an update to the app that is now coded in Swift:

if (UserDefaults.standard.object(forKey: "textKey") as? String) != nil { print("There is a string") } else { print("No string exists") }

I try to use .string(forKey:) and .bool(forKey:) since they've been introduced, but is it safest since this was saved as an object to pull it out as an object and then test it with "as? String"?

Trickier version of the same question:

An NSMutableArray of NSDictionary objects was saved as an object in UserDefaults

if let oldData = UserDefaults.standard.object(forKey: "theData") as? [NSMutableDictionary] { }

Will NSDictionary and NSMutableDictionary be interchangeable here?

Thanks!

Answer1:

[NS]UserDefaults is backed by a plist and a dictionary. The Objective-C string was saved to the plist as a <string>Some Text</string>.

That same plist loaded in Swift gives a string for that key.

So you should have no issue using UserDefaults.string to read the value stored with Objective-C. Of course you still need to verify the value actually exists.

if let str = UserDefaults.standard.string(forKey: "textKey") { print("Found \(str)") } else { print("No string for key") }

Even if the original value isn't a string, using UserDefault.string is safe. It will simply return nil for non-string values.

With regard to NSDictionary and NSMutableDictionary, note that UserDefaults only retrieves immutable NSDictionary. You can't read an NSMutableDictionary (or array) from UserDefaults.

Note you can safely use a Swift dictionary to read the original NSDictionary. No need to use Objective-C classes.

Answer2:

Yes your solution is safe, if the value you saved in the Objective C code is indeed a String type than, when you retrieve that value from NSUserDefaults, it will be a String and will correctly be coerced to a String by the ? operator of your Swift code.

Answer3:

The recommended way (in Swift and Objective-C) is to register each key value pair to provide a default value. This default value is considered until the value is changed the first time.

let userDefaults = UserDefaults.standard let defaultValues : [String : Any] = ["textKey" : "", "dictionaryKey" : [:]] userDefaults.register(defaults: defaultValues)

Now you can safely write

if UserDefaults.standard.string(forKey: "textKey")!.isEmpty { print("No string exists") } else { print("There is a string") }

Of course the developer is responsible for overwriting a value with the same type.

<hr>

NSMutableDictionary is not related to Swift Dictionary. To get a mutable object just use the var keyword.

var dictionary = UserDefaults.standard.object(forKey: "dictionaryKey") as! [String:Any]

Recommend

  • Getting an FLV from YouTube in .NET
  • how to remove component from JTextPane
  • Sorting an ArrayList by the third element in the ArrayList
  • Check if an array of custom objects contains an object with a certain date
  • Weird UIView coordinate issue
  • Unable to extract string using NSRegularExpression (regex pattern) - iphone
  • Newtonsoft inline formatting for subelement while serializing
  • Encoding issue with ASIHttpRequest
  • Generate a unique string based on a pair of strings
  • Deleting a widget from QTableView
  • multidatatrigger with multibinding in ControlTemplate.Triggers
  • Is there a parser equivalent of 'fragment' marking in ANTLR4?
  • didUpdatePushCredentials not get called
  • Build Successful but not running on simulator
  • how to save the state in userdefaults of accessory checkmark-iphone
  • How to change the font size of a single index for UISegmentedControl?
  • Django rest serializer Breaks when data exists
  • Is it possible to access block's scope in method?
  • Checking free space on FTP server
  • Can I check if a recipient has an automatic reply before I send an email?
  • Ajax Loaded meta Tags
  • Xamarin Forms - UWP Fonts
  • Display issues when we change from one jquery mobile page to another in firefox
  • Deselecting radio buttons while keeping the View Model in synch
  • Deserializing XML into class C#
  • JSON with duplicate key names losing information when parsed
  • Arrow is showed instead of the material design version hamburger icon. Why doesn't syncState in
  • Jquery - Jquery Wysiwyg return html as a string
  • align graphs with different xlab
  • Return words with double consecutive letters
  • AT Commands to Send SMS not working in Windows 8.1
  • Arrays break string types in Julia
  • Windows forms listbox.selecteditem displaying “System.Data.DataRowView” instead of actual value
  • How to include full .NET prerequisite for Wix Burn installer
  • apache spark aggregate function using min value
  • Sorting a 2D array using the second column C++
  • costura.fody for a dll that references another dll
  • Reading document lines to the user (python)
  • Python/Django TangoWithDjango Models and Databases
  • jQuery Masonry / Isotope and fluid images: Momentary overlap on window resize