Swift进阶 - 12个技巧

作者: 豆志昂扬 | 来源:发表于2016-11-21 23:22 被阅读6724次
    Swift秘籍

    听说你已经学习Swift几个月了,有没有想更进一步成为Swift高手的想法?我这里有11招秘技,各位施主且听我慢慢道来,结个善缘。

    1. 扩展(Extension)

    任务: 求数字的平方。

    // 菜鸟版
    func square(x: Int) -> Int { return x * x }
    var squaredOfFive = square(x: 5)
    square(x: squaredOfFive) // 625
    

    为了求5的四次方我们被迫创建变量 squaredOfFive — 高手可不喜欢被迫定义一个无用的变量。

    // 高手版
    extension Int { 
     var squared: Int { return self * self }
    }
    5.squared // 25
    5.squared.squared // 625
    

    2. 泛型(Generics)

    任务:打印输出数组内所有的元素。

    // 菜鸟版
    var stringArray = ["金庸", "古龙", "梁羽生"]
    var intArray = [1, 3, 4, 5, 6]
    var doubleArray = [1.0, 2.0, 3.0]
    func printStringArray(a: [String]) { 
            for s in a { 
                  print(s) 
            }
    }
    func printIntArray(a: [Int]) { for i in a { print(i) } }
    func printDoubleArray(a: [Double]) {for d in a { print(d) } }
    

    居然要定义这么多函数? 菜鸟能忍高手不能忍!!!

    // 高手版
    func printElementFromArray<T>(a: [T]) {
            for element in a { 
                print(element) 
            } 
    }
    

    3. For 遍历 vs While 遍历

    任务:打印 5 次 陆家嘴

    // 菜鸟版
    var i = 0
    while 5 > i {
          print("陆家嘴")
          i += 1 
    }
    

    被迫定义了变量 i 来确保打印 陆家嘴 5 次。
    注意定义越多的变量,越多的潜在风险,越多的生活问题。这就是蝴蝶效应,你难道想X生活不和谐?

    // 高手版
    for _ in 1...5 { 
         print("陆家嘴") 
    }
    

    上面的代码实在是简洁,美妙。

    4. Gaurd let vs if let

    任务 : 让我们写个欢迎新用户的程序。

    var myUsername: Double?
    var myPassword: Double?
    // 菜鸟版
    func userLogIn() {
         if let username = myUsername {
              if let password = myPassword {
                   print("华山派欢迎, \(username)"!)
              }
         }
    }
    

    这些令人讨厌的嵌套代码,我们要消灭它

    // 高手版
    func userLogIn() {
         guard let username = myUsername, let password = myPassword 
              else { return } 
            print("华山派欢迎, \(username)!") 
    }
    

    注意这里如果myUsername 或 myPassword nil,都会提前结束,否则就会打印 “优衣库欢迎, XXX”

    5. 计算属性 vs 函数

    任务:计算圆的直径

    // 菜鸟版
    func getDiameter(radius: Double) -> Double { return radius * 2}
    func getRadius(diameter: Double) -> Double { return diameter / 2}
    getDiameter(radius: 10) // return 20
    getRadius(diameter: 200) // return 100
    getRadius(diameter: 600) // return 300
    

    上面我们创建了2个毫无关系的函数,可是直径和周长两者真的没有关系吗?

    // 高手版
    var radius: Double = 10
    var diameter: Double {
          get { return radius * 2}
          set { radius = newValue / 2} 
    }
    radius // 10
    diameter // 20
    diameter = 1000
    radius // 500
    

    现在半径和直径相互依赖,真实地反应了两者的关系。
    记得上面说的蝴蝶效应吗? 越少的依赖,代码越简洁,问题越少,生活越美好!

    6. 枚举 - 类型安全

    任务:卖门票

    // 菜鸟版
    switch "Adult" {
       case "Adult": print("请付 50 元")
       case "Child": print("请付 25 元")
       case "Senior": print("请付 30 元")
       default: print("你确认不是僵尸吗,哥们?") 
    }
    

    “Adult”, “Child”, “Senior” 这里都是硬编码,你每次需要输入手动输入这些字符,记得我们上面讲到的吗? 手动键入越少,错误越少,生活越美好。

    // 高手版
    enum People { case adult, child, senior }
    switch People.adult {
       case .adult: print("请付 50 元")
       case .child: print("请付 25 元")
       case .senior: print("请付 30 元")
       default: print("你确认不是僵尸吗,哥们?") 
    }
    

    这样你就避免了不小心输入错误的问题,因为 “.adult”, “.child”, “.senior” 被定义成了enum', 任何不在预定义范围内的实例都会被Xcode毫不留情的指出来,合理利用集成开发环境是高手必备的。

    7. 空合运算符

    任务: 用户选择微博主体颜色。

    // 菜鸟版
    var userChosenColor: String? 
    var defaultColor = "Red"
    var colorToUse = ""
    if let Color = userChosenColor { 
         colorToUse = Color 
    } else { 
         colorToUse = defaultColor
     }
    

    这也太臃肿了吧,让我们来减减肥。

    // 高手版
    var colorToUse = userChosenColor ?? defaultColor
    

    稍微解释一下, 如 userChosenColor 为 nil, 则选择 defaultColor, 否则则userChosenColor.
    其实空合运算符是对以下代码的简短表达方法。

    a != nil ? a! : b
    

    8. 函数式编程

    任务: 获取偶数。

    // 菜鸟版
    var newEvens = [Int]()
    for i in 1...10 {
      if i % 2 == 0 { 
          newEvens.append(i) 
        } 
    }
    print(newEvens) // [2, 4, 6, 8, 10]
    

    这种for循环真是冗长,让人看的昏昏欲睡。

    // 高手版
    var evens = (1...10).filter { $0 % 2 == 0 } 
    print(evens) 
    // [2, 4, 6, 8, 10]
    

    有没有感觉函数式编程让你看起来聪明多了。

    9. 闭包 vs 函数

    任务: 求两个数字的和。

    // 菜鸟版
    func sum(x: Int, y: Int) -> Int { 
        return x + y 
    }
    var result = sum(x: 5, y: 6) // 11
    

    为了这个功能我还需要记住函数名 和 变量名? 能不能少一个呢?

    // 高手版
    var sumUsingClosure: (Int, Int) -> (Int) = { $0 + $1 }
    sumUsingClosure(5, 6) // 11 
    

    10. 属性观测器

    任务:计算圆的直径

    // 菜鸟版
    var radius = 10.0
    func getDiameter(radius: Double) -> Double { 
          return radius * 2
    }
    
    getDiameter(radius: radius) // return 20
    

    这里是不需要专门定义函数的。

    // 高手版
    var diameter = 0
    var radius: Double = 10 {
          willSet { print("准备赋值中") }
          didSet { diameter =radius * 2}
         }
    }
    radius  = 10 // 准备赋值中
    diameter // 20.0
    

    willSet 会在给变量radius赋值前调用,而 didSet 会在给变量radius赋值后调用。

    11.便利初始化

    任务: 一个人有多少根手指和脚趾

    // 菜鸟版
    class Human {
     var finger: Int
     var toe: Int
    
    init(finger: Int, toe: Int) {
      self.finger = finger
      self.toe = toe }
    }
    
    
    var daDi = Human(finger: 10, toe: 10)
    daDi.finger // 10
    daDi.toe // 10
    

    因为绝大部分人都有十根手指和脚趾,可以初始化时预先赋值。

    // 高手版
    class Human {
     var finger: Int
     var toe: Int
    
    init(finger: Int, toe: Int) {
      self.finger = finger
      self.toe = toe
     }
    
      convenience init() {
       self.init(finger: 10, toe: 10) // 调用主初始化方法
       } 
    }
    
    var daDi = Human()
    daDi.finger // 10
    daDi.toe // 10
    

    Swift中可以在init初始化方法前加上convenience关键字,这类方法主要提供使用上的方便。

    所有的convenience初始化方法都必须调用同一个类中的顶级初始化方法完成初始化。另外convenience的初始化方法是不能被子类重写或从子类中以super的方式被调用的。

    12. 延迟初始化

    任务: 定义一个包含pi常量作为属性的类。

    // 菜鸟版
    class MathHelper {
    var pi: Double = {
        // 计算pi
        return resultOfCalculation
        }()
    
    }
    

    计算pi的工作量是繁重的,且对于调用者不是必须的,可以假想下MathHelper内包含数十个类pi常量的场景,如果不在使用的时候再初始化常量会浪费多少宝贵的计算资源。

    // 高手版
    class MathHelper {
    
    lazy var pi: Double = {
          // 计算pi
        return resultOfCalculation
        }()
    
    }
    

    lazy 一方面可以让初始化成本较高的变量延迟初始化,提高资源利用效率。另一方面可以延迟初始化具有外部依赖的属性变量。

    class Person {
    var name: String
    lazy var personalizedGreeting: String = {
        [unowned self] in
        return "Hello, \(self.name)!"
        }()
    
    init(name: String) {
            self.name = name
        }
    }
    

    上面的例子中,属性personalizedGreeting依赖于变量name。

    十二条技巧讲述完毕,打完收工。

    PS: 其实还有 Switch vs If-else,可变参数等,因本文翻译整理于这两篇 文章1文章2,就在此不做赘述,有兴趣的可查看原文。

    推荐阅读:

    iOS开发者注意, ATS 出没!
    Swift之非逃逸闭包与逃逸闭包

    更多

    获取更多内容请关注微信公众号豆志昂扬:

    • 直接添加公众号豆志昂扬
    • 微信扫描下图二维码;

    相关文章

      网友评论

      • 鸿毛W:心累~ 新項目外包用swift,storyboard寫的~ 現在接手 表示好累~我準備辭職了~:joy:
        豆志昂扬:storyboard项目可维护性差,特别是不规范的代码。
      • UASHS:if let 也能写在同一行啊
        豆志昂扬:官方都是这么写的
      • iOS_小胜:学习了,谢谢总结
      • brycegao:这就高手了??? 只是基础语法而已, Swift的官方文档都有介绍。
      • R0b1n_L33:总结的很好:clap
        另:关于guard和let这样写也无妨,其实掌握区别就好
        func userLogIn(myUsername:String?, myPassword:String?) {
        if let username = myUsername, let _ = myPassword {
        print("优衣库欢迎, \(username)!")
        } else { return }
        }
      • 989078cec84b:拿别人的文章过来,稍作小改,这样是不是不道德呢?这位同学?
      • Madlife_ZYC:看完后我觉得我的生活更美好哈哈哈啊哈哈哈
      • ZhHS:赞一个
      • SevenJustin:这些都是原著书中本身就有的 也是swift更高级的重点原因 标题党一个
      • kemchenj:第九条, Range 本身间接地遵守了 IteratorSequence 的协议, 可以被遍历, 没必要转换成 Array 然后再来做 filter, 直接 (1...10).filter { $0 % 2 == 0 } 就可以了
        豆志昂扬:@kemchenj 已修改,多谢指正。
      • 班蹄子:慕课网玩转swift 2.0 讲得很全面。更加深入。
        班蹄子:@豆志昂扬 相通的。3.0 在慕课网也有讲的。很全面哦。可以去看看
        豆志昂扬:@大抱抱 我的哥现在是3.0时代
      • 韩大熊宝要姓张:学习了.谢谢
      • TimberTang: :+1: 厉害.你在进阶的道路上了. 像你学习
      • 故胤道长:总体很好。提点小建议:
        第一个,用protocol比extension可读性更高
        最后一个,其实大项目中更prefer前者,要是不想加变量名,就在函数定义的时候,变量前加下划线,func sum(_ x: Int, _ y: Int) -> Int
        豆志昂扬:@故胤道长 Protocol也可以写成extension的形式,如一个类实现多个protocol的时候,结合extension 使用可读性更强。

        高级语法大都以牺牲代码可读性为代价的,但当团队成员都熟悉了这些语法,可读性就不再是问题。
      • 没故事的卓同学:总结的很好。 :relieved:
      • 梁同桌:我用 Swift ,写了一个 App
        你上面好多方法,我都不知道可以这样写- -,悲催啊。

        我原来学 Swift , 是和JS像,现在更像了。
        梁同桌:@豆志昂扬 确实是这样,我里面Swift一些高级特性都没有怎么, 最近升级3.0。
        ```
        for(var i=0; i<3; i++)
        //这样的写法,就不允许了
        for i in 0...3
        //这样也挺好理解

        豆志昂扬:@梁同桌 这样给后来只会Swift 不了解JS 的开发者维护带来不必要的麻烦。
      • 736173c4ca99:swift确实简洁和优美,值得深入学习,多谢大大分享
        豆志昂扬:@swift潘 :stuck_out_tongue_winking_eye:
      • 小虫1234:真的很有用:pray:🏻
      • SawyerZh:对比合理,范例简单典型:+1:
      • 十一岁的加重:还不错哦
      • 贾萧遥:强悍:+1:
        豆志昂扬:@贾萧遥 看你文章都是电影,还以为是影视圈的:smile:
        贾萧遥:@豆志昂扬 :sweat:略懂
        豆志昂扬:@贾萧遥 哥们还懂编程?

      本文标题:Swift进阶 - 12个技巧

      本文链接:https://www.haomeiwen.com/subject/wixppttx.html