从Object-C -> Swift3.0

来源:互联网 发布:下载文件进度条js特效 编辑:程序博客网 时间:2024/06/03 21:26

目录

      • 目录
      • 前言
      • 从Object-C向Swift过渡
        • protocol
        • block
        • GCD
        • Property属性
        • 函数
        • extensioncategory
        • 可选类型与
        • 类型判断与转换
        • id类型与AnyAnyObjectnil
        • typedef与typealias
        • 宏定义
        • 混合编程
        • API设计与函数命名对比
      • 参考资料
      • 结语

前言

当我们开始接触一门新语言时,我们难免避免不了类型和基本语法规则。我们会急切的想知道如何用新的语法规则写我们原先所熟知的语句。本文旨在对于Object-C和Swift做一些基本的对比。通过阅读本文,您能快速的了解Swift3.0和Object-C的一些差别。

  • 基本类型
    同所有的面向对象语言一样,Swift里也只有两种类型:

    1.值类型
    2.引用类型

    值类型包括struct,enum;
    引用类型主要是class,嗯还有闭包也是引用类型哦。

  • 代码不再需要分号结尾

    Swift代码单行结束,不需要强制加分号,但也可以选择加

  • 类型推断

    Swift可以自动根据上下文为一个变量推断出其类型;

  • 强类型语言

    尽管Swift可以支持类型推断,可以用var来声明变量。但Swift是强类型语言。这样意味着,只要涉及不同类型之间的运算,都需要进行强制类型转换

  • 变量、常量定义

    let constant name : type = expression
    var variable name : type = expression

在开始所有介绍前,我们先看简单的几行代码.大家采一些预期结果是什么?

    var num=3.0    var integer=6    print(num+integer) //输出结果是?

结果:编译不过。因为Swift是一个强类型语言


从Object-C向Swift过渡

接下来将会从Protocol,block,GCD等大家在Object-C里熟知的内容开始,一步步过渡到Swift3.0。

**1.protocol
2.block
3.GCD
4.property
5.函数
6.extension,category
7.可选类型?与??
8.类型判断与转换
9.id类型与Any,AnyObject,nil
10.typedef与typealias
11.宏定义
12.混合编程
13.API设计与函数命名对比**

1.protocol

Swift也和OC一样有protocol,但不同的是Swift的protocol可以被class,struct,enum实现,甚至还能进行extension扩展。
参考:Protocols

  • Protocol以及optional protocol定义
//Object-C@protocol RefreshHeaderDelegate <NSObject>@optional   - (void)willBeginRefresh:(PullRefreshHeader*)header;   - (void)didRefresh:(PullRefreshHeader*)header;@required   - (void)didFinishRefresh:(PullRefreshHeader*)header;@end//Swift@objc protocol RefreshHeaderDelegate {    @objc optional func willBeginRefresh(header:PullRefreshHeader) -> Void    @objc optional func didRefresh(header:PullRefreshHeader) -> Void}//加了classprotocol才能被使用在类的delegate模式中,因为protocol不加class标记则还可以被enum,struct实现protocol RefreshHeaderDelegate :class{    func willBeginRefresh(header:PullRefreshHeader) -> Void    func didRefresh(header:PullRefreshHeader) -> Void}
  • 定义了optional方法后,如何判断delegate是否实现了该方法?
//Object-Cif([self.delegate respondsToSelector:@selector(willBeginRefresh:)]){  //执行delegate的方法  [self.delegate willBeginRefresh:self];}//Swift中我们可以更优雅的实现,optional是很方便的self.delegate?.willBeginRefresh?(header: self)

2.block

Swift中任何两个{}之间的代码都算是闭包,因此函数也是一种特殊的闭包。
参考:closure-expressions-in-swift

  • 闭包定义
//Swift闭包定义{ (obj:AnyObject) ->Void in  //闭包内容开始  print(obj)  pring($0)  //可以用$<index>来指向闭包的形参,下标从0开始}
  • 如何避免闭包中的循环引用?
//Object-C__weak __typeof(self) __weak_self = self[button onClicked:^(MttTopBannerButton * button) {    MttBottomBanner *banner=[[MttBottomBanner alloc] init];    [__weak_self.view addSubview:banner];    [banner show];    button.hidden=YES; }]; //Swift更优雅button.onClicked({    [weak self]    (button:MttTopBannerButton) ->Void in    var banner = MttBottomBanner()    self?.view.addSubview(banner)    banner.show()    button.hidden=true})
  • weakself,strongself
//SwiftDispatchQueue.main.sync(execute: {    [weak self]    (_:AnyObject?) ->Void in    self?.draw()    self?.color=UIColor.white()    DispatchQueue.main.sync(execute: {        if let strongSelf=self {            strongSelf.lock.lock()            strongSelf.layer.contents=strongSelf.display?.cgImage            strongSelf.lock.unlock()        }    })})//请思考为何此处我是NSLock来加锁?//因为Swift里没有@synchonized关键字的替代品了啊,需要的话,得自行调用GCD接口实现了.//Object-C__weak __typeof(self) __weak_self = selfdispatch_async(dispatch_get_main_queue(),^{    [self draw];    self.color=[UIColor whiteColor];    __typeof(__weak_self) strongSelf = __weak_self    dispatch_async(dispatch_get_main_queue(),^{        [strongSelf.lock lock];        strongSelf.layer.contents=strongSelf.display.CGImage;        [strongSelf.lock unlock];    })});

3.GCD

Grand Dispatch Queue在Object-C中是一组C语言接口,虽然在swif1,swift2中仍保留了这种用法习惯,但它毕竟不太符合一门强类型与面向对象的语言的要求(就像这些人取消了++,–运算符一样,无时无刻不再想着摒弃老式的C语言编程思维),于是Swift3中GCD终于也面向对象了.

  • dispatch_async
//SwiftDispatchQueue.main.async(execute:{blk(nil)})//Object-Cdispatch_async(dispatch_get_main_queue(),^(id obj){});
  • dispatch_after
//Object-C- (void)performBlockOnMainThread:(void (^)())block afterDelay:(CGFloat)delay{    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{        block();    });}//block参数可为空,因为是optionalfunc performOnMainThread(_ block:AsyncLoaderTask? ,delay:Double) -> Void {    if let blk=block {        let time=DispatchTime.now()+delay        //DispatchWorkItem相当于之前的dispatch_queue_t所以直接用        DispatchQueue.main.after(when:time,execute:{blk(nil)})    }}

4.Property属性

在Swift中类里定义了的变量或常量即是属性

属性分为2种:

  • 存储型属性
    跟Object-C的property基本差不多
  • 计算型属性
    比较特别,并不是用于真正的存储一个值或变量,而是提供了getter和setter方法来间接的获取其他属性或变量的值。其本身的存在价值是依赖于其它属性或变量的存在

1.属性定义
2.属性观察器
3.getter,setter
4.delegate模式
5.普通属性
6.lazy标记
7.optional属性
8.completion block模式
9.初始化

typealias AsyncLoaderTask = (_:AnyObject?) ->Voidclass PullHeaderTable: UITableView {    // MARK: Public Properties    //////////////    //1.标准属性定义方式    //常量属性,以及属性定义的两种方式,可以隐身让Swift自行推断类型,也可以明确指定类型    let source=PullHeaderTableSource()    let src : PullHeaderTableSource = PullHeaderTableSource()    var s : PullHeaderTableSource = PullHeaderTableSource()    //////////////    //2.property观察器    var data : [AnyObject]?{        didSet{            source.data=data            print(oldValue)        }        willSet{            print(newValue)        }    }    //////////////    //3.getter,setter,通过getter返回的,叫做计算型属性    var src : PullHeaderTableSource  {        get{            return PullHeaderTableSource()        }        set{            print(newValue)        }    }    //////////////    //4.delegate模式    weak var tableDelegate : PulllHeaderTableDelegate?    //////////////    //5.普通属性,必须在init方法里最先被初始化    var header : UIView    //////////////    //6.lazy标记,该属性只会在被调用时自动调用初始化赋值,而不是在init之前就初始化了,thread unsafe    lazy var footer = UIView()    //7.optional属性    var listener : AnyObject?    //8.optional block属性(和OC的completion block模式)    var completion : AsyncLoaderTask?    //////////////    //9.对于非optional的属性,在init时必须要初始化,否则会出错    //init初始化与OC的不一样,是先把当前实例的非optional属性初始化完毕,然后再调用父类的init    //原因在于Swift定义了的任何类型property编译器都不会给默认值,因此非optional property必须在init中有优先初始化    init(frame:CGRect) {        header=UIView()        super.init(frame:frame, style:UITableViewStyle.plain)        self.onCreate()    }    required init?(coder aDecoder: NSCoder) {        header=UIView()        super.init(coder: aDecoder)        self.onCreate()    }    override init(frame:CGRect,style:UITableViewStyle){        header=UIView()        super.init(frame: frame, style: style)        self.onCreate()    }    deinit {        self.dataSource=nil        self.delegate=nil    }    // MARK: Private Functions    private func onCreate() -> Void {        self.scrollsToTop=false        self.separatorColor=UIColor.clear()        self.separatorStyle=UITableViewCellSeparatorStyle.none        self.contentOffset=CGPoint.zero        self.delegate=source        self.dataSource=source    }}

5.函数

使用 func 来声明一个函数,使用名字和参数来调用函数。使用 -> 来指定函数返回值的类型。
参考:Functions

1.如何让函数返回多个返回值?
2.如何传入1个或N个参数
3.重构->函数内嵌套函数
4.函数类型与函数返回值,函数参数

Swift的函数相比较于OC发生了很多很好的改进,我们可以更自由的使用定义函数了.
同时还加入了函数类型。
参考:函数类型

class App: NSObject {    func test() {        print(calculate(scores: [0,1,2,3,4,5]))        print(sumOf(numbers: 0,1,2,3,4,5))        runAnotherFunction(longlongFunction)    }    // MARK:Function Usage    //1.使用元组返回多个返回值    //下述函数从数组中返回最小,最大,求和.返回值是一个元组.    //其中调用了Swift里的min,max函数,全局泛型函数,用于比较大小返回结果.    //min,max函数类似于OC宏定义的MIN(),MAX()    func calculate(scores: [Int]) -> (min: Int, max: Int, sum: Int) {        var vmin=scores[0]        var vmax=vmin        var sum : Int = 0        for val in scores {            vmin=min(vmin, val)            vmax=max(vmax, val)            sum+=val        }        return (vmin,vmax,sum)    }    //2.传入可变个数的参数    func sumOf(numbers: Int...) -> Int {        var sum=0        for val in numbers {            sum+=val        }        return sum    }    //3.嵌套函数,用于部分代码的重构,其实也可以里面定义一个block一样的。不过比OC多了个选择    func longlongFunction() {        var x=10        //猜猜看 _ 这里下划线的作用?看看如何调用的你就会明白了        func increament(_ val:Int) -> Int {            return val+1        }        print(increament(x))        func add() {            //x++            //Swift 3.0不支持++,--了哦            x=x+1        }        add()    }    //4.函数作为参数,当然函数也可以作为返回值的.函数类型    func runAnotherFunction(_ fun: () -> ()) {        fun()    }}

6.extension,category

Swift中没有category的概念,因为Swift中的extension基本涵盖了所有原先Object-C中需要的一切

1.添加计算型属性和计算型静态属性
2.定义实例方法和类型方法
3.提供新的构造器
4.定义下标[]
5.定义和使用新的嵌套类型
6.支持协议

参考:下标运算符

extension String {    func toHex() -> String {        return ""    }}protocol AppProtocol: class {    func app() -> Void}class App: NSObject {    var data : Array = Array<Int>()    static var instance = App()    private override init() {        for i in 0...8 {            self.data.append(i)        }    }}extension App: AppProtocol {    //////////////    //1.添加计算性属性,存储型的不可以啊    var hashCode : Int {        return Int(Date.timeIntervalSinceReferenceDate)+8    }    //非法,存储性属性不能再extension里存在    //var newProperty : Int = 0    //////////////    //2.添加新的构造函数    convenience init(_ id:Int, time:Int) {        self.init()    }    //////////////    //3.函数或实现协议    func app() -> Void {        print("app")    }    //////////////    //4.为对象实现下标运算符    subscript(index: Int) -> Int {        get{            return self.data[index]        }        set{            self.data[index]=newValue        }    }    //////////////    //5.嵌套类型,class,enum,也就是相当于定义内部类    class UI : NSObject {    }}func testApp() -> Void {    let app = App.instance    app[0]=1    print(app[1])}

7.可选类型?与??

可空链式调用(Optional Chaining)
这个名词太专业了,我们就简单的来谈谈吧

定义属性或变量时,如果要允许一个属性为空即nil,像Object-C一样的话。那么我们需要制定其位optional类型
只需定义结束末尾在加一个?符号即可,如下

var obj : AnyObject?//定义了一个相当于Object-C的 id obj=nil;东西

对于optional类型的变量或方法(如optional protocol method)我们在调用时需要把optional类型的值/对象取出来,这一步叫做unwrap;反之定义时就叫wrap;
通过?来unwrap或者直接利用!来强制unwrap(强制的前提是你能确保变量是有有效值的),如下

var str : String?str="value"//前面已经为str赋值过了,所以我们是已知强制unwrap是不会有异常的if str!.characters.count>0 {}//如果签名没有为str赋值,或者不确定有值与否,需要尝试unwrapif str?.characters.count>0 {}var count : Intcount=str?.characters.count ?? 0print(count)

大家是否在好奇上述的??符号到底是什么意思呢?很简单,如果你理解选择表达式,那么可以把它看做对于optional类型的选择表达式吧
等价于如下代码

if str != nil {    count=str!.characters.count}else{    count=0}

8.类型判断与转换

1.在Object-C中我们经常会对一个id类型或者不确定具体类型的实例对象做类型判断,如isKindOfClass;在Swift中我们可以更简单来实现

参考:Type Casting

is类型检查运算符

//Object-C判断类型UIView *v=XXX;if([v isKindOfClass:[UIWindow class]){}//Swiftvar v=XXXif v is UIWindow {}

2.在Object-C中我们要做类型转换可以直接使用C语言的方式来强制类型赋值,但在Swift中需要用as运算符实现

as 用于向上转型(upcasts)
as? 和as! 用于向下转型(Downcasting)

备注:
1.向上转型:由派生类转为父类对象
2.向下转型:有父类对象转为具体子类对象

当不确定类型转换是否成功时,用类型转换的条件形式( as? )
as?如果失败会返回nil
当确定一定是时,用强制形式式( as! )

//Object-Cfor(UIViewController *ct in controllers){    if([ct isKindOfClass:[MttBaseViewController class]])    {        NSLog(@"MttBaseViewController");    }    else if([ct isKindOfClass:[MttRootViewController class]])    {        NSLog(@"MttRootViewController");    }}//Swiftfor ct in controllers {    if let mtt = ct as? MttBaseViewController {            print("MttBaseViewController")    } else if let nav = ct as? MttRootViewController {            print("MttRootViewController")    }}

9.id类型与Any,AnyObject,nil

Any 和 AnyObject 是 Swift 中两个妥协的产物;

AnyObject 可以代表任何 class 类型的实例
Any 可以表示任意类型,甚至包括方法 (func) 类型

AnyObject用于在Swift中替换Object-C的id类型;
Swift中编译器不会对 AnyObject 实例的方法调用做出检查,甚至对于 AnyObject 的所有方法调用都会返回 Optional 的结果。因此使用AnyObject实例之前我们务必需要检测对象是否存在和类型有效性。
参考:ANY 和 ANYOBJECT

nil:
Swift中的nil与Object-C的nil是不一样的。Object-C中,nil是一个指针指向一个不存在的object。在Swift中,nil不是指针,而是对于特定类型的缺省值。任何optional类型都可以设置为nil,而不仅仅是对象类型;
optional类型变量的值默认就是nil;

10.typedef与typealias

typealias相当于Object-C中的typedef,用来为已经存在的类型重新定义名字。通过命名,可以使代码变得更加清晰。
参考:swift-typealias,typelias

//重命名闭包,和Object-C一样typealias AsyncLoaderTask = (_:AnyObject?) ->Voidfunc submit(_ block:AsyncLoaderTask?,completion:AsyncLoaderTask?) -> Void {    if let blk=block {        self.queue.async(execute:{            blk(nil)            if let cmp=completion {                cmp(nil)            }        })    }}//protocol组合protocol changeName{    func changeNameTo(name:String)}protocol changeSex{    func changeSexTo(sex:String)}typealias changeProtocol = protocol<changeName,changeSex>struct Person:changeProtocol{  func changeNameTo(name:String){  }  func changeSexTo(sex:SEX){  }}//swift中很多类型别名即是typealias定义的public typealias AnyClass = AnyObject.Typepublic typealias NSInteger = Int

11.宏定义

很抱歉,Swift中终于不支持宏定义了。
Object-C中的宏暴露到Swift中的话,只有简单展开宏会被直接变为同名常量。
参考:converting-complex-objective-c-macros-swift-functions,Objective的宏到swift

//Object-C#defien MTT_DEBUG 1//Swiftlet MTT_DEBUG = 1 //以上二者等价

其余复杂的宏定义以及宏嵌套都无法被翻译到Swift里,也无法在Swift中调用或使用。
所以要使用宏,只能在Object-C中使用.

12.混合编程

处于某些目的,我们还是有必要在Swift代码中使用Object-C,或者在Object-C代码中装一下样子,搞点Swift。那这时就涉及到混合编程了。
参考:混和编程

1.OC中使用Swift
在工程的 Build Settings 中把 defines module 设为 YES.即可.(如需必要,再把把 product module name 设置为项目工程的名字。理论上不需要了,XCode 8.0已经默认是这样了)
最后一步,在你的OC文件中导入 ProjectName-Swift.h.即(productModuleName-Swift.h)

2.Swift中使用OC
Swift代码引用OC,需依靠 Objective-C bridging header 将相关文件暴露给Swift。
创建 Objective-C bridging header 有两种方法

a.当你在Swift项目中尝试创建OC文件时,系统会自动帮你创建 Objective-C bridging header
b.自己创建 Objective-C bridging header
File > New > File > (iOS or OS X) > Source > Header File
切记,名字 一定要 是 项目工程名-Bridging-Header.
然后还有一步,在项目的 Build Settings 选项里,要确保Swift Compiler 选项里有这个 Bridging Header 文件的设置,路径必须指向文件本身,而不是目录!

13.API设计与函数命名对比

篇幅原因,这里就不copy&&paste了,大家可以自行看原文或者译文。这是一篇很好的API设计指导,终于可以抛弃Object-C的冗长命名了。
参考:Swift API设计 , 译文


参考资料

  • Swift学习资料
    http://www.swiftguide.cn/
    https://github.com/ipader/SwiftGuide

  • 参考文献
    https://swift.org/about/
    https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html
    http://www.devtalking.com/articles/closure-expressions-in-swift/
    https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Functions.html#//apple_ref/doc/uid/TP40014097-CH10-XID_270
    http://www.jianshu.com/p/989999a5104b
    http://blog.csdn.net/xbenlang/article/details/31787973
    http://swifter.tips/any-anyobject/
    http://www.jianshu.com/p/082202b9dc17
    http://swifter.tips/typealias/
    https://www.andrewcbancroft.com/2015/01/29/converting-complex-objective-c-macros-swift-functions/
    http://www.cnblogs.com/xilifeng/p/5243986.html
    http://kittenyang.com/swiftandoc/
    http://www.jianshu.com/p/fce426e4f1c4

结语

如果你在一门语言上,可以看到很多让你曾痴狂,压抑,热爱,也失望的特性时。那就一定是Swift了。
本文比较了Swift3.0和Object-C在开发中主要的一些差别,限于篇幅(已经很长了)与作者本人认知能力,并未对Swift中更多特性做介绍或深究。如有疏漏或错误还望指正。
Swift就像一个四不像,因为var而像javascript,因为@objc而又保留了Object-C特性,因为内部类而多了点Java的影子,因为deinit而带了些c++的气味。但无论如何,Swift必定是将来!
参考:About Swift

0 0
原创粉丝点击