我们在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可用来指定每个元素的类型。

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

  1. //
  2. // ViewController.swift
  3. // SwiftTest
  4. //
  5. // Created by Zenny Chen on 16/4/1.
  6. // Copyright © 2016年 GreenGames Studio. All rights reserved.
  7. //
  8.  
  9. import Cocoa
  10.  
  11. class MyIterContainer<T> : SequenceType {
  12.  
  13. // 容器本身包含一个数组对象mElemArray
  14. private var mElemArray: [T]?
  15.  
  16. init() {
  17. mElemArray = [T]()
  18. }
  19.  
  20. init(elems: [T]) {
  21. mElemArray = elems;
  22. }
  23.  
  24. func generate() -> MyIterGenerator<T> {
  25.  
  26. // 这里返回一个GeneratorType对象
  27. return MyIterGenerator(elems: mElemArray!)
  28. }
  29. }
  30.  
  31. class MyIterGenerator<T> : GeneratorType {
  32.  
  33. private var mCurrentIndex: Int = 0
  34. private var mElemArray: [T]?
  35.  
  36. init(elems: [T]) {
  37.  
  38. mElemArray = elems
  39. }
  40.  
  41. func next() -> T? {
  42.  
  43. guard let list = mElemArray else { return nil }
  44.  
  45. if mCurrentIndex < list.count {
  46.  
  47. let element = list[mCurrentIndex]
  48. mCurrentIndex += 1
  49. return element
  50.  
  51. }
  52. else {
  53. return nil
  54. }
  55. }
  56. }
  57.  
  58. class ViewController: NSViewController {
  59.  
  60. override func viewDidLoad() {
  61. super.viewDidLoad()
  62.  
  63. // Do any additional setup after loading the view.
  64.  
  65. let container = MyIterContainer(elems: [1, 2, 3, 4])
  66.  
  67. var sum = 0
  68. for i in container {
  69. sum += i
  70. }
  71. print("sum = \(sum)")
  72.  
  73. sum = 0
  74.  
  75. // 上述的for-in迭代就相当于以下代码:
  76. let generator = container.generate()
  77. var elem: Int? = nil
  78.  
  79. repeat {
  80. elem = generator.next()
  81. if let value = elem {
  82. sum += value
  83. }
  84. }
  85. while elem != nil
  86.  
  87. print("second sum = \(sum)")
  88. }
  89.  
  90. override var representedObject: AnyObject? {
  91. didSet {
  92. // Update the view, if already loaded.
  93. }
  94. }
  95. }

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

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

  1. Swift编程语言中的方法引用

    由于Apple官方的<The Swift Programming Guide>对Swift编程语言中的方法引用介绍得不多,所以这里将更深入.详细地介绍Swift中的方法引用. Swift与 ...

  2. Swift编程语言学习9—— 存储属性和计算属性

    属性将值跟特定的类.结构或枚举关联.存储属性存储常量或变量作为实例的一部分,计算属性计算(而不是存储)一个值.计算属性能够用于类.结构体和枚举里,存储属性仅仅能用于类和结构体. 存储属性和计算属性通经 ...

  3. struts2自定义类型转换器

    首先,何为struts2的类型转换器? 类型转换器的作用是将请求中的字符串或字符串数组参数与action中的对象进行相互转换. 一.大部分时候,使用struts2提供的类型转换器以及OGNL类型转换机 ...

  4. 关于 Swift 4 中内存安全访问

    前言 本文主要翻译今年 The Swift Programming Language (Swift 4) 中新出的章节 -<Memory Safety>.在 Swift 4 中,内存安全访 ...

  5. 浅谈 Swift 2 中的 Objective-C 指针

    浅谈 Swift 2 中的 Objective-C 指针 2015-09-07  499 文章目录 1. 在 Swift 中读 C 指针 2. 在 Swift 中创建 C 指针 3. 总结 作者:Ja ...

  6. Android进阶AIDL使用自定义类型

    原文首发于微信公众号:jzman-blog,欢迎关注交流! 上篇文章中主要介绍从 AIDL 的使用方式以及 Android 开发中不同进程之间的通信,遗留的问题是如何在 AIDL 中使用自定义类型,具 ...

  7. iOS Swift编程语言

    Swift,苹果于2014年WWDC(苹果开发者大会)发布的新开发语言,可与Objective-C*共同运行于Mac OS和iOS平台,用于搭建基于苹果平台的应用程序. Swift是一款易学易用的编程 ...

  8. iOS中生成并导入基于Swift编程语言的Framework

    从iOS 8.0开始就引入了framework打包方式以及Swift编程语言.我们可以主要利用Swift编程语言将自己的代码打包成framework.不过当前Xcode 7.x在自动导入framewo ...

  9. Swift 中的闭包与 C 和 Objective-C中的 blocks 以及其它一些编程语言中的 lambdas 比較类似。

    闭包是功能性自包括模块,能够在代码中被传递和使用. Swift 中的闭包与 C 和 Objective-C中的 blocks 以及其它一些编程语言中的 lambdas 比較相似.  闭包能够 捕获 和 ...

随机推荐

  1. Kotlin调用Java程序重点分析

    在上一次https://www.cnblogs.com/webor2006/p/11530801.html中学习了Kotlin调用Java的使用方式及一些注意点,这次继续其这个场景进一步学习. 数组( ...

  2. P1505 [国家集训队]旅游[树剖]

    题目描述 Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但又为了节约成本,T 城的任意两个景点之间有且只有一条路 ...

  3. 性能:Output层面

    将数据保存到MySQL中 import java.sql.DriverManager import org.apache.spark.storage.StorageLevel import org.a ...

  4. 【比赛题解】CSP2019 简要题解

    D1T1 code 签到题,大家都会. 可以从高位往低位确定,如果遇到 \(1\),则将排名取反一下. 注意要开 unsigned long long. #include <bits/stdc+ ...

  5. pass的作用?

    1.空语句 do nothing   2.保证格式完整,保证语义完整       3.占位语句

  6. 13-Flutter移动电商实战-ADBanner组件的编写

    1.AdBanner组件的编写 我们还是把这部分单独出来,需要说明的是,这个Class你也是可以完全独立成一个dart文件的.代码如下: 广告图片class AdBanner extends Stat ...

  7. jeecg uedit 自定义图片上传路径

    jeecg uedit 图片上传配置自定义物理路径,简单描述:我们知道 jeecg 中使用的 uedit 默认图片上传路径为 "当前项目\plug-in\ueditor\jsp\upload ...

  8. maven的目录

    maven目录主要分为: src/main/java:项目主体源代码目录 src/main/resources:项目主体源代码所需资源目录 src/test/java:测试代码目录(测试代码不会被打包 ...

  9. 使用window.localStorage,window.localStorage记录点击次数

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  10. Vue.directive全局自定义指令案例

    今天正好这个知识点有点淡忘了,就随笔一下吧: Vue.directive(参数1,参数2) 参数1:指令名称,如"drag" 参数2:指令要实现的回调函数,其中回调函数中也有两个参 ...