• Swift 4.2Swift 4的第二次小更新,随之带来了很多很棒的改进-这使得今年将成为Swift的重要一年,并且更加确认这个社区驱动的Swift演变进程正在让一个伟大的语言变得更好。这次我们获得了一些特性比如enum case ...


    Swift 4.2是Swift 4的第二次小更新,随之带来了很多很棒的改进-这使得今年将成为Swift的重要一年,并且更加确认这个社区驱动的Swift演变进程正在让一个伟大的语言变得更好。

    这次我们获得了一些特性比如enum case 数组,warning与error编译指令,动态成员查找等等,这些都是Swift 4.1新特性(详见我的文章what's new in Swift 4.1)之外新增加的。Swift 4.2现在距离主代码分支的最终合并仅相差几天,届时只有一些重要修正会加入。如果将来有任何改变,文中这些例子也会更新。

    直到一个新版的Xcode与Swift4.2一起发布,你就可以下载最新版的Swift主干开发快照并在你当前Xcode版本上激活它。

    • 试着自己做:我创建了一个 Xcode playground展示Swift 4.2新内容,你可以编辑里面的实例。

    enum案例的衍生集合

    SE-0194介绍了一个新的CaseIterable协议,它会对一个enum中的所有cases自动生成一个数组(array)属性。

    在Swift 4.2之前,它需要 hacks, hand-coding, 或者源代码生成才能实现,但是现在你需要的仅仅是让你的enum符合CaseIterable协议。在编译时,Swift会自动生成一个allCases属性,这个allCases是一个按照你定义的顺序排列,包含所有enum’s cases的数组。

    例如,如下创建一个pasta形的enum,并要求Swift去自动为它创建一个allCases数组

    enum Pasta: CaseIterable {

    casecannelloni, fusilli, linguine, tagliatelle

    }

    你可以更进一步,像使用一个普通数组一样用这个属性- 把[Pasta]放在代码前,我们就可以这样输入

    forshape inPasta.allCases {

    print("I like eating \(shape).")

    }

    这个allCases的自动合成仅替换并不使用关联数值的enums。加入下面这些并不会自动生效,但是如果需要你可以自己添加。

    enum Car: CaseIterable {

    staticvarallCases: [Car] {

    return[.ford, .toyota, .jaguar, .bmw, .porsche(convertible: false), .porsche(convertible: true)]

    }

    caseford, toyota, jaguar, bmw

    caseporsche(convertible: Bool)

    }

    这时如果你的任何一个enum cases被标记为unavailable,Swift就不能合成allCases属性。所以如果你需要allCases,你要像下面这样自己添加它:

    enum Direction: CaseIterable {

    staticvarallCases: [Direction] {

    return[.north, .south, .east, .west]

    }

    casenorth, south, east, west

    @available(*, unavailable)

    caseall

    }

    注意:要想allCases 数组被合成,你需要添加CaseIterable而不是一个extension到你enum的原始声明中。这意味着你不能用extension反向地让已存在的enums遵守一个协议。

    Warning与error诊断指令

    SE-0196介绍新的编译指令来帮助我们在代码中标记 issues. 这对使用过Objective-C的开发者应该很熟悉了,随着Swift 4.2的发布,我们也能在Swift中使用它了

    这两个指令是#warning和#error,前者会强制Xcode在生成你的代码时发出一个警告,后者会发出一个编译错误这样你的代码就完全不能生成。下面说明了它们的用处

    • #warning主要用于提醒你或者别人一些工作还没有完成,Xcode模板常使用#warning标记一些你需要替换成自己代码的方法存根(method stubs)。

    • #error主要用于如果你发送一个库,需要其他开发者提供一些数据。比如,一个网络 API的认证密码,你需要用户输入它们自己的密码,就使用#error在继续之前强制他们更改这行代码。

    它们的使用方式都一样,#warning("Some message") 和 #error("Some message"),例如

    func encrypt(_ string: String, withpassword: String) -> String{

    #warning("This is terrible method of encryption")

    returnpassword + String(string.reversed()) + password

    }

    struct Configuration {

    varapiKey: String{

    #error("Please enter your API key below then delete this line.")

    return"Enter your key here"

    }

    }

    #warning和#error可以和已存的#if编译指令共同使用,并且只有在条件为true时才会激活。例如:

    #ifos(macOS)

    #error("MyLibrary is not supported on macOS.")

    #endif

    动态成员查找

    SE-0195介绍了一个方法,让Swift更接近脚本语言比如Python,但是用一种类型安全的方法-你不会失去任何Swift的安全性,但是你确实增强了写类似PHP和Python代码的能力。

    这个特性的核心在于一个新属性,称作@dynamicMemberLookup,它命令Swift使用一种下标方法去进行属性访问。这种下标方法,需要subscript(dynamicMember:):你可以通过所请求属性的字符串名得到,并且可以返回你想要的任何值。

    让我们看一个小例子这样你就可以知道基本了。我们可以创建一个Person结构,并且从一个字典读取它的值,像这样

    @dynamicMemberLookup

    struct Person {

    subscript(dynamicMember member: String) -> String{

    let properties = ["name": "Taylor Swift", "city": "Nashville"]

    returnproperties[member, default: ""]

    }

    }

    @dynamicMemberLookup 属性需要一个类型去执行subscript(dynamicMember:)方法,从而处理一件实际的动态成员查找工作。你可以看到,我写了一个代码,按字符串接收成员名字,并返回一个字符串。从内部看它只是在一个字典中查找这个成员名字并返回它的值。

    这种结构允许我们这样写代码:

    let person = Person()

    print(person.name)

    print(person.city)

    print(person.favoriteIceCream)

    它会干净地编译运行,即使name, city, 和favoriteIceCream并不作为Person类型中的属性存在。相反,它们都在运行时被查找。在前两次呼叫print()时,代码会打出Taylor Swift” 和 “Nashville”,而最后一次会是一个空白字符串,因为我们的字典并不存储任何favoriteIceCream

    我的subscript(dynamicMember:) 方法必须返回一串字符,这体现了Swift的类型安全性。即使你在处理动态数据,Swift依旧保证你会得到你想要的。如果你想要多种不同的类型,就执行不同的subscript(dynamicMember:)方法,像这样

    @dynamicMemberLookup

    struct Employee {

    subscript(dynamicMember member: String) -> String{

    let properties = ["name": "Taylor Swift", "city": "Nashville"]

    returnproperties[member, default: ""]

    }

    subscript(dynamicMember member: String) -> Int {

    let properties = ["age": 26, "height": 178]

    returnproperties[member, default: 0]

    }

    }

    现在任何属性都可以通过不止一种方式被访问,Swift需要你知道应该运行哪一种。它可以是内部的,比如如果你向一个只接收字符串的函数传递返回值,或者它可以是外部的,像这样

    let employee = Employee()

    let age: Int = employee.age

    无论哪种方式,Swift必须明确知道哪种下标要被呼叫

    你甚至可以强行要求subscript返回一个闭包(Closure):

    @dynamicMemberLookup

    struct User {

    subscript(dynamicMember member: String) -> (_ input: String) -> Void {

    return{

    print("Hello! I live at the address \($0).")

    }

    }

    }

    let user = User()

    user.printAddress("555 Taylor Swift Avenue")

    当它运行时,user.printAddress返回一个闭包,即输出一串字符,之后("555 Taylor Swift Avenue")部分立即通过这串字符来呼叫它。

    如果你对包含一些普通属性和方法的类型使用动态成员下标,这些属性和方法会始终代替动态成员被使用。例如,我们可以定义一个附有动态成员下标的Singer结构,其中内置有name属性

    struct Singer {

    publicvarname = "Justin Bieber"

    subscript(dynamicMember member: String) -> String{

    return"Taylor Swift"

    }

    }

    let singer = Singer()

    print(singer.name)

    这个代码会打出“Justin Bieber”,因为name属性会代替动态成员下标被使用

    @dynamicMemberLookup完全参与到Swift的类型系统中,这意味着你可以用在protocols, structs, enums,和 classes中,即使classes被标记为@objc

    实际中,这意味着两件事情。首先,你可以使用@dynamicMemberLookup建立一个类,并且任何从它继承的类都会自动为@dynamicMemberLookup属性. 所以,下例会打出“I’m a sandwich”,因为HotDog继承于Sandwich

    @dynamicMemberLookup

    classSandwich {

    subscript(dynamicMember member: String) -> String{

    return"I'm a sandwich!"

    }

    }

    classHotDog: Sandwich { }

    let chiliDog = HotDog()

    print(chiliDog.description)

    注意:如果你不认为热狗是三明治,那就来我的推特打我呀

    第二,你可以通过在协议中定义,来反向地让其他类型使用@dynamicMemberLookup,通过扩展协议 添加一个默认执行的subscript(dynamicMember:),之后让其他类型按你想要的方式符合你的协议。

    例如,下例创建了一个新的Subscripting协议,提供一个默认的subscript(dynamicMember:),它会返回一条信息,之后扩展Swift的String去使用这个协议。

    @dynamicMemberLookup

    protocol Subscripting { }

    extension Subscripting {

    subscript(dynamicMember member: String) -> String{

    return"This is coming from the subscript"

    }

    }

    extension String: Subscripting { }

    let str = "Hello, Swift"

    print(str.username)

    在他的Swift演变提案中, Chris Lattner也给了一个JSON enum的例子,即使用动态成员查找通过JSON为引导(navigating)建立更自然的语法

    @dynamicMemberLookup

    enum JSON {

    caseintValue(Int)

    casestringValue(String)

    casearrayValue(Array)

    casedictionaryValue(Dictionary)

    varstringValue: String? {

    ifcase.stringValue(let str) = self {

    returnstr

    }

    returnnil

    }

    subscript(index: Int) -> JSON? {

    ifcase.arrayValue(let arr) = self {

    returnindex < arr.count ? arr[index] : nil

    }

    returnnil

    }

    subscript(key: String) -> JSON? {

    ifcase.dictionaryValue(let dict) = self {

    returndict[key]

    }

    returnnil

    }

    subscript(dynamicMember member: String) -> JSON? {

    ifcase.dictionaryValue(let dict) = self {

    returndict[member]

    }

    returnnil

    }

    }

    没有动态成员查找你将需要为JSON enum 引导一个实例 ,像这样

    let json = JSON.stringValue("Example")

    json[0]?["name"]?["first"]?.stringValue

    但是有了动态成员查找你可以用下面这个

    json[0]?.name?.first?.stringValue

    我认为这个例子特别重要,因为它指出了@dynamicMemberLookup的要点,它能把定制下标转化为简单的点语法

    注意:使用动态成员查找意味着如果不具备全部的有效性,代码的完成会损失很多,因为不存在东西去完成。尽管这不算是什么惊喜,这也是Python IDEs有时不得不处理的问题。Chris Lattner (SE-0195的作者)在他的提案中讨论了未来关于代码完成的可能性,它值得一读

    增强的条件一致性

    条件一致性在Swift 4.1中引入,允许当特定条件被满足时,类型就去符合一个协议。

    例如,如果我们有Purchaseable协议

    protocol Purchaseable {

    func buy()

    }

    和一个符合这个协议的简单类型

    struct Book: Purchaseable {

    func buy() {

    print("You bought a book")

    }

    }

    之后如果数组中所有元素符合Purchasable,我们就可以让数组符合Purchaseable,

    extension Array: Purchaseable where Element: Purchaseable {

    func buy() {

    foritem inself {

    item.buy()

    }

    }

    }

    在编译时它运行的很好,但是有一个问题,如果你要在运行时查询一个条件一致性,你的代码会崩溃,因为这在Swift 4.1中不支持。

    现在,在Swift 4.2中已经被修复,所以如果你收到一种类型的数据,想要检查它是否可以被转化为一个条件一致性协议,它可以做到了。

    例如

    let items: Any = [Book(), Book(), Book()]

    iflet books = items as? Purchaseable {

    books.buy()

    }

    另外,对Hashable一致性自动合并的支持在Swift 4.2被大幅提高,来自Swift 标准库的几个内置类型,包括optionals, arrays, dictionaries, 和 ranges-现在当他们的元素符合Hashable时会自动符合Hashable 协议

    例如:

    struct User: Hashable {

    varname: String

    varpets: [String]

    }

    Swift 4.2 可以为这个结构自动合并 Hashable一致性, 但Swift 4.1不能.

    本地集合元素移除

    SE-0197介绍一个新的 removeAll(where:) 方法,它具有高性能,本地为集合过滤。给它一个闭合环境运行,它会除去所有符合条件的目标。

    例如,如果你有一个名称的collection,并且想移除叫“Terry”的人,你可以用这个

    varpythons = ["John", "Michael", "Graham", "Terry", "Eric", "Terry"]

    pythons.removeAll { $0.hasPrefix("Terry") }

    print(pythons)

    现在,你也许会想到你可以通过filter()来实现,像这样

    pythons = pythons.filter { !$0.hasPrefix("Terry") }

    然而,这样并不能有效利用存储,它指定你不需要的而不是你想要的,而且更高级的本地方法会带来一系列复杂性,这些是新手很讨厌的。

    布尔值切换

    SE-0199为布尔值带来了一个新的toggle()方法,即在true和false之间翻转。这个引发了Swift社区的一片讨论,部分人认为它太细枝末节,也有部分是因为Swift论坛的讨论时不时变得失控。

    执行这个提案的完整代码仅仅几行

    extension Bool {

    mutating func toggle() {

    self = !self

    }

    }

    然而,它最终有助于让Swift代码变得更自然

    varloggedIn = false

    loggedIn.toggle()

    就像这个提案中提到,它在更复杂的数据结构中特别有用:

    myVar.prop1.prop2.enabled.toggle()避免了在手动操作时潜在的输入错误。=

    这个提案让Swift更简单安全的写入,并且完全是附加的,所以我认为大部分人会很快去使用它。

    展望Swift 5.0

    苹果形容Swift 4.2为”为了实现Swift 5中ABI稳定性的中继点”,但是我希望你能明白这是一个很保守的声明-我们正在得到一些很好的新特性,既有对过去特性的改进,也有ABI的改变。

    更好的是,在最终发布之前我们也许还会看到新的特性被加入-我们可能同时看到SE-0192, SE-0193, SE-0202, 和SE-0206的到来。

    然而,我们归根结底依旧期待Swift 5.0能提供大家盼望已久的ABI稳定性。苹果谨慎小心步步为营的方法似乎会走的更好,而且它让人怀有希望,觉得Swift 5.0将会更值得等待。

    展开全文
  • override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. let rect1 = CGRect(x: 30, y: 50, width: 200, height...
     override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view, typically from a nib.
            let rect1 = CGRect(x: 30, y: 50, width: 200, height: 200)
            let view1 = UIView(frame: rect1)
            view1.backgroundColor = UIColor.brown
    
            let rect2 = CGRect(x: 90, y: 120, width: 200, height: 200)
            let view2 = UIView(frame: rect2)
            view2.backgroundColor = UIColor.purple
    
            self.view.addSubview(view1)
            self.view.addSubview(view2)

    展开全文
  • 1、设置自定义的右滑手势,别忘记禁止系统右滑手势let target = self.interactivePopGestureRecognizer?.delegate let pan:UIPanGestureRecognizer = UIPanGestureRecognizer.init(target: target!...

    1、设置自定义的右滑手势,别忘记禁止系统右滑手势

    let target = self.interactivePopGestureRecognizer?.delegate
            let pan:UIPanGestureRecognizer = UIPanGestureRecognizer.init(target: target!, action: Selector(("handleNavigationTransition:")))
            self.view.addGestureRecognizer(pan)
    
            self.interactivePopGestureRecognizer?.isEnabled = false
            pan.delegate = self
    

    2、UIGestureRecognizerDelegate代理方法筛选手势作用条件

    设置根控制器右滑手势不起作用,如果不设置,一旦在根控制器中右滑,将造成app卡死

    
        func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
            return self.childViewControllers.count > 1
        }

    这样即可

    展开全文
  • Swift iOS 函数说明

    2018-03-07 08:06:06
    # 函数## 4.1 函数的定义与调用函数是一个组织在一起的程序代码集合,用来完成...Swift使用关键字func进行函数的定义。当定义一个函数时,可以为其定义一个或多个不同的名称,类型的值,作为函数的输入参数。当该...
    # 函数


    ## 4.1 函数的定义与调用
    函数是一个组织在一起的程序代码集合,用来完成某个特定的功能。为了提高代码的复用性,通常对代码进行抽取,将能够完成同一个任务的代码放置在一起,可作为一个函数使用。给定函数一个名称标识,当执行其任务时,就可以用这个标识来进行函数的调用。
    Swift使用关键字func进行函数的定义。当定义一个函数时,可以为其定义一个或多个不同的名称,类型的值,作为函数的输入参数。当该函数完成时,将返回输出定义的类型。
    每一个函数都有一个函数名来描述它的功能。通过函数名以及对应类型的参数值,可调用这个函数,函数的参数传递顺序必须与参数列表中的顺序相同。
    函数定义的格式如下所示:


    ~~~
     func 函数(参数变量: 类型, 参数变量: 类型...) -> 返回类型
     {
         程序语句
         程序语句
         ...
         return 结果
     }
    ~~~
       
    在下面的 码中,我们定义了一个无参数并且无返回类型的函数:


    ~~~java
     func sayHello()
     {
         print("Hello,Swift")
     }
    ~~~


    函数定义之后,我们可以通过函数名以及对应类型的参数值来调用函数,函数的参数传递的顺序必须与参数列表相同。由于sayHello函数是一个无参函数,所以你可以直接使用函数的名称,以调用该函数。


    ~~~java
     sayHello()
    ~~~


    sayHello函数极为简单,当调用该函数后,将在控制台输出“Hello,Swift”信息。
    在下面的代码中,我们定义了拥有两个参数和返回值的函数。所有的参数都被放置在函数名右侧的小括号内。指定的函数的返回值类型以箭头 -> (一个连字符后跟一个右尖括号)以及随后类型的名称作为函数。


    ~~~java
     func sum(num1: Int, num2: Int) -> Int 
     {
         return num1 + num2
     }
    ~~~


    ## 4.2 为参数设置默认值
    在Swift环境中,可以为函数的参数设置默认值。


    ~~~java
     func sum(num1: Int, num2: Int = 2) -> Int
     {
         print(num1 + num2)
     }
    ~~~


    在sum方法的参数声明区域,当添加第二个参数时,在参数类型的右侧添加了一个等号,并在等号后面添加了默认参数值。当调用该函数时,值需要传入第一个参数即可。当然你也可以填写上第二个参数。


    ~~~java
     sum(num1: 1)
     sum(num1: 1, num2: 3)
    ~~~


    ## 4.3 设置可变的函数参数数量
    在定义函数时,如果你不确定参数的数量,可通过在变量类型后面加(...),定义可变参数,一个函数最多能有一个可变参数。为避免在调用函数时产生歧义,一个函数如果有一个或多个参数,并且还有一个可变参数,一定要把可变参数放在最后。


    ~~~java
     func getCount(nums: Int...)
     {
         print(nums.count)
     }


     getCount(nums: 1, 2, 3)
     getCount(nums: 1, 2, 3, 4, 5, 6)
    ~~~


    ## 4.4 函数作为参数和返回类型
    Swift中的每个函数都有一个类型,包括函数的参数类型和返回类型。你可以方便的使用此类型,像其他类型一样。


    ### 4.4.1 函数作为参数
    这使得它很容易将函数作为参数,传递给其他的函数,甚至从函数中返回函数类型。


    ~~~java
     func getMin(num1: Int, num2: Int) -> Int
     {
         var minNum = (num1 < num2) ? num1: num2
         return minNum
     }


     func getMax(num1: Int, num2: Int) -> Int
     {
         var maxNum = (num1 > num2) ? num1: num2
         return maxNum 
     }


     func printResult(mathFunc: (Int, Int) -> Int, num1: Int, num2: Int)
     {
         print(mathFunc(num1, num2))
     } 


     // 调用的地方
     printResult(mathFunc: getMin, num1: 1, num2: 2)
     printResult(mathFunc: getMax, num1: 1, num2: 2)
    ~~~


    以上代码分别求出了两个参数中的最小值和最大值,最终的输出结果如下:


    ~~~
     1
     2
    ~~~


    ### 4.4.2 函数作为返回类型
    一个函数除了可被作为另一个函数的参数使用,同时也可以作为其他函数的返回类型。在下面的代码中,通过将函数作为另一个函数的返回类型,实现了与上一个例子中同样的功能。


    ~~~java
     func getMin(num1: Int, num2: Int) -> Int
     {
         var minNum = (num1 < num2) ? num1: num2
         return minNum
     }


     func getMax(num1: Int, num2: Int) -> Int
     {
         var maxNum = (num1 > num2) ? num1: num2
         return maxNum 
     }


     func chooseFunc(needBigger: Bool) -> (Int, Int) -> Int
     {
         let func = needBigger ? getMax : getMin
         return func
     } 


     // 调用的地方
     let func = chooseFunc(needBigger: true)
     print(func(2, 3))  // 输出结果为: 3
    ~~~


    ## 4.5 元组作为函数的返回类型,实现多个返回值
    在日常的开发过程中,可能会遇到这样的场景:当用户通过用户名(一般为邮箱或手机号)和密码来登陆系统后,需要从服务器获取用户的姓名,用户级别和头像信息。对于像这样需要同时返回多条信息的函数,你可以使用元组来组织函数返回的所有内容。


    ~~~java
     func getUserInfo(userId: String) -> (userName: String, userlevel: Int, photoPath: String)
     {
         let userName = "paul"
         let userLevel = 3
         let photoPath = "http://www.baidu.com"


         return (userName, userLevel, photoPath)
     }
    ~~~


    在第一行代码中,定义了一个名为getUserInfo的函数,其包含一个参数userId,通过该参数,可以从服务器查询指定用户的信息,并设置返回类型为(String, Int, String),分别存储用户的姓名,级别,头像路径等信息。
    服务器以元组形式返回用户属性信息之后,在控制台打印输出元组的信息即可。


    ~~~java
     let msg = getUserInfo(userId: "0001")
     print(msg.0) //输出结果: pual
     print(msg.1) //输出结果: 3
     print(msg.2) //输出结果: http://www.baidu.com
    ~~~


    ## 4.6 使用函数类型
    使用函数类型就跟使用其他的类型一样。比如可以定义一个常量或变量,其类型就是函数,而且可以给这个函数赋值。
    首先定义一个普通的函数,它包含两个整型参数,然后计算并返回两个参数之和。


    ~~~java
     func getTotal(num1: Int, num2: Int) -> Int
     {
         return num1 + num2
     }
    ~~~


    接着定义了一个newFunc的变量,其类型是两个整型参数并返回整型的函数,并让这个变量指向getTotal函数。


    ~~~java
     let newFunc: (Int, Int) -> Int = getTotal
     let result = newFunc(1, 1)
     print(result)  //输出结果: 2
    ~~~


    在给使用函数类型定义变量时,可以省略函数类型的书写。


    ~~~java
     let newFunc = getTotal
     let result = newFunc(1, 1)
     print(result)  //输出结果: 2
    ~~~


    那么如何使用无参数并且无返回值的函数类型呢?首先定义一个次类型的函数。


    ~~~java
     func printHello()
     {
         print("Hello, Swift")
     }
    ~~~


    printHello函数没有包含任何参数,也没有任何返回值,当需要定义该函数类型的常量或变量时,可以使用以下方式:


    ~~~java
     let a1: ()->() = printHello
     a1()
    ~~~


    ## 4.7 函数的输入输出参数
    一般默认在函数中定义的参数都是常量参数,也就是这个参数只可以查询使用,不能改变它的值。
    如果想要声明一个变量参数,可以在参数定义前加 inout 关键字,这样就可以改变这个参数的值。


    ~~~java
     func getName(_ name: inout String)
    ~~~


    此时这个name的值可以在函数在改变。
    一般默认的参数传递都是传值调用,而不是传引用。所以传入的参数在函数内改变,并不影响原来的哪个参数,传入的只是这个参数的副本。
    当传入的参数作为输入输出参数时,需要在参数名前加 & 符,表示这个值是可以被函数改变的。


    ~~~java
     func swap(_ a: inout Int, _ b : inout Int)
     {
         let tmp = a
         a = b
         b = tmp
     }


     var x = 1
     var y = 5
     swap(&x, &y)
     print("x=\(x),y=\(y)")
    ~~~


    ## 4.8 函数的嵌套
    一个函数也可以写在其他函数之中,来封装一个嵌套函数,用以实现仅在一定范围内起作用的功能。


    ~~~java
     func getTotal()
     {
         func getNumber()
         {
             print("GetNumber")
         }
         getNumber()
     }


     getTotal()
    ~~~


    需要注意的是,被嵌套的子函数只能在其父函数的内部使用,在父函数的外部是无法被调用的。









































































    展开全文
  • 经过大约一个月的时间的适配,项目正式使用XCode10(以下简称为10 or XC10)大部分库都升级为Swift4.2(以下简称为 4.2 or S4.2),下面是适配过程中遇到的一些坑。 1. Swift4、Swift4.2混编 如果你对项目是小的独立...

    以下是2018年10月23日更新

    经过大约一个月的时间的适配,项目正式使用XCode10(以下简称为10 or XC10)大部分库都升级为Swift4.2(以下简称为 4.2 or S4.2),下面是适配过程中遇到的一些坑。

    1. Swift4、Swift4.2混编

    如果你对项目是小的独立项目,完全可以全部升级为4.2,你可以略过第一条;如果你依赖了一些第三方的库,且没有升级4.2,你可以继续看这一条。目前测试的结果来看,Swift4 和 S4.2的混编没有什么大的问题,如果你是通过cocoapod引入的可以在Podfile中加入如下代码:

    swift_41_pod_targets = ['your_target_name']
    post_install do |installer|
      installer.pods_project.targets.each do |target|
        if swift_41_pod_targets.include?(target.name)
          target.build_configurations.each do |config|
            config.build_settings['SWIFT_VERSION'] = '4.1'
          end
        end
      end
    end
    复制代码

    2. NSDataAsset

    升级XC10和S.2之前,项目里面有些对 'NSDataAsset' 的错误使用: 用‘NSDataAsset’读ImageAsset中的图片,这个是不正确的,但是却可以工作,这次升级修复了这个BUG。

    正确的做法使用'DataAsset',然后才可以用‘NSDataAsset’读取数据,我由于不够认真且经验不足还以为是个BUG,给Apple提了个BUG。。。[捂脸]

    3. 第三方库的重命名 typealias

    为了方便的适配S4.2对UIKit中的重命名,有些第三方使用typealias对一些类型进行了重命名,以 RxSwift 为例子,RxSwift中就有如下代码:

    #if swift(>=4.2)
        public typealias UIControlEvents = UIControl.Event  private
    #endif
    复制代码

    这会导致一些重命名的类型即使不改也不会报错,但是一旦去掉了对某个库的依赖就会引入新的问题。

    4.Delegate 的 Access Modifier

    在升级S4.2过程中,XC偶尔会提示需要给某些Delegate方法添加 private修饰符,不要为了消除这个⚠️添加private,可能会导致Delegate永远不被调到;另外,如果是一个public或者openclass,协议方法记得也要加上public,否则会出一样的问题,具体原因我还在测试,但是现象是这样的,有新的见解欢迎评论区讨论。

    5. 机型适配问题,iPhone XS Max字体变大

    有些同事遇到XC9构建的安装包在iPhone XS Max上会有字体变大的情况,这个貌似是普遍现象,微信也有,使用XC10构建安装包可以解决这个问题,但是会遇到问题6

    ###6. iOS9.3以下系统Crash率飙升 使用XC10构建安装包可以解决问题5,但是iOS9.3以下的系统Crash到让你怀疑人生

    以下是2018年9月18日内容

    AVAudioSession.sharedInstance().setCategory()

    disappeared

    Swift 4.2 中 iOS10以下不能用 AVAudioSession.sharedInstance() setCategory

    可选方案:
    • 使用OC实现该部分,然后使用Swift调用
    • 放弃 iOS9用户体验

    参考地址

    do {
        if #available(iOS 11.0, *) {
            try audioSession.setCategory(.playback, mode: .default, policy: .longForm, options: [])
        } else if #available(iOS 10.0, *) {
            try audioSession.setCategory(.playback, mode: .default, options: [])
        } else {
            // Compiler error: 'setCategory' is unavailable in Swift
            try audioSession.setCategory(AVAudioSession.Category.playback)
        }
    } catch let error {
        print("Unable to configure audio sesson category: \(error)")
    }
    复制代码

    NSUnderlineStyle(.patternSolid、.none)

    disappeared

    可选方案:
    • .none

      mutableAttributedString.addAttribute(NSAttributedString.Key.underlineStyle, value: NSUnderlineStyle.none.rawValue, range: range) ^~~~~ 'none' is unavailable: use [] to construct an empty option set

    Wrong: mutableAttributedString.addAttribute(NSAttributedString.Key.underlineStyle, value: [], range: range) Right: mutableAttributedString.addAttribute(NSAttributedString.Key.underlineStyle, value: 0, range: range)

    • 使用 CTUnderlineStyleModifiers

      // 没有测试 NSUnderlineStyle.init(rawValue: Int(CTUnderlineStyleModifiers.patternSolid.rawValue))

    • 使用其他默认值

    下面是Rename操作

    UIKit

    #Swift4/UIKit

    UITableViewCell

    Swift 4 Swift 4.2
    UITableViewCellStyle UITableViewCell.CellStyle

    UIEvent

    Swift 4 Swift 4.2
    UIEventSubtype UIEvent.EventSubtype

    UITableView

    Swift 4 Swift 4.2
    UITableViewScrollPosition UITableView.ScrollPosition
    UITableViewAutomaticDimension UITableView.automaticDimension
    UITableViewCellEditingStyle UITableViewCell.EditingStyle
    UITableViewRowAnimation UITableView.RowAnimation
    UITableViewStyle UITableView.Style
    UITableViewCellAccessoryType UITableViewCell.AccessoryType

    UIControl

    Swift 4 Swift 4.2
    UIControlEvents UIControl.Event

    UIWindow

    Swift 4 Swift 4.2
    UIWindowLevelAlert UIWindow.Level.alert
    UIKeyboardFrameEndUserInfoKey UIResponder.keyboardFrameEndUserInfoKey
    UIKeyboardFrameBeginUserInfoKey UIResponder.keyboardFrameBeginUserInfoKey
    UIKeyboardAnimationDurationUserInfoKey UIResponder.keyboardAnimationDurationUserInfoKey
    UIKeyboardAnimationCurveUserInfoKey UIResponder.keyboardAnimationCurveUserInfoKey
    UIKeyboardIsLocalUserInfoKey UIResponder.keyboardIsLocalUserInfoKey
    UIWindowDidBecomeVisible UIWindow.didBecomeVisibleNotification
    UIWindowDidBecomeHidden UIWindow.didBecomeHiddenNotification
    UIWindowDidBecomeKey UIWindow.didBecomeKeyNotification
    UIWindowDidResignKey UIWindow.didResignKeyNotification
    UIKeyboardWillShow UIResponder.keyboardWillShowNotification
    UIKeyboardDidShow UIResponder.keyboardDidShowNotification
    UIKeyboardWillHide UIResponder.keyboardWillHideNotification
    UIKeyboardDidHide UIResponder.keyboardDidHideNotification

    UIViewController

    Swift 4 Swift 4.2
    open func addChildViewController(_ childController: UIViewController) open func addChild(_ childController: UIViewController)
    open func willMove(toParentViewController parent: UIViewController?) open func willMove(toParent parent: UIViewController?)
    open func didMove(toParentViewController parent: UIViewController?) open func didMove(toParent parent: UIViewController?)
    open func removeFromParentViewController() open func removeFromParent()

    UIActivity

    Swift 4 Swift 4.2
    UIActivityType UIActivity.ActivityType

    UIActivityIndicatorView

    Swift 4 Swift 4.2
    activityIndicator.activityIndicatorViewStyle activityIndicator.style

    UIAlertController

    Swift 4 Swift 4.2
    UIAlertActionStyle UIAlertAction.Style
    UIAlertControllerStyle UIAlertController.Style

    UIPageViewController

    Swift 4 Swift 4.2
    UIPageViewControllerNavigationDirection UIPageViewController.NavigationDirection
    UIPageViewControllerSpineLocation UIPageViewController.SpineLocation
    UIPageViewControllerNavigationOrientation UIPageViewController.NavigationOrientation
    UIPageViewControllerTransitionStyle UIPageViewController.TransitionStyle
    UIPageViewControllerOptionsKey UIPageViewController.OptionsKey

    UINavigationController

    Swift 4 Swift 4.2
    UINavigationControllerOperation UINavigationController.Operation

    UIGestureRecognizer

    Swift 4 Swift 4.2
    UIGestureRecognizerStatePossible UIGestureRecognizer.State.possible
    UIGestureRecognizerStateBegan UIGestureRecognizer.State.began
    UIGestureRecognizerStateChanged UIGestureRecognizer.State.changed
    UIGestureRecognizerStateEnded UIGestureRecognizer.State.ended
    UIGestureRecognizerStateCancelled UIGestureRecognizer.State.cancelled
    UIGestureRecognizerStateFailed UIGestureRecognizer.State.failed
    UIGestureRecognizerStateRecognized UIGestureRecognizer.State.recognized

    NSLayoutFormat

    Swift 4 Swift 4.2
    NSLayoutFormatOptions NSLayoutConstraint.FormatOptions

    UIEdgeInsets

    Swift 4 Swift 4.2
    public func UIEdgeInsetsMake(_ top: CGFloat, _ left: CGFloat, _ bottom: CGFloat, _ right: CGFloat) -> UIEdgeInsets UIEdgeInsets(top: CGFloat, left: CGFloat, bottom: CGFloat, right: CGFloat)
    public func UIEdgeInsetsInsetRect(_ rect: CGRect, _ insets: UIEdgeInsets) -> CGRect public func inset(by insets: UIEdgeInsets) -> CGRect

    UIFontDescriptor

    Swift 4 Swift 4.2
    UIFontDescriptorSymbolicTraits UIFontDescriptor.SymbolicTraits

    UIImage

    Swift 4 Swift 4.2
    UIKIT_EXTERN NSData * __nullable UIImagePNGRepresentation(UIImage * __nonnull image); public func pngData() -> Data?
    NSData * __nullable UIImageJPEGRepresentation(UIImage * __nonnull image, CGFloat compressionQuality); public func jpegData(compressionQuality: CGFloat) -> Data?

    UIApplication

    Swift 4 Swift 4.2
    UIApplicationDidEnterBackground UIApplication.didEnterBackgroundNotification
    UIApplicationWillEnterForeground UIApplication.willEnterForegroundNotification
    UIApplicationDidFinishLaunching UIApplication.didFinishLaunchingNotification
    UIApplicationDidBecomeActive UIApplication.didBecomeActiveNotification
    UIApplicationWillResignActive UIApplication.willResignActiveNotification
    UIApplicationDidReceiveMemoryWarning UIApplication.didReceiveMemoryWarningNotification
    UIApplicationWillTerminate UIApplication.willTerminateNotification
    UIApplicationSignificantTimeChange UIApplication.significantTimeChangeNotification
    UIApplicationWillChangeStatusBarOrientation UIApplication.willChangeStatusBarOrientationNotification
    UIApplicationDidChangeStatusBarOrientation UIApplication.didChangeStatusBarOrientationNotification
    UIApplicationDidChangeStatusBarFrame UIApplication.didChangeStatusBarFrameNotification
    UIApplicationBackgroundRefreshStatusDidChange UIApplication.backgroundRefreshStatusDidChangeNotification
    UIApplicationProtectedDataWillBecomeUnavailable UIApplication.protectedDataWillBecomeUnavailableNotification
    UIApplicationProtectedDataDidBecomeAvailable UIApplication.protectedDataDidBecomeAvailableNotification
    UIApplicationUserDidTakeScreenshot UIApplication.userDidTakeScreenshotNotification
    UIApplicationOpenSettingsURLString UIApplication.openSettingsURLString
    UIApplicationLaunchOptionsKey UIApplication.LaunchOptionsKey
    UIInterfaceOrientationIsLandscape() UIApplication.shared.statusBarOrientation.isLandscape

    UIView

    Swift 4 Swift 4.2
    func bringSubview(toFront view: UIView) func bringSubviewToFront(_ view: UIView)
    UIViewAnimationOptions UIView.AnimationOptions()

    Foundation

    NSAttributedString

    Swift 4 Swift 4.2
    NSAttributedStringKey NSAttributedString.Key

    QuartzCore

    CAShapeLayer

    Swift 4 Swift 4.2
    kCALineCapRound CAShapeLayerLineCap.round
    kCALineCapButt CAShapeLayerLineCap.butt
    kCALineCapSquare CAShapeLayerLineCap.square
    kCALineJoinMiter CAShapeLayerLineJoin.miter
    kCALineJoinRound CAShapeLayerLineJoin.round
    kCALineJoinBevel CAShapeLayerLineJoin.bevel
    kCAFillRuleNonZero CAShapeLayerFillRule.nonZero
    kCAFillRuleEvenOdd CAShapeLayerFillRule.evenOdd

    参考资料

    Swift-Migration-4.2

    转载于:https://juejin.im/post/5ba0dfb9e51d450e4a1babcb

    展开全文
  • Xcode 10可在Mac App Store中使用,包括适用于iOS 12,watchOS 5,macOS 10.14和tvOS 12的SDK.Xcode 10支持iOS 8及更高版本,tvOS 9及更高版本以及watchOS 2及更高版本的设备上调试。Xcode 10需要Mac运行macOS ...
  • 当前环境: Xcode10.0 Swift4.2 iOS SDK 12.1 为此做了下面的Demo,演示了如何在Swift的Framework中引用OC对象。 Demo: github.com/zColdWater/… 具体步骤 创建Swift Framework 添加OC对象的 .h .m 文件 在Header....
  • 这是公司iOS Framework的制作与发布流程的踩坑记录。 主要需求和情况为: 1.Swift工程 2.无其他第三方库的依赖 3.无xib、storyboard等资源文件 4.打包为Framework 5.发布到CocoaPods 使用的工具、语言版本 Xcode:...
  • Get started with push notifications on iOS! Currently updated to: Platform: iOS12; Language: Swift4.2; Editor: Xcode10
  • Core Data By Tutorials Fifth Edition IOS 12 and Swift 4.2 edittion Ray Wenderlich Download PDF
  • 这里写自定义目录标题iOS 集成极光推送 (swift版)1、使用cocoapods安装极光推送SDK2、注册及配置极光推送相关3、使用别名做唯一标识推送到指定用户的设备搞定!!! iOS 集成极光推送 (swift版) 1、使用cocoapods...
  • 最近学习ios编程,启用了swift语言,非常高效的一门y
  • // 后台任务标识 var backgroundTask:UIBackgroundTaskIdentifier! = nil func applicationDidEnterBackground(_ application: UIApplication) { // 延迟程序静止的时间 DispatchQueue....
  • iOSSwift4.2编码教程

    2020-04-10 23:33:57
    iOSSwift最新版本4.2的教程,希望对你有帮忙,中文翻译,格式棒棒。2018-8-16
  • swift5.2 方法 将 [String] 转换成 String let class3_2: [String] = ["LiMing", "LiHua", "XiaoWang", "Uzi"] let studentsName = class3_2.joined(separator: "") 判断是否包含所求字符串 if studentsName....
  • Learn how to use RxSwift to create complex, reactive applications on iOS. Currently updated to: Platform: iOS12; Language: Swift4.2; Editor: Xcode10
  • 其实Core Data是OS X和iOS SDK中以图表方式对象进行管理并进行永久存储的framework。这就意味着Core Data可以用于存储数据,但是它不是类似MySQL或SQLite的传统数据库。虽然它可以使用SQLite作为后台的数据存储仓库...
  • 章节目录如下: 第 1 章 游戏的设计 … 9 1.1 设计游戏引擎 …9 1.2 创建基于继承的设计…10 1.3 创建基于组件的设计…12 1.4 用 GameplayKit 创建基于组件的游戏设计 … 16 1.5 计算屏幕的帧刷新时间 …18 ...
  • wift4.2文档 epub和pdf版本, mobi版本凌乱,不能使用,kindle用户直接pdf比较好
  • 基于swift4.2常见的全局常量和函数集合(objective-c称之为宏定义,swift没有宏这个概念)
1 2 3 4 5 ... 20
收藏数 1,607
精华内容 642
热门标签