Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to covert NSMutableOrderedSet to generic array?

I have this for loop, p is a NSManagedObject, fathers is a to-many relationship, so I need to cast NSMutableOrderedSet to [Family] but it does not work, why?

for f in p.fathers as [Family] {
}

enter image description hereenter image description here

like image 618
János Avatar asked Nov 22 '14 11:11

János


2 Answers

You can obtain an array representation of the set via the array property - then you can downcast it to the proper type and assign to a variable:

let families = p.fathers.array as [Family]

but of course you can also use it directly in the loop:

for f in p.fathers.array as [Family] {
    ....
}

Update

A forced downcast is now required using the ! operator, so the code above should be:

let families = p.fathers.array as! [Family]
like image 76
Antonio Avatar answered Nov 07 '22 15:11

Antonio


The simple solution by Antonio should be used in this case. I'd just like to discuss this a bit more. If we try to enumerate an instance of 'NSMutableOrderedSet' in a 'for' loop, the compiler will complain:

error: type 'NSMutableOrderedSet' does not conform to protocol 'SequenceType'

When we write

for element in sequence {
    // do something with element
}

the compiler rewrites it into something like this:

var generator = sequence.generate()

while let element = generator.next() {
    // do something with element
}

'NS(Mutable)OrderedSet' doesn't have 'generate()' method i.e. it doesn't conform to the 'SequenceType' protocol. We can change that. First we need a generator:

public struct OrderedSetGenerator : GeneratorType {

    private let orderedSet: NSMutableOrderedSet

    public init(orderedSet: NSOrderedSet) {
        self.orderedSet = NSMutableOrderedSet(orderedSet: orderedSet)
    }

    mutating public func next() -> AnyObject? {
        if orderedSet.count > 0 {
            let first: AnyObject = orderedSet.objectAtIndex(0)
            orderedSet.removeObjectAtIndex(0)
            return first
        } else {
            return nil
        }
    }
}

Now we can use that generator to make 'NSOrderedSet' conform to 'SequenceType':

extension NSOrderedSet : SequenceType {
    public func generate() -> OrderedSetGenerator {
        return OrderedSetGenerator(orderedSet: self)
    }
}

'NS(Mutable)OrderedSet' can now be used in a 'for' loop:

let sequence = NSMutableOrderedSet(array: [2, 4, 6])

for element in sequence {
    println(element) // 2 4 6
}

We could further implement 'CollectionType' and 'MutableCollectionType' (the latter for 'NSMutableOrderedSet' only) to make 'NS(Mutable)OrderedSet' behave like Swift's standard library collections.

Not sure if the above code follows the best practises as I'm still trying to wrap my head around details of all these protocols.

like image 37
Ivica M. Avatar answered Nov 07 '22 14:11

Ivica M.