从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}//加了class的protocol才能被使用在类的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
- 从Object-C -> Swift3.0
- 5 数组 Swift/Object-C ——《Swift3.0从入门到出家》
- swift3.0 从c语言字符串转换到swift 字符串
- Swift3.0 去掉C风格
- 4 字符串 Swift/Objective -C ——《Swift3.0从入门到出家》
- Swift3.0从入门到放弃(一)
- Swift3.0从入门到放弃(二)
- Swift3.0从入门到放弃(三)
- Swift3.0语言教程获取C字符串
- 从C到Object-C基础
- 【Object C】从Java 一步步走向Object C
- object-c之从"Hello World"开始(object-c)
- Swift3.0
- swift3.0
- Swift3.0
- Swift3.0从入门到放弃(四)-基础最终篇
- 7 函数——《Swift3.0从入门到出家
- protobuf3 从object-c角度说明数据类型
- Log4j配置详解
- Eclipse Plug-ins for Gradle: buildship 插件安装说明
- Linux常用命令
- caffe示例实现之4在MNIST手写数字数据集上训练与测试LeNet
- qtp的运行原理
- 从Object-C -> Swift3.0
- spring 在启动服务器的时候报错 Could not open ServletContext resource [/WEB-INF/dispather-servlet.xml]
- 树状数组
- 算法3_八大排序算法
- MySQL之Replication
- Docker容器
- 详解JPA 2.0动态查询机制:Criteria API
- Wireshark入门与进阶系列二之IP地图
- struts2.1的一个小bug