3中的新特征

by admin on 2019年9月2日

提出读二回swift
blog
来掌握OC与swift分歧以及swift版本变动细节

相较于Swift 2.2 , Swift 3做了很大的更动,慢慢脱离OC的阴影。
语法上多多对象去掉了NS最早,去掉了麻烦的命名。如 UIColor.redColor() 改为
UIColor.red , 产生了品质,还可能有方法的第贰个参数假使不钦定
_调用的时候也要写参数名等等…

OC id -> Swift Any

可取,无需手动装箱
使得OC API更灵活

OC Swift2 Swift3
id AnyObject Any
NSArray * [AnyObject] [Any]
NSDictionary * [NSObject:AnyObject] [AnyHashable:Any]
NSSet * Set<NSObject> Set<AnyHashable>

亟待留神的而是swift2不再提供隐式调换,由此NS桥接的急需你体现转换

正文首要研究Swift 3中的一些坑和动用进程中的一些小本事,排行无理由~~

Overriding methods and conforming to protocols

取名符合OC的正经,id->Any

// Swift 2
class Foo: NSObject, NSCopying {
    override func isEqual(_ x: AnyObject?) -> Bool { ... }
    func copyWithZone(_ zone: NSZone?) -> AnyObject { ... }
}

// Swift 3
class Foo: NSObject, NSCopying {
    override func isEqual(_ x: Any?) -> Bool { ... }
    func copy(with zone: NSZone?) -> Any { ... }
}

AnyObject 、Any

事先全部项目为主只用 AnyObject
代表大多实例,基本也不和Any有哪些交集。因为Swift 2 针对Int、String
等结构体举行了转移,编写翻译器会活动桥接为NSNumber和NSString这种对象类型
,在swift3中AnyObject无法代表结构体了 。而 Any 能够表示 struct 、 class
、 func 等差相当少具有类型。

Untyped Collections

隐式桥接子虚乌有了,须要运用as,swift3导入的cocoa接受了Any/AnyHashable,由此对于集结也得以利用[AnyHashable:Any]

// Swift 2
struct State {
    var name: String
    var abbreviation: String
    var population: Int

    var asPropertyList: [NSObject: AnyObject] {
        var result: [NSObject: AnyObject] = [:]//也可以使用NSDictionary
        // Implicit conversions turn String into NSString here…
        result["name"] = self.name
        result["abbreviation"] = self.abbreviation
        // …and Int into NSNumber here.
        result["population"] = self.population
        return result
    }
}

let california = State(name: "California",
                       abbreviation: "CA",
                       population: 39_000_000)
NSNotification(name: "foo", object: nil,
               userInfo: california.asPropertyList)

// Swift 3
struct State {
    var name: String
    var abbreviation: String
    var population: Int

    // Change the dictionary type to [AnyHashable: Any] here...
    var asPropertyList: [AnyHashable: Any] {
        var result: [AnyHashable: Any] = [:]
        // No implicit conversions necessary, since String and Int are subtypes
        // of Any and AnyHashable
        result["name"] = self.name
        result["abbreviation"] = self.abbreviation
        result["population"] = self.population
        return result
    }
}
let california = State(name: "California",
                       abbreviation: "CA",
                       population: 39_000_000)
// ...and you can still use it with Cocoa API here
Notification(name: "foo", object: nil,
             userInfo: california.asPropertyList)

fileprivate

在原来的swift中的private其实并不是当真的个体,假如三个变量定义为private,在同叁个文书中的别的类依然是足以访问到的。这一个现象在使用extension的时候很醒目。

class User {
    private var name = "private"
}

extension User{
    var accessPrivate: String {
        return name
    }
}

如此那般拉动了七个难题:

  • 当大家标识为private时,意为真的私有依然文件内可分享呢?
  • 当大家若是谋算为确实的村办时,必需确保那个类照旧结构体在三个独自的文书里。不然可能同文件里另外的代码访谈到。

通过,在swift 3中,新添了三个
fileprivate来显式的表明,那些因素的拜访权限为文件内私有千古的private对应以后的fileprivate。未来的private则是真正的民用,离开了这些类还是结构体的功效域外面就不可能访谈

The AnyHashable Type

Any类型可以有所别的项目,然则Dictionary、Set供给Hasble,AnyHashble是swift3提议的hashable的超类,任何贰个可hash的品种都完成了Anyhashble左券,譬如String、Int

不再有CGRectMake,CGSizeMake等常用函数了

UIView(frame: CGRectMake(0, 0, 48, 48))
被改为
UIView(frame: CGRect(x: 0, y: 0, width: 48, height: 48))

// 'CGRectMake' is unavailable in Swift
// let frame = CGRect(0, 20, view.bounds.width, 130)        
// Swift 3.0 不再有CGRectMake,CGSizeMake等常用函数了        
 let frame = CGRect(x: 0, y: 20, width: view.bounds.width, height: 130)

Explicit Conversion for Unbridged Contexts

在局部限制的场馆swift无法直接桥接C和OC的规划,比如id*,今年api将会展现UnsafePointer<AnyObject>,此时急需as转变,再&

// ObjC
@interface Foo

- (void)updateString:(NSString **)string;
- (void)updateObject:(id *)obj;

@end

// Swift
func interactWith(foo: Foo) -> (String, Any) {
    var string = "string" as NSString // explicit conversion
    foo.updateString(&string) // parameter imports as UnsafeMutablePointer<NSString>
    let finishedString = string as String

    var object = "string" as AnyObject
    foo.updateObject(&object) // parameter imports as UnsafeMutablePointer<AnyObject>
    let finishedObject = object as Any

    return (finishedString, finishedObject)
}

其它,OC的斟酌是类合同,不可能用结构体、枚举或别的轻量级的通用项目遵循OC的说道

参谋文献

AnyObject Member Lookup

Any未有AnyObject的查找行为艺术,因而无法动态的向Any发送音信,但是AnyObject能够,此时亟需改动

// Swift 2
func foo(x: NSArray) {
    // Invokes -description by magic AnyObject lookup
    print(x[0].description)
}

// Swift 3
func foo(x: NSArray) {
    // Result of subscript is now Any, needs to be coerced to get method lookup
    print((x[0] as AnyObject).description)//也可以转换到你期望的指定类型as!NSOjbect
}

Swift Value Types in Objective-C

Any可以享有别的的结构体、枚举、元组或然另外的花色,OC的id在swift3等价于any,在swift2中供给手动封箱大概转入类,swift3则不要求

// Swift 2
struct CreditCard { number: UInt64, expiration: NSDate }

let PaymentMade = "PaymentMade"

// We can't attach CreditCard directly to the notification, since it
// isn't a class, and doesn't bridge.
// Wrap it in a Box class.
class Box<T> {
    let value: T
    init(value: T) { self.value = value }
}

let paymentNotification =
    NSNotification(name: PaymentMade,
                   object: Box(value: CreditCard(number: 1234_0000_0000_0000,
                                                 expiration: NSDate())))


// Swift 3
let PaymentMade = Notification.Name("PaymentMade")

// We can associate the CreditCard value directly with the Notification
let paymentNotification =
    Notification(name: PaymentMade,
                 object: CreditCard(number: 1234_0000_0000_0000,
                                    expiration: Date()))

亟待留神的是swift3中对于广泛的布局体类型将会桥接作为透明对象实际不是cocoa对象,Int、UInt、Double、Bool会桥接为NSNumber,Int8,UInt16则单纯桥接为透明对象。假诺碰着了unrecognized selector sent to _SwiftValue难题,它代表OC尝试唤醒一个办法在swift
值类型上,此时我们必要手动管理

swift Any持有任一类型包罗Optional,就算OC api供给是nonull
id,Optional在未解包的动静下也得以作为参数字传送递,会变成runtime
error而不是编写翻译错误。swift3.0.1+Xoce8.1化解了上述难点,为了制止包容难题,不要借助于透明对象因为前景的swift只怕会桥接到固定类型

Working with JSON in Swift

JSONSerialization Foundation framework

Extracting Values from JSON

JSONSerialization类方法jsonObject再次回到Any类型何况扔出极度借使data不可能分析

import Foundation

let data: Data // received from a network request, for example
let json = try? JSONSerialization.jsonObject(with: data, options: [])

json顶层对象一般为字典只怕数组,大家得以使用as?+if实行剖断转变

// Example JSON with object root:
/*
    {
        "someKey": 42.0,
        "anotherKey": {
            "someNestedKey": true
        }
    }
*/
if let dictionary = jsonWithObjectRoot as? [String: Any] {
    if let number = dictionary["someKey"] as? Double {
        // access individual value in dictionary
    }

    for (key, value) in dictionary {
        // access all key / value pairs in dictionary
    }

    if let nestedDictionary = dictionary["anotherKey"] as? [String: Any] {
        // access nested dictionary values by key
    }
}

// Example JSON with array root:
/*
    [
        "hello", 3, true
    ]
*/
if let array = jsonWithArrayRoot as? [Any] {
    if let firstObject = array.first {
        // access individual object in array
    }

    for object in array {
        // access all objects in array
    }

    for case let string as String in array {
        // access only string values in array
    }
}

Creating Model Objects from Values Extracted from JSON

假使有个茶馆的model

import Foundation

struct Restaurant {
    enum Meal: String {
        case breakfast, lunch, dinner
    }

    let name: String
    let location: (latitude: Double, longitude: Double)
    let meals: Set<Meal>
}

来自sever的JSON数据

{
    "name": "Caffè Macs",
    "coordinates": {
        "lat": 37.330576,
        "lng": -122.029739
    },
    "meals": ["breakfast", "lunch", "dinner"]
}

Writing an Optional JSON Initializer

extension Restaurant {
    init?(json: [String: Any]) {
        guard let name = json["name"] as? String,
            let coordinatesJSON = json["coordinates"] as? [String: Double],
            let latitude = coordinatesJSON["lat"],
            let longitude = coordinatesJSON["lng"],
            let mealsJSON = json["meals"] as? [String]
        else {
            return nil
        }

        var meals: Set<Meal> = []
        for string in mealsJSON {
            guard let meal = Meal(rawValue: string) else {
                return nil
            }

            meals.insert(meal)
        }

        self.name = name
        self.coordinates = (latitude, longitude)
        self.meals = meals
    }
}

Writing a JSON Initializer with Error Handling

enum SerializationError: Error {
    case missing(String)
    case invalid(String, Any)
}

extension Restaurant {
    init(json: [String: Any]) throws {
        // Extract name
        guard let name = json["name"] as? String else {
            throw SerializationError.missing("name")
        }

        // Extract and validate coordinates
        guard let coordinatesJSON = json["coordinates"] as? [String: Double],
            let latitude = coordinatesJSON["lat"],
            let longitude = coordinatesJSON["lng"]
        else {
            throw SerializationError.missing("coordinates")
        }

        let coordinates = (latitude, longitude)
        guard case (-90...90, -180...180) = coordinates else {
            throw SerializationError.invalid("coordinates", coordinates)
        }

        // Extract and validate meals
        guard let mealsJSON = json["meals"] as? [String] else {
            throw SerializationError.missing("meals")
        }

        var meals: Set<Meal> = []
        for string in mealsJSON {
            guard let meal = Meal(rawValue: string) else {
                throw SerializationError.invalid("meals", string)
            }

            meals.insert(meal)
        }

        // Initialize properties
        self.name = name
        self.coordinates = coordinates
        self.meals = meals
    }
}

Interactive Playgrounds

有关这里能够去看自己的简文playground精确运用姿势

Literals in Playgrounds

Xcode7.1初步帮助字面量,首要用以颜色、图片、文件

Strings in Swift 2

有关这里能够去看笔者的简文您真的懂swift
string吗?

Increasing Performance by Reducing Dynamic Dispatch

swift允许重写超类的情势和性质,那就须要在运营时刻接的拜谒并且实行直接调用。这么些本事叫做动态派发,那项技巧增添了语言表达的繁杂和大量的runtime消耗在直接的选拔上。下边介绍三种方法消除动态派发:final、private、WholeModule
Optimization

请看上边包车型地铁代码

class ParticleModel {
    var point = ( 0.0, 0.0 )
    var velocity = 100.0

    func updatePoint(newPoint: (Double, Double), newVelocity: Double) {
        point = newPoint
        velocity = newVelocity
    }

    func update(newP: (Double, Double), newV: Double) {
        updatePoint(newP, newVelocity: newV)
    }
}

var p = ParticleModel()
for i in stride(from: 0.0, through: 360, by: 1.0) {
    p.update((i * sin(i), i), newV:i*1000)
}

就如上面写的,编写翻译器发出动态派发调用

  1. 调用p 的 update
  2. 调用p 的 updatePoint
  3. 获得p 的 point元祖属性
  4. 获取p 的 速率

此间使用动态派发的由来在于ParticleModel的子类也许因此可总计属性重写point、velocity,也重写update、updatePonit

动态派发调用的落到实处是由此寻找method
table然后实行直接调用。着相对于直接调用的进度自然是慢的。

Use final when you know that a declaration does not need to be overridden

final关键字能够范围class、method、property不被重写。能够平安的驱动编写翻译器撤消动态派发。point、velocity、updatePoint不实行动态派发,直接待上访谈,update进行动态派发

class ParticleModel {
    final var point = ( x: 0.0, y: 0.0 )
    final var velocity = 100.0

    final func updatePoint(newPoint: (Double, Double), newVelocity: Double) {
        point = newPoint
        velocity = newVelocity
    }

    func update(newP: (Double, Double), newV: Double) {
        updatePoint(newP, newVelocity: newV)
    }
}

final修饰类的时候,注明不能够被子类化,因而指明函数、属性都以final

final class ParticleModel {
    var point = ( x: 0.0, y: 0.0 )
    var velocity = 100.0
    // ...
}

Infer final on declarations referenced in one file by applying the private keyword.

应用private关键字,限制在当前文件内,借使当前文件内并未有对该class的重写,那么编写翻译器就能猜想它不适用动态派发

class ParticleModel {
    private var point = ( x: 0.0, y: 0.0 )
    private var velocity = 100.0

    private func updatePoint(newPoint: (Double, Double), newVelocity: Double) {
        point = newPoint
        velocity = newVelocity
    }

    func update(newP: (Double, Double), newV: Double) {
        updatePoint(newP, newVelocity: newV)
    }
}

与final同样,private也可以修饰class

Use Whole Module Optimization to infer final on internal declarations.

internal私下认可的访谈调控权限申明仅可以在模块可知。swift编写翻译文件是模块独立的,不可能显著internal表明在分裂的文本是还是不是被重写了。不过倘若一切模块的优化是敞开的,全体的模块同期编写翻译、能够允许编译器将internal测度它的可知性

public class ParticleModel {
    var point = ( x: 0.0, y: 0.0 )
    var velocity = 100.0

    func updatePoint(newPoint: (Double, Double), newVelocity: Double) {
        point = newPoint
        velocity = newVelocity
    }

    public func update(newP: (Double, Double), newV: Double) {
        updatePoint(newP, newVelocity: newV)
    }
}

var p = ParticleModel()
for i in stride(from: 0.0, through: times, by: 1.0) {
    p.update((i * sin(i), i), newV:i*1000)
}

Nullability and Objective-C

其实对应的正是可选值

  • !表示非空
  • ?可空

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图