那些年,学swift踩过的坑

最近在学Swift,本以为多是语法与oc不同,而且都是使用相同的cocoa框架,相同的API,但是或多或少还是有些坑在里,为了避免以后再踩,在这里记下了,以后发现新的坑,也会慢慢在这里加上

[TOC]

1.main文件去哪儿了?

OC中main.m中的代码, 通过@UIApplicationMain标记自动生成

可以注掉AppDelegate里的@UIApplicationMain,自己实现Main,不过一般没人这样做

实现下面代码就是OC中的main文件的函数

UIApplicationMain(Process.argc, Process.unsafeArgv,nil, NSStringFromClass(AppDelegate))

2.如何通过字符串创建类对象?

在swift中打印对象时,会发现在类型前面总会有命名空间

.+类名

在swift中用字符串生成类对象就需要拼接成这样的格式,才能成功生成类

注意,命名空间不要加特殊符号,不然依然无法获取控制器类

//获取命名空间,在info.plist文件里就是Executable fileletnameSpace = NSBundle.mainBundle().infoDictionary!["CFBundleExecutable"]as!String//拼接成固定格式letcontroller:AnyClass = NSClassFromString(nameSpace +"."+ controllerName)!//创建对象letviewController = (controlleras! UIViewController.Type).init()

3.Swift中的Any,AnyObject,AnyClass分别代表是什么?

AnyObject: 相当于OC中的id, 表示所有class类型的数据, 所有继承与NSObject的类都隐式实现了protocol AnyObject协议, 所以他可以表示所有的class类型

Any:所有基本数据类型和enum/ struct都可以用Any来表示

注意: 有的时候你会发现将基本数据类型或者enum/ struct通过AnyObject来保存也不会报错, 这是因为Swift中很多数据类型可以和OC中的数据类型进行自动转换, 系统内部已经将他们转换为了OC的对象类型

AnyClass: 用来表示任意类的类类型(元类型)

typealiasAnyClass=AnyObject.Type.Type用于获取类的元类型, 例如Person.Type就代表着获取Person的元类型  .self如果通过类名调用, 那么可以获取该类的类型, 说白了就是获取自己

4.在Swife中如何抓取异常?

在Swift中抓取异常需要do,catch,try这三个关键字

这里举个json序列化的例子

do{letpath =/..路径../letdata =/..转data..///编译器会要求你实行异常检测,于是在序列化前面添加try字段//外部包裹do,catch,显而易见出错自然会走catchletdicArr =tryNSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers)        }catch{// 如果抛出异常就会来到catch}

5.在swift中如何定义全局打印方法

由于swift没有宏,我们不能像oc那样去定义

直接在AppDelegate中写,反正哪里都可以用

用泛型传参

如何判断调试与发布状态呢?

在Build settings里找到Swift Compiler-custom Flags

在other swift flags 的Debug里添加两个字段

"-D"

"DEBUG"

代码中直接判断就行

funcHJSLog(message: T){    #ifDEBUGprint("\(message)")    #endif}

6.在swift中,单例怎么写?

在swift中,单例有两种写法

一种是按照OC的思维去写

static var onceToken: dispatch_once_t =0staticvarinstance: NetworkTools?classfunc shareNetworkTools() -> NetworkTools    {        dispatch_once(&onceToken) { () ->Voidinprint("我被调用了")instance= NetworkTools()        }returninstance!    }

另一种就是swift的纯正写法

在swift中,let本身就只会创建一次,可以运用这个特性

let是线程安全的

staticletinstance:NetworkTools=NetworkTools()classfuncshareNetworkTools() ->NetworkTools{returninstance    }

7.在swift中如何私有化点击事件方法

一般我们不公开方法会在前面添加private

但是例如按钮点击方法,光是添加private是不够的

因为swift的方法调用是在编译时就决定了

而点击事件方法由于是来自于runloop中

编译器不会它一起编译进来,只有在运行时呼叫,这属于OC的调用方式

所以我们还需要再在方法前面加上@objc

//按钮点击handle@objcprivatefunccomposeClick(){    }`

8.在swift中如何懒加载

在swift中对懒加载有专门的关键字

///懒加载一个imageViewprivate lazy var icon:UIImageView= {        let imageV =UIImageView(image:UIImage(named:"visitordiscover_feed_image_smallicon"))returnimageV    }()

9.在swift中的协议(protocol)

在swift中定义协议也很简单

只需要在类前定义就行

@objcprotocolVisitorViewDelegate:NSObjectProtocol{//点击注册按钮optionalfuncvisitorViewDidRegisterBtnClick(visitView: VisitorView)//点击登录按钮optionalfuncvisitorViewDidLoginBtnClick(visitView:VisitorView)}

代理属性需要设定为weak,防止循环引用

weakvardelegate:VisitorViewDelegate?

在调用代理方法时,代理作为可选属性,已经帮我们预防代理不存在的可能

我们还需要借助可选属性来预防方法未实现

当然在确定实现的前提下可以解包

///注册handle@objcprivatefuncregisterClick(){delegate?.visitorViewDidRegisterBtnClick!(self)  }///登录handle@objcprivatefuncloginClick(){ delegate?.visitorViewDidLoginBtnClick?(self)  }

10.在swift中如何写分类

我刚从oc转过来就遇到了如何在swift中写分类的问题

swift中写分类很简单

extension就是swift中的分类

例如给UIBarbuttonItem添加分类

新建一个UIBarButtonItem+Extension.swift文件

importUIKitextensionUIBarButtonItem{    convenience init(target:AnyObject?,action:Selector,image:String) {        let btn =UIButton(type:UIButtonType.Custom)        btn.setImage(UIImage(named: image), forState:UIControlState.Normal)        btn.setImage(UIImage(named: image +"_highlighted"), forState:UIControlState.Highlighted)        btn.addTarget(target, action: action, forControlEvents:UIControlEvents.TouchUpInside)self.init(customView:btn)    }}

11.为何经常被强制实现init(coder: NSCoder)

因为Objective-C 和 Swift 中都没有直接的这样的抽象函数语法支持

然而有些时候我们却有不想让别人调用某个方法,但又不得不将其暴露出来的时候。

一般满足这种需求的就是抽象类型或者抽象函数

在面对这种情况时,为了确保子类实现这些方法,而父类中的方法不被错误地调用,我们就可以利用 fatalError 来在父类中强制抛出错误,以保证使用这些代码的开发者留意到他们必须在自己的子类中实现相关方法:

classMyClass{funcmethodMustBeImplementedInSubclass(){        fatalError("这个方法必须在子类中被重写")    }}classYourClass:MyClass{overridefuncmethodMustBeImplementedInSubclass(){print("YourClass 实现了该方法")    }}classTheirClass:MyClass{funcsomeOtherMethod(){    }}YourClass().methodMustBeImplementedInSubclass()// YourClass 实现了该方法TheirClass().methodMustBeImplementedInSubclass()// 这个方法必须在子类中被重写

不仅仅是对于类似抽象函数的使用中可以选择 fatalError,对于其他一切我们不希望别人随意调用,但是又不得不去实现的方法,我们都应该使用 fatalError 来避免任何可能的误会。比如父类标明了某个 init 方法是 required 的,但是你的子类永远不会使用这个方法来初始化时,就可以采用类似的方式, 被广泛使用 (以及被广泛讨厌的) init(coder: NSCoder) 就是一个例子。在子类中,我们往往会写

requiredinit(coder:NSCoder) {fatalError("NSCoding not supported")}

12.在swift中使用guard与fatalError配合抛出异常

在严谨的开发中会经常用到断言

前面一条介绍了fatalError来抛出错误

这条就来介绍一下guard与fatalError的配合使用达到断言的效果

guardletsafeValue = criticalValueelse{  fatalError("criticalValue cannot be nil here")}someNecessaryOperation(safeValue)

本来我认为if也可以达到这样的效果

ifletsafeValue = criticalValue {  someNecessaryOperation(safeValue)}else{  fatalError("criticalValue cannot be nil here")}

或者

ifcriticalValue ==nil{  fatalError("criticalValue cannot be nil here")}someNecessaryOperation(criticalValue!)

但是看到有些博客这么说:

这个flatten code以其他方式进入一个if let 代码块,并且在靠近相关的环境中过早地退出了,而不是进入else代码块。甚 至当你没有捕获一个值(guard let),这个模式在编译期间也会强制过早退出。在第二个if的例子里,尽管代码flattend得像guard一样,但是一个毁灭性的错误或者其他返回 一些无法退出的进程(或者基于确切实例的非法态)将会导致crash。一个过早的退出发生时,guard声明将会及时发现错误,并将其从else block中移除。(这博主翻译得真烂)

所以,还是用guard比较好

13.在swift中,互斥锁变成什么样了?

在swift中,互斥锁如何写

oc中的互斥锁:

@synchronized(self) {//需要执行的代码块}

swift中的互斥锁

objc_sync_enter(self)//需要执行的代码块objc_sync_exit(self)

至于其他多线程的API和以前的一样,只是少了perform这一类的API,苹果已经去掉了

14.在swift中,引用self时,如何避免循环引用

在oc中,我们需要在代码块用到self时,可以直接把self付给其他变量,然后在块中使用完毕后制空,或者像下面弱引用self来避免循环引用:

__weaktypeof(self) weakSelf =self;

那么在swift中我们怎么办到这点呢?

很简单,看下面代码

//这里用gcd举例不好,毕竟系统的块不会造成循环引用,这里就勉强的学一下怎么改吧dispatch_async(dispatch_get_global_queue(0,0)) {[unownedself] () -> Voidinself.view//添加自己的代码}

只需要在闭包里加入[unowned self]即可

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,014评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,796评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,484评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,830评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,946评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,114评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,182评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,927评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,369评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,678评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,832评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,533评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,166评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,885评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,128评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,659评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,738评论 2 351

推荐阅读更多精彩内容