Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSUserDefaults returns swift array [String] instead of Set<String>

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?

like image 513
aporat Avatar asked Jan 07 '23 06:01

aporat


1 Answers

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
like image 164
deadbeef Avatar answered Jan 09 '23 19:01

deadbeef