swift3.0_swift3.0和4.0区别 - CSDN
  • swift3.0新浪微博项目源码--黑码哥,这是黑马程序员最新的swift项目讲解的代码。有学习的可以看看。
  • 一、对象和类Swift 当中使用class和类名来创建一个类。类中属性的声明和常量、变量声明一样,唯一的区别就是它们的上下文是类。同样,方法和函数声明也一样。class TestViewController: ViewController { var ...

    一、对象和类

    Swift 当中使用class和类名来创建一个类。类中属性的声明和常量、变量声明一样,唯一的区别就是它们的上下文是类。同样,方法和函数声明也一样。

    class TestViewController: ViewController {
        var numberOfSides = 0
        func simpleDescription() -> String {
            return "A shape with \(numberOfSides) sides"
        }
    
    
    }
    

    要创建一个类的实例,在类名后面加上括号。使用点语法来访问实例的属性和方法。

            var vc = ViewController()
    
            vc.numberOfSides = 8
    
            var s = vc.returnFifteen()

    这个版本的ViewContrller类缺少了一些重要的东西:一个构造函数来初始化类实例。使用init来创建一个构造器。

    class NamedShape {
        var numberOfSides: Int = 0
          var name: String
        init(name: String) {
            self.name = name
    }
        func simpleDescription() -> String {
            return "A shape with \(numberOfSides) sides."
    } }

    注意 self 被用来区别实例变量。当你创建实例的时候,像传入函数参数一样给类传入构造器的参数。每个属性都 需要赋值——无论是通过声明(就像 numberOfSides )还是通过构造器(就像 name )。

    子类如果要重写父类的方法的话,需要用override标记—如果没有添加override就重写父类方法的话编译器会报错。编译器同样会检测override标记的方法时候确定在父类中。

    class Square: NamedShape {
        var sideLength: Double
        init(sideLength: Double, name: String) {
            self.sideLength = sideLength
            super.init(name: name)
            numberOfSides = 4
    }
        func area() ->  Double {
            return sideLength * sideLength
    }
        override func simpleDescription() -> String {
            return "A square with sides of length \(sideLength)."
    } }
    let test = Square(sideLength: 5.2, name: "my test square")
    test.area()
    test.simpleDescription()

    除了储存简单的属性之外,属性可以有getter和setter。

    class EquilateralTriangle: NamedShape {
        var sideLength: Double = 0.0
        init(sideLength: Double, name: String) {
            self.sideLength = sideLength
            super.init(name: name)
            numberOfSides = 3
    }
    var perimeter: Double {
            get {
                return 3.0 * sideLength
            }
            set {
                sideLength = newValue / 3.0
    } }
        override func simpleDescription() -> String {
            return "An equilateral triagle with sides of length \(sideLength)."
    } }
    var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")
    print(triangle.perimeter)
    triangle.perimeter = 9.9
    print(triangle.sideLength)

    在perimeter的setter中,新值的名字是newValue。你可以在set之后显示的设置一个名字。
    注意 EquilateralTriangle 类的构造器执行了三步:
    1. 设置子类声明的属性值
    2. 调用父类的构造器
    3. 改变父类定义的属性值。其他的工作比如调用方法、getters 和 setters 也可以在这个阶段完成。

    二、枚举和结构体

    使用enum来创建一个枚举。就像类和其他所有命名类型一样,枚举可以包含方法。

    enum Rank:Int {
        case Ace = 1
        case Two,Three,Four,Five,Six,Seven
        case Jack,Queen,King
        func simpleDescription() -> String {
            switch self {
            case .Ace:
                return "ace"
            case .Two:
                return "two"
            case .Queen:
                return "queen"
            default:
                return String(self.rawValue)
            }
        }
    }
    
    let ace = Rank.Ace
    let aceRawValue = ace.rawValue

    默认情况下,Swift按照从0开始每次加1的方式为原始值进行赋值,不过你可以通过显式赋值进行改变。在上面的栗子中,Ace被显式赋值为1,并且剩下的原始值会按照顺序赋值。你也可以使用字符串或者浮点数作为枚举的原始值。使用rawValue属性来访问一个枚举成员的原始值。

    使用init?(rawValue:) 初始化构造器在原始值和枚举值之间进行转换。

    if let convertedRank = Rank(rawValue: 3) {
                let threeDescription = convertedRank.simpleDescription()
            }

    枚举的成员值是实际值,并不是原始值的另一种表达方法。实际上,如果没有比较有意义的原始值,你就不需要提供原始值。

    enum Suit {
        case Spades,Hearts,Diamonds,Clubs
        func simpleDescription() -> String {
            switch self {
            case .Spades:
                return "spades"
            case .Hearts:
                return "hearts"
            case .Diamonds:
                return "diamonds"
            case .Clubs:
                return "clubs"
    
            }
        }
    }
    
    let hearts = Suit.Hearts
    let heartDesciption = hearts.simpleDescription()

    注意,有两种方式可以引用Hearts 成员:给hearts 常量赋值时,枚举成员Suit.Hearts 需要用全名来引用,因为常量没有显示指定类型。在switch 里,枚举成员使用缩写.Hearts 来引用,因为self的值已经知道一个suit。已知变量类型的情况下你可以使用缩写。

    一个枚举成员的实例可以有实例值。相同枚举成员的实例可以有不同的值,创建实例的时候传入值即可。实例值和原始值是不同的:枚举成员的原始值对于所有实例都是相同的,而且你是在定义枚举的时候设置原始值。

    举个栗子,考虑从服务器获取日出和日落的时间。服务器会返回正常结果或者错误信息。

    enum SeverResponse {
        case Result(String,String)
        case Failure(String)
    }
    
    let success = SeverResponse.Result("6:00 am","8:00 pm")
    let failure = SeverResponse.Failure("Out of cheese")
    
    switch success {
            case let .Result(sunrise,sunset):
                let serverResponse = "Sunrise is at \(sunrise) and sunset is at \(sunrise)"
    
            case let .Failure(message):
                print("Failure... \(message)")
            }

    注意,日升和日落是如何从SeverResponse中提取到并且与switch的case相匹配的。

    使用struct 来创建一个结构体和类有很多相同的地方,比如方法和构造器。它们之间最大的一个区别就是结构体时传值,类是传引用。

    三、协议和扩展

    使用protocol 来声明一个协议。

    protocol ExampleProtocol {
        var simpleDescription : String{ get }
        mutating func adjust()
    
    }

    类、枚举和结构体可以实现协议。

    class SimpleClass: ExampleProtocol {
        var simpleDescription: String = "A very simple class."
        var anotherProperty: Int = 69105
        func adjust() {
            simpleDescription += "  Now 100% adjusted."
        }
    }
    var a = SimpleClass()
    a.adjust()
    let aDescription = a.simpleDescription
    struct SimpleStructure: ExampleProtocol {
        var simpleDescription: String = "A simple structure"
        mutating func adjust() {
            simpleDescription += " (adjusted)"
        }
    }
    var b = SimpleStructure()
    b.adjust()
    let bDescription = b.simpleDescription

    注意声明 SimpleStructure 时候 mutating 关键字用来标记一个会修改结构体的方法。 SimpleClass 的声明不需要 标记任何方法,因为类中的方法通常可以修改类属性(类的性质)。

    使用 extension 来为现有的类型添加功能,比如新的方法和计算属性。你可以使用扩展在别处修改定义,甚至是 从外部库或者框架引入的一个类型,使得这个类型遵循某个协议。

    extension Int: ExampleProtocol {
        var simpleDescription: String {
            return "The number \(self)"
        }
        mutating func adjust() {
    self += 42 
       }
    }
    print(7.simpleDescription)

    你可以使用其他命名类型一样使用协议名—例如,创建一个有不同类型但是都实现一个协议的对象集合。当你处理类型是协议的值时,协议外定义的方法不可用。

    let protocolValue: ExampleProtocol = a print(protocolValue.simpleDescription)
    // print(protocolValue.anotherProperty) // 去掉注释可以看到错误

    即使 protocolValue 变量运行时的类型是 simpleClass ,编译器会把它的类型当做 ExampleProtocol 。这表示你不 能调用类在它实现的协议之外实现的方法或者属性。

    展开全文
  • Swift 3.0介绍

    2017-02-22 21:41:39
    概述我接触swift是从2.0开始,当时出于对ios的好奇,加上官方的大力推荐,于是扎入了ios的怀抱,从1.2发展到了今天的3.0.1,这期间由于...尽管对于开发人员来说Swift3.0的变化会令你的程序几乎处处报错,但是试想一下如

    概述

    我接触swift是从2.0开始,当时出于对ios的好奇,加上官方的大力推荐,于是扎入了ios的怀抱,从1.2发展到了今天的3.0.1,这期间由于Swift目前还在发展阶段并不能向下兼容,这也造成部分我们2.x开发的版本在新版本上运行的问题,不过基于最近基本版本改动比较小的原因吧,我觉得swift是为了ios的趋势。尽管对于开发人员来说Swift3.0的变化会令你的程序几乎处处报错,但是试想一下如果Apple没有追求极致的精神又怎么会做出如此多的更改。本文介绍主要以3.0为基础讲解,从Swift编译器和标准库两个方面来说明从Swift3.0的变化。

    编译器和语法变化

    函数或方法参数

    调用函数或方法时从第一个参数开始就必须指定参数名
    在Swift的历史版本中出现过在调用函数时不需要指定任何函数参数(或者从第二个参数开始指定参数名),在调用方法时则必须从第二个参数开始必须指定参数名等多种情况,而在Swift3.0中不管是函数还是方法都必须从第一个参数开始必须指定参数名(当然可以使用“_”明确指出调用时省略参数)。

    func sum(num1:Int,num2:Int)->Int{
        return num1 + num2
    }
    sum(num1: 1, num2: 2) // old: sum(1,2)或者sum(1, num2: 2)

    取消var参数

    //func increase(var a:Int){
    //    a += 1
    //}
    // 上面的代码会报错,可改写成
    func increase(a:Int){
        var a = a
        a += 1
    }

    inout参数修饰改放到类型前

    //func increase(inout a:Int) {
    //    a += 1
    //}
    // 上面的代码会报错,可改为
    func increase( a:inout Int) {
        a += 1
    }

    方法返回值

    Swift 3.0 中方法的返回值必须有接收否则会报警告,当然其实主要目的是为了避免开发人员忘记接收返回值的情况,但是有些情况下确实不需要使用返回值可以使用”_”接收来忽略返回值。当然你也可以增加 @discardableResult 声明,告诉编译器此方法可以不用接收返回值。
    例如:

    struct Caculator {
        func sum(a:Int,b:Int) -> Int {
            return a + b
        }
        //@discardableResult声明,告诉编译器此方法可以不用接收返回值
        @discardableResult
        func func1(a:Int,b:Int) ->Int {
            return a - b + 1
        }
    }
    let ca = Caculator()
    ca.sum(a: 1, b: 2) // 此处会警告,因为方法有返回值但是没有接收
    let _ = ca.sum(a: 1, b: 2) // 使用"_"接收无用返回值
    ca.func1(a: 1, b: 2) // 由于func1添加了@discardableResult声明,即使不接收返回值也不会警告

    可选类型

    Swift3.0对于可选类型控制更加严谨,隐式可选类型和其他类型的运算之后获得的是可选类型而不是隐式可选类型。

    let a:Int! = 1
    let b = a + 1 // 此时强制解包,b是Int型
    let c = a // 注意此时c是Int? 在之前的Swift版本中c是Int!

    Selector的变化

    Selector的改变其实从1.0到3.0经历了多次变化,从最早的@Selector(“method:”)到现在的#selector(method(param1:))可以说经历了多次修改,好在它变得越来越好,毕竟字符串操作对于语法检查来说是很无助的。

    class MyClass {
        @objc func sum(a:Int,b:Int) -> Int {
            return a + b
        }
    
        func func1(){
            let _ = #selector(sum(a:b:))
        }
    }
    
    // old: Swift 2.x
    //class MyClass {
    //    @objc func sum(a:Int,b:Int) -> Int {
    //        return a + b
    //    }
    //    
    //    func func1(){
    //        let _ = #selector(sum(_:b:))
    //    }
    //}

    协议中的可选方法

    在Swift3.0之前如果要定义协议中可选方法,只需要给协议加上@objc之后方法使用optional修饰就可以了,但是Swift3.0中除了协议需要@objc修饰,可选方法也必须使用@objc来修饰。

    @objc protocol MyProtocol {
        @objc optional func func1() //old: optional func func1()
        func func2()
    }

    取消++、–操作符

    var d = 1
    d++ //报错,可以改写成 d += 1 或者 d = d + 1

    取消C风格for循环

    取消C风格for循环,使用更加简洁的语法(有点类似于前端的语法)

    //for var i = 0 ;i < 10 ; i += 1 {
    //    debugPrint(i)
    //}
    // 上面的代码会报错,可改写成如下代码
    for i in 0  ..< 10  {
        debugPrint(i)
    }

    SDK类库变化

    大家都知道Swift诞生在Objective-C已经发展的相当成熟的情况下,为了保证ObjC开发人员顺利过渡到Swift,也因为Swift处于初级阶段,很多类库和方法命名都尽量和ObjC保持一致,在使用Swift开发iOS应用中处处可以看到ObjC的影子。但是作为一门Modern语言Swift还是做出了改变,从中可以看出日后Swift将彻底摆脱ObjC的影子。这其中包括重新导入Foundation消除类型前缀、方法名去重、函数和方法去C风格等等。

    命名

    去掉一些前缀,更加注重语意的表达,书写上也尽量考虑一些驼峰命名等规则。

    // 1.去掉前缀
    let url1 = URL(string: "www.cmjstudio.com")
    let isFileURL = url1?.isFileURL //old:url1.fileURL ,现在更加注重语意
    let data1 = Data() //NSData
    
    // 2.方法名使用动词,其他名词、介词等作为参数或移除
    var array1 = [1,2,3]
    array1.append(contentsOf: [4,5,6]) // old:array1.appendContentsOf([4,5,6])
    array1.remove(at: 0) // old:array1.removeAtIndex(0)
    
    // 3.不引起歧义的情况下尽量消除重复
    let color1 = UIColor.red() // old:var color1 = UIColor.redColor()
    
    // 4.枚举成员首字母变成小写
    let label1 = UILabel()
    label1.textAlignment = .center // old:label1.textAlignment = .Center
    
    // 5.按钮的Normal状态去掉
    let btn1 = UIButton()
    btn1.setTitle("hello", for: UIControlState()) // 相当于Normal状态

    去C风格

    Swift发展初期很多类库的引入依然保持的ObjC风格,但是ObjC由于根出C语言,因此很多操作其实并不是对象和方法操作而是C语言的函数形式。到了Swift3.0之后这一现状将发生变化,全局函数将会变成某些类型的方法;某些常量定义将以某个枚举类型的成员来表示。

    let rect1 = CGRect(x: 0, y: 0, width: 100, height: 100)
    // 下面的代码将要报错,3.0完全废除这种类C的风格
    //let rect1 = CGRectMake(0, 0, 100, 100)
    
    if let context1 = UIGraphicsGetCurrentContext() {
        CGContext.fillPath(context1) // old:CGContextFillPath(context1!)
    }
    
    // GCD的改变
    let queue = DispatchQueue(label: "myqueue")
    queue.async {
        debugPrint("hello world!")
    }
    // old:
    //let queue = dispatch_queue_create("myqueue", nil)
    //dispatch_async(queue) {
    //    debugPrint("hello world!")
    //}
    
    // 相关常量定义被移到枚举内部
    NotificationCenter.defaultCenter().addObserver(self, selector: #selector(userDefaultChange()), name: UserDefaults.didChangeNotification, object: nil)
    //old:NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(userDefaultChange()), name: NSUserDefaultsDidChangeNotification, object: nil)

    集合API的变化

    let array1 = [1,2,3]
    let next = array1.index(after: 0)  // old:let start = array1.startIndex let next = start.successor()
    let first = array1.first { (element) -> Bool in // 增加新的方法
        element > 1
    }
    
    let r = Range(0..<3) //old: let _ = NSRange(location: 0, length: 3)
    
    // 下面的代码必须在控制器中执行,用于遍历当前view及其父视图
    for subview in sequence(first: self.view, next: { $0?.superview }){
        debugPrint(subview)
    }

    新的浮点协议

    Float、Double、CGFloat使用了新的协议,提供了提供 IEEE-754标准的属性和方法。

    let a = 2 * Float.pi // old: let a = 2 * M_PI
    let b = 2.0 * .pi // 注意前面是浮点型,后面可以省略Float

    Swift2.2和Swift3.0对比

    可以看出如果要更新到Swift3.0现有项目需要作出大量修改,经过使用之前开源项目TagEditor进行测试,区区十个类文件就出现了一百多个错误,不过好在Xcode 8已经提供了很好用的迁移工具(Xcode:Editor - Convert - To Current Swift Syntax),经过迁移工具转化后仅仅发现两处错误需要手动修正。在使用这个工具的时候大家会看到如下界面:
    这里写图片描述
    为什么上图会出现2.3,其实就是Swift 2.2 + New SDKs。之所以如此是因为Xcode 8目前还是beta版,使用Swift 3.0进行开发的应用还不能提交App Store,所以就使用了一个新的版本2.3。

    总结

    Swift的每次变化由于对之前的版本乃至上一个版本都不兼容造成每次Swift的升级都显得比较虐心,但是事实上这也是Swift的重大进步。记得之前曾有传闻说Swift3.0的语法和API都会稳定并且向上兼容,但是不久这个消息就破灭了,WWDC上官方也再次证实这个希望可能要到4.0才能实现。但是试想一下:Apple在很短的时间内就固话API对于Swift的发展真的是好事吗?毕竟新特性的加入、更好的语法优化才能让Swift越来越好!总的来说,如果应用要升级到Swift3.0可能要做不同程度的修改,但是这种改动仅仅是语法和SDK的变动并不会消耗太多的工作量,更何况Apple提供了迁移工具。

    展开全文
  • Swift3.0语法变化写在前面首先和大家分享一下学习新语法的技巧: 用Xcode8打开自己的Swift2.3的项目,选择Edit->Convert->To Current Swift Syntax… 让Xcode帮我们把Swift2.3的代码转换为Swift3.0。 手动调出Xcode...

    Swift3.0语法变化

    写在前面

    首先和大家分享一下学习新语法的技巧:
    用Xcode8打开自己的Swift2.3的项目,选择Edit->Convert->To Current Swift Syntax… 让Xcode帮我们把Swift2.3的代码转换为Swift3.0。

    这里写图片描述
    手动调出Xcode自动转换Swift2.3 到 Swift3.0

    弹出语言版本选择界面,选择Covert to Swift3,Next:
    这里写图片描述

    进入选择模块界面:
    这里写图片描述
    选择模块界面

    建议只选择自己创建的模块,第三方框架的模块最好不要使用Xcode来转换,等待第三方作者更新。

    进入转换界面:
    这里写图片描述
    转换界面
    不要着急Save,在这个界面中详细的列出了各个语法具体变化,我们可以利用这个界面来快速学习自己项目中遇到语法变化。

    好了,下面给大家分享一下我的遇到的语法变化。

    常用类及方法的Swfit风格化

    UIColor

    将常用的标准颜色写成了只读属性,不再是方法,调用方法改变。
    这里写图片描述

    Swift 2.3 UIColor

    这里写图片描述

    Swift 3.0 UIColor

    这里写图片描述

    Swift 3.0 和 Swift 2.0 写法对比

    Any和AnyObject

    这两个类型都是Swift中很早就出现的类型,但是我们经常使用AnyObject,很少使用Any。
    AnyObject类似于OC中的id类型,表示任意的class的实例对象,但是在Swift中,例如我们常见的String和Array都变为结构体了,而且在Swift3.0中,更多的类型或者枚举被写为结构体了,AnyObject的适用范围变相被削弱了,所以在Swift3.0的API中曾经许多AnyOjbect的类型被替换为Any了。
    当然,这对于我们使用这些API没有影响,但是在我们自己定义方法时,如果需要用到AnyObject,就需要认真考虑一下该用AnyObject还是Any了。
    这里写图片描述

    Swift 3.0 和 Swift 2.0 写法对比

    BOOL属性的命名规则

    在OC中,官方建议我们将BOOL属性的getter方法命名为isXXX,Swift中由于只是将原有OCUIKit框架进行Swift转换,所以这个规则在之前是Swift中并没有体现。在Swift3.0中,这个规则被再次应用,所有的BOOL类型都重新命名为isXXX,所以以后我们的自定义类中BOOL属性的命名也应体现这个规则。
    这里写图片描述

    布尔类型的属性get方法改变

    Foundation框架部分类名去掉NS前缀

    包括:UserDefaults、URL、NotificationCenter、Bundle、Timer、Thread、RunLoop
    这里写图片描述

    Swift 3.0 和 Swift 2.3 写法对比

    常用系统提供单例类的获取方法Swift风格化

    这里写图片描述
    Swift 3.0 和 Swift 2.3 写法对比

    常用结构体的构造方法改变

    常用的结构体有:CGSize、CGPoint和CGRect。
    这里写图片描述

    Swift 3.0 和 Swift 2.3 写法对比

    Swift2.3中,使用构造方法和make函数都可以创建;

    // Make函数创建
    let _ = CGSizeMake(10, 20)
    // 构造方法创建
    let _ = CGSize(width: 10, height: 20)
    Swift3.0中,废弃make函数,只能使用构造方法创建。

    // 只能使用构造方法创建
    let _ = CGSize(width: 10, height: 20)

    转变为结构体的类

    在之前的Swift版本中,苹果引入了String、Array和Dictionary这三个结构体来代替OC中的NSString、NSArray和NSDictionary这三个类,当然这三个OC类依然可以使用。但是在平时的开发使用中,Swift的这三个结构体使用起来更方便,大部分情况下效率更高。
    在Swift3.0中,苹果又推出了以下新的结构体,原有OC类依然可以使用。并且可以相互转化。
    这里写图片描述
    新增结构体类型及对应的OC类型

    通知的变化

    这里写图片描述

    Swift 3.0 和 Swift 2.3 写法对比

    Swift 3.0 中NSNotification和Notification创建时,通知的name参数类型都变为“Notification.Name”类型,该类型创建比较复杂。

    // Swift3.0中的通知
    let _ = NSNotification(name: NSNotification.Name(rawValue: “name”), object: nil)
    let _ = Notification(name: NSNotification.Name(rawValue: “name”))

    UIViewController 返回是否显示状态栏的方法变化

    这里写图片描述
    控制器方法改为属性

    获取string的字符串长度方法的改变

    这里写图片描述
    获取字符串长度参数改变

    获取沙盒指定文件夹路径的方法变化

    获取文件路径统一交给FileManager来管理
    这里写图片描述

    获取沙盒路径参数改变

    Swift3.0中GCD语法的改变

    Swift3.0中GCD写起来更简洁了。
    这里写图片描述
    GCD语法改变

    延迟执行的代码转换的不够好。应该这样写:

    // 延迟执行代码
    DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 5) {
    print(“2324”)
    }

    Swfit的关键字的变化

    private和fileprivate

    private: 私有属性和方法,仅在当前类中可以访问,不包括分类;
    fileprivate: 文件内私有属性和方法,仅在当前文件中可以访问,包括同一个文件中不同的类。

    /// 以下所有的类都在同一个文件中
    class Test: NSObject {
    // 只能在当前大括号内访问
    private var value: Int = 0
    // 只能在当前文件内访问
    fileprivate var value1: Int = 0

    // 只能在当前大括号内访问
    private func privatePractise() {
    value = 1
    value1 = 1
    fileprivatePractise()
    fileprivatePractise1()
    print(“privatePractise方法被调用了”)
    }
    // 只能在当前文件内访问
    fileprivate func fileprivatePractise() {
    privatePractise()
    fileprivatePractise()
    fileprivatePractise1()
    print(“fileprivatePractise方法被调用了”)
    }
    }
    extension Test {
    // 只能在当前大括号内访问
    private func privatePractise1() {
    value1 = 1
    fileprivatePractise()
    fileprivatePractise1()
    print(“privatePractise方法被调用了”)
    }

    // 只能在当前文件内访问
    fileprivate func fileprivatePractise1() {
    privatePractise1()
    fileprivatePractise()
    print(“fileprivatePractise方法被调用了”)
    }
    }
    class Test2: NSObject {
    func test() {
    let t = Test()
    t.value1 = 0
    t.fileprivatePractise()
    t.fileprivatePractise1()
    }
    }

    public和open

    在Swift2.3中,pubic有两层含义:

    1. 这个元素可以在其他作用域被访问
    2. 这个元素可以在其他作用域被继承或者override

    继承是一件危险的事情。尤其对于一个framework或者module的设计者而言。在自身的module内,类或者属性对于作者而言是清晰的,能否被继承或者override都是可控的。但是对于使用它的人,作者有时会希望传达出这个类或者属性不应该被继承或者修改。这个对应的就是 final。

    final的问题在于在标记之后,在任何地方都不能override。而对于lib的设计者而言,希望得到的是在module内可以被override,在被import到其他地方后其他用户使用的时候不能被override。

    这就是 open产生的初衷。通过open和public标记区别一个元素在其他module中是只能被访问还是可以被override。

    在Swift3.0中

    • public表示当前类、属性或者方法只能在当前module内被继承或者override,在当前module意外只能被访问;
    • open表示当前类、属性或者方法可以在任何地方被继承或者override;
    • final是一个辅助修饰词,表示当前类、属性或者方法在任何地方都只能被访问,不能被继承或者override;
    • internal表示默认级别。

    /// ModuleA:
    import UIKit
    /// 这个类在ModuleA的范围外是不能被继承的,只能被访问
    public class NonSubclassableParentClass: NSObject {
    // 这个方法在ModuleA的范围外只能被访问,不能被override
    public func test() {
    print(“test”)
    }
    //这是错误的写法,因为class已经不能被集成,所以她的方法的访问权限不能大于类的访问权限
    open func bar() {
    print(“bar”)
    }
    // 这个方法在任何地方都只能被访问,不能被override
    public final func baz() {
    print(“baz”)
    }
    }
    /// 在ModuleA的范围外可以被继承
    open class SubclassableParentClass: NSObject {
    // 这个属性在ModuleA的范围外只能被访问,不能被override
    public var size: Int = 0
    // 这个方法在ModuleA的范围外只能被访问,不能被override
    public func foo() {
    print(“foo”)
    }
    // 这个方法在任何地方都可以被override
    open func baz() {
    print(“baz”)
    }
    // 这个方法在任何地方都只能被访问,不能被override
    public final func bar() {
    print(“bar”)
    }
    }
    /// 这个类在任何地方都不能被继承
    public final class FinalClass {
    }

    总结

    Swfit3.0中,访问控制权限由高到低依次为:open、public、internal(默认)、fileprivate,private。

    Swift3.0中if…where和guard…where的变化

    Swift3.0中对where关键字的使用场景进行了一些调整,在Swift2.3中,我们常这样写:

    // Swift2.3
    var value: Int?
    var num: Int?

    if let v = value, n = num where v > n {
    print(“value > num”)
    }

    value = 1
    num = 2

    guard let v = value, n = num where v > n else {
    print(“value < num”)
    return
    }
    在Swift3.0中,应该这样实现:

    // Swift3.0
    var value: Int?
    var num: Int?

    if let v = value, let n = num, v > n {
    print(“value > num”)
    }

    value = 1
    num = 2

    guard let v = value, let n = num, v > n else {
    print(“value < num”)
    return
    }

    Swift3.0中枚举的变化

    在Swift2.3中,官方使用的枚举值首字母使用大写,在Swift3.0中,统一将官方使用的枚举值首字母改为了小写。虽然自定义的枚举中枚举值首字母依然可以使用大写,但是为了和官方风格保持一致,建议枚举值首字母使用小写。

    /// 这种写法是正确的(与官方风格一致,推荐使用)
    enum Direction: String {
    case east = “east”
    case south = “south”
    case west = “west”
    case north = “north”
    }

    /// 这种写法也是正确的(与官方风格不一致,不推荐使用)
    enum Sex: Int {
    case Man = 0
    case Woman = 1
    case Other = 2
    }

    Swift3.0中方法名的Swift风格化

    在Swift的方法命名规则中,参数有两个名称,一个内部名,一个外部名。当参数有外部名时,方法调用时只显示外部名,若无外部名,则默认外部名和内部名相同。
    这里写图片描述
    外部名和内部名

    在Swift2.3中,第一个参数若没有外部名,则调用时候常省略。对于常用的UIKit和Foundation框架来说,Swift2.3中的方法名称依然是OC语言的风格。
    这里写图片描述

    Swift2.3 方法名称风格

    在Swift3.0中,第一个参数若没有外部名,则调用时显示内部名,不省略。同时将常用的UIKit和Foundation框架的方法名进行了Swift风格化,使方法调用时更简洁清晰。
    这里写图片描述

    Swift3.0 方法名称风格

    两种风格方法调用对比:
    这里写图片描述
    dismiss方法swift风格化

    建议以后自定义方法时,风格尽量和Swift3.0保持一致。
    在Swift3.0 编译器环境下两种风格对比:
    这里写图片描述

    自定义方法两种风格对比

    Swift3.0中selecter的Swift风格化

    在Swift2.2中,当我们为一个按钮添加点击事件时常常这样写:
    这里写图片描述

    Swift 2.3 中 Selector写法

    在Swift2.2更新到Swift2.3后可以看到警告告诉我们这是一个OC风格的写法,建议改为Swift风格的写法。
    在Swift3.0中两种写法依然都可以使用,但是建议统一写为Swift风格的,因为你不知道什么时候OC风格的就不被允许了。
    这里写图片描述
    Swift 3.0 中 Selector写法
    运算符的变化

    1. Swift3.0中运算符的左右两边必须不能为optional。
    2. ++和–是继承自C语言中的运算符,在Swift3.0中被移除,建议使用 x += 1来代替。
      这里写图片描述

    文/光无影(简书作者)
    原文链接:http://www.jianshu.com/p/460b5424942a
    著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。

    展开全文
  • swift3.0转4.0遇到的坑

    2018-05-15 10:38:27
    我们以斗鱼APP为例,总结swift3.0以及swift4.0转换过程中遇到的问题。 一、方法重写问题 1、swift 3.0在子类中的方法重写 我们RecommendVC类继承自BaseAnchorVC,BaseAnchorVC中包含setupUI方法,我们重写...

    我们以斗鱼APP为例,总结swift3.0以及swift4.0转换过程中遇到的问题。

    一、方法重写问题

    1、swift 3.0在子类中的方法重写

    我们RecommendVC类继承自BaseAnchorVC,BaseAnchorVC中包含setupUI方法,我们重写setupUI方法,然后再子类RecommendVC中重写setupUI方法。

    extension RecommendVC {
        override func setupUI(){
            //调用父类方法
            super.setupUI()
            collectionView.addSubview(cycleView)
            collectionView.addSubview(gameView)
            //拓宽collectionView的高度
            collectionView.contentInset = UIEdgeInsets(top: kCycleViewH+kGameViewH, left: 0, bottom: 0, right: 0)
        }
    }
    

    2、swift4.0方法的重写

    在swift4.0方法中不可使已使用这种方法重写,否则会报错。如下图所示:
    swift4.0在子类中重写方法错误
    由于无法重写方法,所以我们目前就不重写父类方法,而是重新给子类定义一个方法使用。

    二、KVC自动赋值问题

    1、在swift3.0中,我们从服务器获取数据之后,进行字典转模型,然后使用KVC自动赋值。

    class CycleModel: NSObject {
        var title : String = ""
        var pic_url : String = ""
        var anchor : AnchorModel?
        //didSet自动监控值的变化,使用guard进行检验
        var room :[String :Any]?{
            didSet{
                guard let room = room  else {
                    return
                }
                anchor = AnchorModel(dict: room)
            }
        }    
        init(dict : [String : Any]) {
            super.init()
            setValuesForKeys(dict)
        }
        //防止在KVC赋值时有找不到key导致的崩溃
        override func setValue(_ value: Any?, forUndefinedKey key: String) {}
    }

    2、在swift4.0中,直接这样使用无效。

    我们必须在属性前添加@objc,只有这样才能满足OC的KVC赋值。

    class CycleModel: NSObject {
        @objc var title : String = ""
        @objc var pic_url : String = ""
        @objc var anchor : AnchorModel?
        @objc var room :[String :Any]?{
            didSet{
                guard let room = room  else {
                    return
                }
                anchor = AnchorModel(dict: room)
            }
        }
    
        init(dict : [String : Any]) {
            super.init()
            setValuesForKeys(dict)
        }
    
        override func setValue(_ value: Any?, forUndefinedKey key: String) {
    
        }
    }
    展开全文
  • 本文介绍几点Swift 3.0相对于Swift 2.0的一些改变和使用方法 关于Swift 3.0的具体使用指南大家可以去阅读Swift 3.0中文文档(Swift 3.0 中文文档)和Swift 3.0官网文档(Swift 3.0 官网文档)

    关于Swift 3.0的具体使用指南大家可以去阅读Swift 3.0中文文档(Swift 3.0 中文文档)和Swift 3.0官网文档(Swift 3.0 官网文档

    1.首当其冲的就是闭包的修改。

    升级完Xcode8之后根据提示会默认帮你进行一些修改。但是修改完成还有500+多个错误很大一部分是闭包的修改,我的内心是这样的。

    在Swift2.3中我们写闭包是这样写:

        //Swift 2.2
        typealias detailCollectBlock = (state:Bool)->Void
    
        var detailCollect:detailCollectBlock?
    
        func detailCollect(detailCollect:detailCollectBlock)
        {
            self.detailCollect = detailCollect
        }
    
        //在需要的时候调用
        self.detailCollect?(state:true)
    
        //
        controller.detailPraise({ (state) in
            model.isPraise = (state ? "1" : "0")
                })
        //Swift3中的 使用方法1 
        typealias detailCollectBlock = (Bool)->Void
    
        var detailCollect:detailCollectBlock?
    
        func detailCollect(detailCollect:@escaping detailCollectBlock)
        {
            self.detailCollect = detailCollect
        }
        //在需要的时候调用
        self.detailCollect?(true)
    
        //在上页面回调接收的时候的用法
        controller.detailPraise(detailPraise: { (<#Bool#>) in
             model.isPraise = (state ? "1" : "0")
                })
    
        //使用方法2
        typealias detailCollectBlock = (_ state:Bool)->Void
    
        var detailCollect:detailCollectBlock?
    
        func detailCollect(_ detailCollect:@escaping detailCollectBlock)
        {
            self.detailCollect = detailCollect
        }
    
        //在需要的时候调用
        self.detailCollect?(state:true)
    
        //
        controller.detailPraise({ (state) in
            model.isPraise = (state ? "1" : "0")
                })

    这个时候大家应该就可以从代码中发现,swift3中需要定义闭包的时候不需要命名参数名,只需要告诉参数类型即可.

    现在迁移我们也可以使用方法2,这时我们的参数在使用时还是省略的(就和2.2时使用相同),外部调用闭包的时候就不需要在修改了。这样可以减少很多工作量,因为项目中的闭包实在是太多了..

    如果闭包不是在当前作用域内执行而是还要继续传递到别的函数里的话, 那就必须加上@escaping,本身的意思是逃逸的

    别接收回调的地方也和swift2.2不同,回调方法中会有block的名字,但是没有参数名了(方法2中就没有名字啦),只有参数的类型,我们需要自己来定义参数的名称.

    详情见SE-0103SE-0118

    2.在Swift2.3中我们函数在被调用时的第一个参数名会被省略,除非在前面在此定义eq:

    //这样才会在调用的时候显示参数名 swift2.2时
    func addCollect(detailId detailId)

    在Swift3中我们不需要在这样做了。会一直带有第一个参数名

    3.UIControlState等的表示状态的常量 都变成了首字母小写

    //Swift2.2
    self.toolsView?.praiseButton.setImage(UIImage.init(named: "tool_icon_like_normal"), forState: .Normal)
    
    self.phone?.componentsSeparatedByString() //swift2.2
    
    //swift3
    self.toolsView?.praiseButton.setImage(UIImage.init(named: "tool_icon_like_normal"), for: .normal)
    
    self.phone?.components(separatedBy: "-") //swift3

    这样做也是为了脱离OC冗长的方法命名,精简了语意,但是可读性还需要长时间的检验吧

    3.使用NSDictionary的修改

    dict.setObject(true, forKey: "state")
    dict.setObject(num, forKey: "key")

    在之前我们一直使用NSDictionary(<font color=gray>因为从OC转过来感觉还是NSarray和NSDictionary用起来顺手的</font> ),用来设置key的时候。现在需要添加NSCopying ,所以我都改成Dictionary啦哈哈。现在我们也应该在之后写代码的时候避免使用NSString,NSArray, NSDictionary等因为现在更加不方便了~~

    4.泛型

    //swift2.2
     var selectResult:PHFetchResult?
    
    //swift3
     var selectResult:PHFetchResult<PHAsset>?

    这个是项目中图片管理器所用到的,现在就是需要在PHFetchResult后面告诉它是什么类型,也可以是AnyObject
    这个后面还需要详细的介绍。给自己挖个坑

    5.没有了CGRectMake 改用CGRect.init来初始化或者我们写一个他的扩展.来模拟之前的CGRectmake

    //用来代替,修改的CGRectMake
    func CGRectMake(_ x:CGFloat,_ y:CGFloat,_ width:CGFloat,_ height:CGFloat)->CGRect
    {
        return CGRect.init(x: x, y: y, width: width, height: height)
    }

    6.关于颜色的初始化方法UIColor.color都去掉了括号,并且color的后缀页去掉了,新添加了Url类,也是为了脱离OC的NSUrl吧.

    7.GCD的改变 更加Swift化.

    DispatchQueue.main.async {
        let controller = LoginViewController()
        self.present(controller, animated: true, completion: nil)
                    }

    其实GCD的用法没有太多的改变,只是写法变的更加Swift,去掉了之前C语言的形式,多写读多熟悉应该就好了。

    9.NSString操作的变化

    //swift2.2
       let ch = (pinYinString as NSString).character(at: 0)
    //swift3
        let ch=pinYinString?.unicodeScalars[(pinYinString?.unicodeScalars.startIndex)!]

    因为我需要取到拼音的首字母来进行排序,所以需要获取到首字母的ASCII码。所以使用NSString更方便。但是现在不能这样用了,所以我们只能使用Swift中的这个unicodeScalars来获取啦。

    8.枚举变成了小写,自己定义的时候是大写当他变成.语法的时候Xcode页把它变成了小写

    展开全文
  • Swift 3.0 环境下使用 AFNetworking 封装网络请求业务类
  • Swift_3.0 相对于 Swift_2.2 版本发生了哪些的变化。本文件将以最直观的代码对比以及文字分析阐述。
  • Swift3.0要注意的地方

    2017-01-04 10:29:44
    都知道苹果要在下个版本的Xcode中移除Swift2.3的支持,强制开发者使用Swift3.0,这是一个很悲痛的现实��。然而正好公司的项目是OC和Swift混编的项目,里面用到了一个第三方库SwiftBond,当时SwiftBond还没有升级...
  • 随着Swift3.0的到来,一些语法悄然改变,导致很多以前的博客都不能看了= = 于是,我在这里记录一下自己的Swift3.0编写TableView的简单过程。 (1)在创建一个简单swift项目之后,先点击Main.storyboard文件,把...
  • 每当看到新的编程语言我总是会有相当大的兴趣,是的,Swift 3是一门『新语言』,因为它看起来,怎么都不像过往的 Swift。打开一个老的项目时,发现满目疮痍,基本上能标红的代码全被标红了。先来个截图提提神: 图...
  • 自学swift3.0,如果有什么错误或建议的话欢迎吐槽哦~ //1.字典的定义使用[key:value,key:value]快速定义 let dic:[String:Any] = ["name":"张三","age":22] print(dic) //数组字典 let arrDic:[[String
  • Swift3.0 类型转换 示例

    2017-03-14 19:27:46
    // // ViewController.swift // test_Swift3.0_type_casting // // Created by jeffasd on 17/3/14. // Copyright © 2017年 jeffasd. All rights reserved. // import UIKit class ViewController: UIViewContr
  • 在这里列举出一些在网上收集到的关于Swift 3.0的变化,技术更新太快,越来越fashion!!! Swift编译器和标准库的改变 1、编译器和语法变化 函数或方法参数 调用函数或方法时从第一个参数开始就必须...
  • Xcode8正式版准备上线,swift3.0也标示着这门语言日渐成熟了。 在中国国内,主流的开发语言还是Objective-C,这个主流主要还是国内用户群的问题,国内很多app都是支持的最低版本是iOS 6.0 到最新的。我在坐地铁和...
  • swift3.0自定义运算符

    2017-06-18 13:59:44
    swift3.0自定义运算符
  • Swift 3.0 变更小结

    2016-12-30 09:34:02
    Apple 官网 Swift 3.0 版本变更文档新增访问符关键字: open, fileprivateApple 官网解释 open: 公开访问接口, 类和成员变量是可以被模块内外 override public: 公开访问接口, 但是只能在模块内被 override ...
  • Swift3.0异常 Error
  • Swift 3.0 以后, GCD 的使用发生了很大的变化, 相比 Swift 2.0+ ,变得更加简洁了!首先学习几个比较重要的概念:队列 1 - 并发队列可以让多个任务并发(同时)执行(自动开启多个线程同时执行任务) 并发功能只有在...
  • Swift 3.0 实现图片轮播器 图片轮播器的实现方法一般分为两种:一种是用三张图片,通过改变显示的数据源来达到轮播的效果;另一种是通过在数据源的起始和结束位置分别插入数据源的最后一个元素和第一个元素,通过多...
1 2 3 4 5 ... 20
收藏数 9,496
精华内容 3,798
关键字:

swift3.0