4

I'm storing a set of strings (Set<String>) into a NSUserDefaults.standardUserDefaults() and when retrieving back the object, it comes back as an array of strings instead of a set.

This block works, as I'm recreating the array as a NSSet

if let products = NSUserDefaults.standardUserDefaults().objectForKey("products") as? [String] {

   // recreate the array into a NSSet / Set
   if let productSet = NSSet(array: products) as? Set<NSObject> {
     // now it's a set 
   }

}

However, it's not possible to get the object directly as a swift Set:

if let products = NSUserDefaults.standardUserDefaults().objectForKey("products") as? Set<String> {
   // will not cast into Set<String>
}

I assume NSUserDefaults coverts set into an array internally? Is there a way to receive the items as a set and not an array?

6
  • 2
    According to the documentation, a user defaults object must be an instance or a combination of NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary. How did you store a Set? Commented Oct 27, 2015 at 18:56
  • Convert anything in NSData and on retrieval type cast it to whatever you want when originally converted Commented Oct 27, 2015 at 18:58
  • 2
    NSUserDefaults.standardUserDefaults().setObject(Set(["a", "b"]), forKey: "products") throws a runtime exception. Without seeing how you set the defaults it is impossible to give a (helpful) answer. Commented Oct 27, 2015 at 18:59
  • I'm getting the data as a JSON object and store it with NSUserDefaults.standardUserDefaults().setValuesForKeysWithDictionary(response) Commented Oct 27, 2015 at 19:01
  • JSON objects have arrays, dictionaries, strings, numbers, but no sets. Commented Oct 27, 2015 at 19:02

1 Answer 1

9

Short answer : No

NSUserDefaults cannot store sets. It's documented that way and it's because of the limitations of the format used to store the data on disk.

If saving a set works for you and automatically converts it to an array, you're actually lucky as I don't think this is a documented behavior and it should just throw an error.
EDIT : It doesn't work and you should not try it.

The best practice is to convert it to an array before saving and convert it back to a set after retrieving. You could also write a category on NSUserDefaults that does that automatically. Here is an example with objective-C :

//
//  NSUserDefaults+SetAdditions.h
//

#import <Foundation/Foundation.h>

@interface NSUserDefaults (SetAdditions)

- (NSSet *)setForKey:(NSString *)defaultName;
- (void)setSet:(NSSet *)set forKey:(NSString *)defaultName;

@end


//
//  NSUserDefaults+SetAdditions.m
//

#import "NSUserDefaults+SetAdditions.h"

@implementation NSUserDefaults (SetAdditions)

- (NSSet *)setForKey:(NSString *)defaultName
{
    NSArray *array = [self arrayForKey:defaultName];
    if (array) {
        return [NSSet setWithArray:array];
    } else {
        return nil;
    }
}

- (void)setSet:(NSSet *)set forKey:(NSString *)defaultName
{
    if (set) {
        [self setObject:[set allObjects] forKey:defaultName];
    } else {
        [self setObject:nil forKey:defaultName];
    }
}

@end
Sign up to request clarification or add additional context in comments.

2 Comments

As stated above, saving a set does not work and does not automatically convert to an array.
@MartinR Edited my answer. That's what I thought too.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.