Convert NSSet to Swift Array

Core DataSwiftIos8

Core 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;

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionBoukeView Question on Stackoverflow
Solution 1 - Core DataConnorView Answer on Stackoverflow
Solution 2 - Core DataFranMowinckelView Answer on Stackoverflow
Solution 3 - Core DataDanielView Answer on Stackoverflow
Solution 4 - Core DataDavid.Chu.caView Answer on Stackoverflow
Solution 5 - Core DataBoukeView Answer on Stackoverflow
Solution 6 - Core DatamcfroobView Answer on Stackoverflow
Solution 7 - Core DataAmr AngryView Answer on Stackoverflow