Swift编程语言中如何实现自定义类型的for-in循环(基于Swift 2.2)

Posted zenny_chen

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Swift编程语言中如何实现自定义类型的for-in循环(基于Swift 2.2)相关的知识,希望对你有一定的参考价值。

我们在Swift编程语言中常常会用到for-in循环(在编程语言术语中又被称为for-each)。此外,从Swift 2.2版本起,for循环将只支持for-in形式,而不支持for i = 0; i < n; i+=1 { }这种形式了,若要使用这种形式的话,只得用while或repeat-while来代替,或想办法转为for-in。

在Swift中,标准库已经定义了许多类型可直接支持for-in循环形式,比如Range、Array、Set、Dictionary等等。那么我们是否能自己定义一个类或结构体来支持for-in这种迭代形式呢?当然可以!我们要实现这个目标需要分两步走。

第一步,我们要使用for-in循环的类或结构体需要实现SequenceType这个协议。SequenceType包含了许多容器相关的接口方法,但如果我们只需要简单实现for-in循环的话,那么只需要实现其 public func generate() -> Self.Generator 接口方法即可。这里的Self只能用在protocol的定义内,相当于self,但是这里又不能用self,因为self是对对象的引用,协议不是一个对象,所以Swift编程语言中引入了Self(注意S是大写的)表示引用本协议内定义的类型。generate方法用于生成所需迭代的每个元素的列表。此外,Generator的本体是GeneratorType,它也是一个protocol,表示所需迭代的每个元素对象,所以我们要做第二步。

第二步,实现GeneratorType协议。这个协议比较简单,就一个 public mutating func next() -> Self.Element 接口方法。这里的Element可用来指定每个元素的类型。

下面我们就看一下一个实例代码:

//
//  ViewController.swift
//  SwiftTest
//
//  Created by Zenny Chen on 16/4/1.
//  Copyright © 2016年 GreenGames Studio. All rights reserved.
//

import Cocoa

class MyIterContainer<T> : SequenceType {
    
    // 容器本身包含一个数组对象mElemArray
    private var mElemArray: [T]?
    
    init() {
        mElemArray = [T]()
    }
    
    init(elems: [T]) {
        mElemArray = elems;
    }
    
    func generate() -> MyIterGenerator<T> {
        
        // 这里返回一个GeneratorType对象
        return MyIterGenerator(elems: mElemArray!)
    }
}

class MyIterGenerator<T> : GeneratorType {
    
    private var mCurrentIndex: Int = 0
    private var mElemArray: [T]?
    
    init(elems: [T]) {
        
        mElemArray = elems
    }
    
    func next() -> T? {
        
        guard let list = mElemArray else { return  nil }
        
        if mCurrentIndex < list.count {
            
            let element = list[mCurrentIndex]
            mCurrentIndex += 1
            return element
            
        }
        else {
            return nil
        }
    }
}

class ViewController: NSViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Do any additional setup after loading the view.
        
        let container = MyIterContainer(elems: [1, 2, 3, 4])
        
        var sum = 0
        for i in container {
            sum += i
        }
        print("sum = \(sum)")
        
        sum = 0
        
        // 上述的for-in迭代就相当于以下代码:
        let generator = container.generate()
        var elem: Int? = nil
        
        repeat {
            elem = generator.next()
            if let value = elem {
                sum += value
            }
        }
        while elem != nil
        
        print("second sum = \(sum)")
    }
    
    override var representedObject: AnyObject? {
        didSet {
            // Update the view, if already loaded.
        }
    }
}

上述示例代码先定义了一个容器类MyIterContainer<T>,然后定义了与之相关的生成器类MyIterGenerator<T>,这里用了泛型,可使得后面的实现更为灵活。然后在viewDidLoad方法中描述了for-in的使用方法,并且在最后描述了其内部实现机制。

 

以上是关于Swift编程语言中如何实现自定义类型的for-in循环(基于Swift 2.2)的主要内容,如果未能解决你的问题,请参考以下文章

数组类型为 JSON 时如何实现自定义搜索栏

在Swift 2中使用自定义消息抛出错误/异常的最简单方法?

如何在 Swift 中以编程方式更改自定义 UITableViewCell 中按钮的背景颜色?

Swift之使用KeyPaths创建自定义查询函数

如何在 Objective-C 控制器中以编程方式加载用 swift 编写的自定义 XIB 视图

Swift:将包含自定义标签的单元格添加到 UITableView