Convert NSSet to Swift Array
Core DataSwiftIos8Core Data Problem Overview
In CoreData I have defined an unordered to-many relationship. This relationship is defined in Swift like this:
@NSManaged var types : NSMutableSet
However, to use Swift at it's best, I want to use a normal Swift array like Type[]
. However, CoreData forces me to use NS(Mutable)Set
. How can I type-cast / convert the NSSet
to Array<Type>[]
?
Core Data Solutions
Solution 1 - Core Data
var set = NSSet() //NSSet
var arr = set.allObjects //Swift Array
var nsarr = set.allObjects as NSArray //NSArray
Solution 2 - Core Data
As of Xcode 7.2 with Swift 2.1.1
Actually, I found out by trial that:
@NSManaged var types : Set<Type>
Works perfectly fine.
The fact is that CoreData generates somethink like:
@NSManaged var types : NSSet
when creating a NSManagedObject
subclass from the editor. So I was wondering if there was a not very verbose method to use the filter
method without casting. But then Swift is supposed to bridge automatically between NSSet, NSArray and their counterparts. So I tried declaring it directly as a Set and it works.
Answering the question, converting it to an Array becomes trivial:
Array(types)
Solution 3 - Core Data
This is how i did it:
` let array = object.NSSet?.allObjects as! [ArrayType] `
Then you can manipulate the array as normal:
for item in array { id = item.id }
Solution 4 - Core Data
Use map to get array like this:
extension NSSet {
func toArray<T>() -> [T] {
let array = self.map({ $0 as! T})
return array
}
}
...
let myArray: [MyType] = set.toArray()
Solution 5 - Core Data
This answer is outdated as of Xcode 7.2/Swift 2.1. See the accepted answer for an updated answer.
I'm currently using obj.types.allObjects as Type[]
, but that feels like a hack/workaround.
Solution 6 - Core Data
You can also use .sortedArray to sort the elements.
Swift 3:
yourNSSetType?.sortedArray(using: [NSSortDescriptor(key: "keyToSortBy", ascending: true, selector: #selector(NSNumber.compare(_:)))]) as! [yourNSSetType]
For strings, use NSString.compare in the #selector call.
Solution 7 - Core Data
Thanks to @David for his solution I had the same situation In my current project, we still use Objective C with swift bridging for the coredata modules so in my case, I had to use the following as compiler can't intervene what is the Generic Type to convert i had to pass it with using actually :(
extension Set {
func toArray<S>(_ of: S.Type) -> [S] {
let array = self.map({$0 as! S})
return array
}
}
and using:
Items?.toArray(XYZ.self)
in my Managed object; variable was like this for reference
@property (nullable, nonatomic, retain) NSSet<XYZ *> * items;