Add 'For...In' Support to a Class in Swift 2

Add 'for...in' support to a class in Swift 2

There are just two changes:

  • GeneratorOf is now called AnyGenerator.

  • GeneratorOf.init(next:) is now a function anyGenerator()

That gives us:

class Cars : SequenceType {   
var carList : [Car] = []

func generate() -> AnyGenerator<Car> {
// keep the index of the next car in the iteration
var nextIndex = carList.count-1

// Construct a GeneratorOf<Car> instance, passing a closure that returns the next car in the iteration
return anyGenerator {
if (nextIndex < 0) {
return nil
}
return self.carList[nextIndex--]
}
}
}

(I've edited the linked answer to match Swift 2 syntax.)

Add for in support to iterate over Swift custom classes

Say you have a class "Cars" that you want to be able to iterate over using a for..in loop:

let cars = Cars()

for car in cars {
println(car.name)
}

The simplest way is to use AnyGenerator with the classes like this:

class Car {
var name : String
init(name : String) {
self.name = name
}
}

class Cars : SequenceType {

var carList : [Car] = []

func generate() -> AnyGenerator<Car> {
// keep the index of the next car in the iteration
var nextIndex = carList.count-1

// Construct a AnyGenerator<Car> instance, passing a closure that returns the next car in the iteration
return anyGenerator {
if (nextIndex < 0) {
return nil
}
return self.carList[nextIndex--]
}
}
}

To try a complete working sample add the two classes above and then try to use them like this, adding a couple of test items:

    let cars = Cars()

cars.carList.append(Car(name: "Honda"))
cars.carList.append(Car(name: "Toyota"))

for car in cars {
println(car.name)
}



That's it, simple.

More info: http://lillylabs.no/2014/09/30/make-iterable-swift-collection-type-sequencetype

support for-each in custom class swift

The answer for calling from objective-c with for-each to swift class,
is by changing the Array to NSArray and implement NSFastEnumeration.

@objcMembers public class FeedItemsCollection:NSObject,NSFastEnumeration,Sequence
{
//private var feedItems:[FeedItem]
private var feedItems:NSMutableArray

public init(feedItems :NSMutableArray)
{
self.feedItems = feedItems
}
public func makeIterator() ->NSFastEnumerationIterator
{
return NSFastEnumerationIterator(self)
}
public func countByEnumerating(with state: UnsafeMutablePointer<NSFastEnumerationState>, objects buffer: AutoreleasingUnsafeMutablePointer<AnyObject?>, count len: Int) -> Int {

return self.feedItems.countByEnumerating(with: state, objects: buffer, count: len);
}

}

and the objective-c code that call for-each loop

   self.feedItemsCollection = [[FeedItemsCollection alloc] initWithFeedItems:entities];

for(FeedItem * feedItem in self.feedItemsCollection)
{
NSLog(@"feedItem-title = %@", feedItem.title);
}

Using AnyGenerator with Swift 2.2+ (for in loop support for custom classes)

(I assume that your code refers to struct ScalarString
from Working with Unicode code points in Swift.)

You can do a Swift 2.2+ compatible "increment index after determining
the return value" with defer:

func generate() -> AnyGenerator<UInt32> {

var nextIndex = 0

return AnyGenerator {
if nextIndex >= self.scalarArray.count {
return nil
}
defer {
nextIndex += 1
}
return self.scalarArray[nextIndex]
}
}

In your special case however, it would be easier to just
forward the generator of the

private var scalarArray: [UInt32] = []

property, either directly:

func generate() -> IndexingGenerator<[UInt32]> {
return scalarArray.generate()
}

or as a type-erased generator which forwards the next() method
to the array generator:

func generate() -> AnyGenerator<UInt32> {
return AnyGenerator(scalarArray.generate())
}

Adding support for the range operator in swift? (e.g. for x in red...violet)

(Note that this is Swift 3. If you want Swift 2.2, see Senseful's answer, which is basically the same with the old protocols.)

You want Color to be Strideable with a Stride of Int. Then you get ... and ..< for free. Let's do that.

First, I'm going to assume your type is something like this. This is just an example. You could do all kinds of things, as long as you can implement Strideable. You seem to want structs rather than enums (which is fine), so let's do structs. That just means other colors could be added by anyone and you have to consider that in your design. Colors need something to distinguish them, so we'll give them a name. If they were classes, then that would also allow them to be distinguished.

struct Color {
let name: String

static let red = Color(name: "red")
static let orange = Color(name: "orange")
static let yellow = Color(name: "yellow")
static let green = Color(name: "green")
static let blue = Color(name: "blue")
static let indigo = Color(name: "indigo")
static let violet = Color(name: "violet")
}

First rule of Strideable is Equatable.

extension Color: Equatable {
static func == (lhs: Color, rhs: Color) -> Bool {
return lhs.name == rhs.name
}
}

Now that it's possible equate, we should come up with what we mean by "order." Here's one way. Since structs make unexpected values possible, I've said that those are all equal and order before any of my rainbow colors. If this were an enum, we wouldn't have to worry about that case.

extension Color {
private static let _order: [Color] = [red, orange, yellow, green, blue, indigo, violet]

private var _indexValue: Int {
return Color._order.index(of: self) ?? Int.min
}
}

So with that, we can answer question #2: Comparable:

extension Color: Comparable {
static func < (lhs: Color, rhs: Color) -> Bool {
return lhs._indexValue < rhs._indexValue
}
}

And just one more little step to Strideable:

extension Color: Strideable {
func advanced(by n: Int) -> Color {
return Color._order[self._indexValue + n]
}

func distance(to other: Color) -> Int {
return other._indexValue - _indexValue
}
}

And ta da, your ...:

for rainbowColor: Color in .red ... .violet { print(rainbowColor) }

Now I happen to like enums a lot, and they happen to have a bit of a trick if you try to implement this with an enum, so it's worth noting. For example, say you had:

enum Color {
case red
case orange
case yellow
case green
case blue
case indigo
case violet
}

It turns out that you can't use index(of:) for computing _indexValue. You get yourself into an infinite loop because it calls distance(to:) in the default == implementation (I'm not actually certain why this happens yet). So you have to implement _indexValue this way:

private var _indexValue: Int {
switch self {
case .red: return 0
case .orange: return 1
case .yellow: return 2
case .green: return 3
case .blue: return 4
case .indigo: return 5
case .violet: return 6
}
}

Huh; that looks an awful lot like a raw value. Yeah. This whole approach is basically attaching raw values from the side without having to modify the type itself. So that's why it's going to seem really similar. The rest is the same as for a struct, and the approach can be applied to anything else that you can figure out how to stride.

For in gives let instead of var

As you rightly say, slide is a constant in this expression:

for slide in slides! {
slide.title = "New title" // Cannot assign to property: 'slide' is a 'let' constant
}

If you need to mutate your slide, simply take a var reference to it:

for slide in slides! {
var slide = slide
slide.title = "New title" // fine
}

(Do not use the for var syntax, as it will soon be abolished from the language.)

However, in your example there's a much better way: declare your protocol like this:

protocol Slide : class {
var title: String { get set }
}

Now this code is legal!

for slide in slides! {
slide.title = "New title"
}

Why? Because you've now guaranteed that the adopter of Slide is a class, and a class is a reference type and can be mutated in place. The only reason this failed before is that Swift was afraid the adopter might be a struct.

Can I add support for Swift 2 in Xcode 9

Here's official release notes for xCode:
https://developer.apple.com/library/archive/releasenotes/DeveloperTools/RN-Xcode/Chapters/Introduction.html#//apple_ref/doc/uid/TP40001051-CH1-SW876

Under Deprecation and Removal Notices it is said:

Xcode 8.3 no longer supports Swift 2.3. Please migrate your projects containing Swift 2.3 code to Swift 3 syntax by opening the project and choosing Edit > Convert > To Current Swift Syntax.

Can a Swift class be extended multiple times with the same methods?

Overriding a single protocol method twice in 2 separate extensions wouldn't work, because the protocol method names would collide. Once compiled, they're all just methods on the same class. With that in mind, perhaps put all the protocol methods in their own extension & call them from within the other ones?

The following could be one general option. Could get messy if you decide to keep adding additional extension functionality.

    class baseClass {
//stuff
}

extension baseClass: myProtocol {

override func myProtocolMethod(args) -> returnType {
//Repeat this in a separate extension & your method names collide
var status: Bool

//protocol method code sets status as appropriate...

return status = true ? optOne(status) : optTwo(status)

}

func optOne(status:Bool) -> returnType{
//do the 'true' thing
return returnType
}

func optTwo(status:Bool) -> returnType{
//do the 'false' thing
return returnType
}
}

extension baseClass {
var oneExtension = myProtocolMethod(someArg)
}

extension baseClass {
var twoExtension = myProtocolMethod(someArg)
}


Related Topics



Leave a reply



Submit