Issue with storing NSCoding object in userdefaults

Hi all. I need to save an array of strings in userdefaults. I am using

NSKeyedArchiver.archivedData(withRootObject: rootObject, requiringSecureCoding: false) 

to convert array of string to data and then save it in userdefaults.

Inorder to retrieve the data back, I am using

let data = self.userDefaults.data(forKey: "key")!
let unarchiver = try NSKeyedUnarchiver(forReadingFrom: data)
unarchiver.requiresSecureCoding = false
let array =  unarchiver.decodeObject(forKey: NSKeyedArchiveRootObjectKey) as? NSObject

This was working perfectly till iOS 18. From iOS 18 in couple of devices, we are getting empty string array while we retrieve the value back from userdefaults. We observed this in an iPhone 12 pro and iPhone 15 running on iOS 18. iPhone 12 pro is facing this issue almost once everyday. In iPhone 15 this happens once in 2-3 days.

Tried printing raw data directly from userdefaults. And I can see some data available. But when we convert that back to array of string, I am getting empty. Tried adding logs in catch block. But couldn't get any. What might be the cause of this issue?

Answered by DTS Engineer in 830145022

Using NSCoding for this is an odd choice. UserDefaults supports all property list types, and those include Array and String. So you can do this using:

import Foundation

func main() {
    let saved = ["Hello", "Cruel!", "World!"]
    UserDefaults.standard.set(saved, forKey: "greeting")
    let loaded = UserDefaults.standard.object(forKey: "greeting") as? [String]
    print(loaded)
    // prints: Optional(["Hello", "Cruel!", "World!"])
}

main()

I’d advise you to use this approach going forward.

Which leaves us with the question of how to help the users having this problem. How important are these strings? Can you just have the affected users set them up again? If so, doing that is gonna be the easiest option.

If not, you’ll need to figure out why your current code is failing. That could be tricky.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Using NSCoding for this is an odd choice. UserDefaults supports all property list types, and those include Array and String. So you can do this using:

import Foundation

func main() {
    let saved = ["Hello", "Cruel!", "World!"]
    UserDefaults.standard.set(saved, forKey: "greeting")
    let loaded = UserDefaults.standard.object(forKey: "greeting") as? [String]
    print(loaded)
    // prints: Optional(["Hello", "Cruel!", "World!"])
}

main()

I’d advise you to use this approach going forward.

Which leaves us with the question of how to help the users having this problem. How important are these strings? Can you just have the affected users set them up again? If so, doing that is gonna be the easiest option.

If not, you’ll need to figure out why your current code is failing. That could be tricky.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Issue with storing NSCoding object in userdefaults
 
 
Q