Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I specialize an NSSet in Swift?

Tags:

swift

So as of xcode 7 the foundation collections are generics which is great so you can do this in ObjC:

NSSet<NSString *> *foo = [[NSSet alloc] initWithArray:@[]];

But if you try to specialize the NSSet in Swift:

let foo:NSSet<String> = NSSet(array: [])

You get this: Cannot specialize non-generic type 'NSSet'

Now, I know Swift has a Set class as well that is generic and bridges to NSSet, but I am doing this for NSManagedObject subclasses so I need to support NSOrderedSet as well and there is no ordered set in Swift yet.

My question is, is this intentional or is this an oversight? Is there any reason NSSet wouldn't be exposed as a generic class in Swift but would be in ObjC?

like image 218
Keith Norman Avatar asked Sep 18 '15 18:09

Keith Norman


People also ask

What's a difference between NSArray and NSSet?

An NSSet is much like an NSArray, the only difference is that the objects it holds are not ordered. So when you retrieve them they may come back in any random order, based on how easy it is for the system to retrieve them.

What is NSSet in Swift?

NSSet declares the programmatic interface for static sets of distinct objects. You establish a static set's entries when it's created, and can't modify the entries after that. NSMutableSet , on the other hand, declares a programmatic interface for dynamic sets of distinct objects.

Is NSMutableSet ordered?

NSSet is an unordered collection. It has no idea what the "order" of its objects are.


1 Answers

As the documentation says:

All NSSet objects can be bridged to Swift sets, so the Swift compiler replaces the NSSet class with Set<AnyObject> when it imports Objective-C APIs.

So, as matt already said with other words in his answer, NSSet inside the Swift language is identical to Set<AnyObject>, and is not the same thing as NSSet in the current version of Objective-C language, even if they have the same name.

Continuing to cite the documentation:

You can also create an NSSet object directly from a Swift array literal, following the same bridging rules outlined above. When you explicitly type a constant or variable as an NSSet object and assign it an array literal, Swift creates an NSSet object instead of a Swift set.

In other words, it creates an object of type Set<AnyObject>, and this is the reason of the error given by the Swift compiler (NSSet is not generic since it correspond to the generic NSSet in Object-C, but already instantiated on the type AnyObject).

What you can do is to write something like:

let foo = NSSet(array: ["one", "two", "three"])

// foo has now the type NSSet<AnyObject>, which corresponds to Set<AnyObject>

let bar = foo as! Set<String>

// bar has now the type Set<String>, which has no correspondent as NSSet<...> in Swift
like image 173
Renzo Avatar answered Sep 24 '22 02:09

Renzo