Swift实战技巧
swift实战技巧
从oc转战到swift,差别还是蛮大的,本文记录了我再从oc转到swift开发过程中遇到的一些问题,然后把我遇到的这些问题记录形成文章,大体上是一些swift语言下面的一些技巧,希望对有需要的人有帮助
- oc调用方法的处理
给oc调用的方法需要添加@objc
标记,一般的action-target的处理方法,通知的处理方法等需要添加@objc标记
@objc func onrefresh(){ self.refreshcallback?() }
- 处理sel选择子
使用方法型如 #selector(方法名称)
eg.
`#selector(self.onrefresh))`
更加详细的介绍可以看这篇文章:
下面是使用mjrefresh给mj_header
和mj_footer
添加回调处理函数的例子
self.mj_header.setrefreshingtarget(self, refreshingaction: #selector(self.onrefresh)) self.mj_footer.setrefreshingtarget(self, refreshingaction: #selector(self.onloadmore))
-
try
关键字的使用
可能发生异常的方法使用try?方法进行可选捕获异常
let jsonstr=try?string(contentsoffile: jsonpath!)
- 类对象参数和类对象的参数值
anyclass作为方法的形参,类名称.self(modelclass.self)作为实参
func registercellnib(nib:uinib,modelclass:anyclass){ self.register(nib, forcellreuseidentifier: string(describing:modelclass.self)) } ... self.tableview?.registercellnib(nib: r.nib.gamecell(), modelclass: gamemodel.self)
- 线程间调用
主线程使用dispatchqueue.main
,全局的子线程使用dispatchqueue.global()
,方法可以使用sync
,async
,asyncafter
等等
下面是网络请求线程间调用的例子
let _ = urlsession.shared.datatask(with: url, completionhandler: { [weak self] (data, response, error) in guard let weakself = self else { return } if error == nil { if let json = try? jsonserialization.jsonobject(with: data!, options: .mutablecontainers) { let data = json as! [any] dispatchqueue.main.async { weakself.suggestions = data[1] as! [string] if weakself.suggestions.count > 0 { weakself.tableview.reloaddata() weakself.tableview.ishidden = false } else { weakself.tableview.ishidden = true } } } } }).resume()
- 闭包中使用weak防止循环引用的语法
urlsession.shared.datatask(with: requesturl) {[weak self] (data, response, error) in guard let weakself = self else { return } weakself.tableview.reloaddata() }
- 逃逸闭包和非逃逸闭包
逃逸闭包,在方法执行完成之后才调用的闭包称为逃逸闭包,一般在方法中做异步处理耗时的任务,任务完成之后把结果使用闭包进行回调处理使用的闭包为逃逸闭包,需要显示的使用@escaping
关键字修饰
非逃逸闭包,在方法执行完成之前调用的闭包称为逃逸闭包,比如snapkit框架使用的闭包是在方法执行完成之后就已经处理完毕了
swift3之后闭包默认都是非逃逸(,不能显示声明),并且这种类型是不能显示使用@noescape
关键字修饰的
// 模拟网络请求,completion闭包是异步延迟处理的,所以需要添加`@escaping`进行修饰 class func fetchvideos(completion: @escaping (([video]) -> void)) { dispatchqueue.global().async { let video1 = video.init(title: "what does jared kushner believe", channelname: "nerdwriter1") let video2 = video.init(title: "moore's law is ending. so, what's next", channelname: "seeker") let video3 = video.init(title: "what bill gates is afraid of", channelname: "vox") var items = [video1, video2, video3] items.shuffle() dispatchqueue.main.asyncafter(deadline: dispatchtime.init(uptimenanoseconds: 3000000000), execute: { completion(items) }) } }
- notification.name的封装处理
swift3中notification的名字是一种特殊的notification.name
类型,下面使用enum
进行封装处理,并且创建一个notificationcenter
的扩展,处理通知消息的发送
// 定义notification.name枚举 enum ytnotification: string { case scrollmenu case didselectmenu case openpage case hidebar var stringvalue: string { return "yt" + rawvalue } // 枚举成员返回对应的notification.name类型 var notificationname: nsnotification.name { return notification.name.init(stringvalue) } } extension notificationcenter { func yt_post(custom notification: ytnotification, object anobject: any?, userinfo auserinfo: [anyhashable : any]? = nil) { self.post(name: notification.notificationname, object: anobject, userinfo: auserinfo) } }
使用方法
添加通知观察者使用的是ytnotification枚举成员的notificationname
返回的notification.name
类型的值
发送消息使用的是ytnotification枚举成员
// 添加通知观察 notificationcenter.default.addobserver(self, selector: #selector(self.changetitle(notification:)), name: ytnotification.scrollmenu.notificationname, object: nil) // 发送消息 notificationcenter.default.yt_post(custom: ytnotification.scrollmenu, object: nil, userinfo: ["length": scrollindex])
lazy
惰性加载属性,只有在使用的时候才初始化变量
// 闭包的方式 let menutitles = ["history", "my videos", "notifications", "watch later"] lazy var menuitems : [menuitem] = { var tmenuitems = [menuitem]() for menutitle in menutitles { let menuitem = menuitem(iconimage: uiimage.init(named: menutitle)!, title: menutitle) tmenuitems.append(menuitem) } return tmenuitems }() // 普通方式, lazy var titles = ["a", "b"]
- 类型判断
使用is判断类型以及使用if-let和as?判断类型
// mark:- 类型检查例子 let sa = [ chemistry(physics: "固体物理", equations: "赫兹"), maths(physics: "流体动力学", formulae: "千兆赫"), chemistry(physics: "热物理学", equations: "分贝"), maths(physics: "天体物理学", formulae: "兆赫"), maths(physics: "微分方程", formulae: "余弦级数")] var chemcount = 0 var mathscount = 0 for item in sa { // 如果是一个 chemistry 类型的实例,返回 true,相反返回 false。 相当于iskindofclass if item is chemistry { chemcount += 1 } else if item is maths { mathscount += 1 } } // 使用if-let和as?判断类型 for item in sa { // 如果是一个 chemistry 类型的实例,返回 true,相反返回 false。 相当于iskindofclass if let _ = item as? chemistry { chemcount += 1 } else if let _ = item as? maths { mathscount += 1 } }
使用switch-case和as判断类型
// any可以表示任何类型,包括方法类型 var exampleany = [any]() exampleany.append(12) exampleany.append(3.14159) exampleany.append("any 实例") exampleany.append(chemistry(physics: "固体物理", equations: "兆赫")) // 使用switch-case和as判断类型 for item2 in exampleany { switch item2 { case let someint as int: print("整型值为 \(someint)") case let somedouble as double where somedouble > 0: print("pi 值为 \(somedouble)") case let somestring as string: print("\(somestring)") case let phy as chemistry: print("主题 '\(phy.physics)', \(phy.equations)") default: print("none") } }
- swift使用kvc,执行kvc操作的变量需要添加@objc标记
class feed: nsobject, handyjson { // 使用kvc添加@objc关键字 @objc var id = 0 var type = "" var payload: payload? var user: postuser? required override init() {} }
- swift中
cgrect
类型的操作
swift中简化了cgrect
类型的操作,比如有一个cgrect的类型实例为frame
,以下例举了oc中对应的在下的语法
oc | swift |
---|---|
cgrectgetmaxx(frame) | frame.maxx |
cgrectgetminy(frame) | frame.miny |
cgrectgetmidx(frame) | frame.midx |
cgrectgetwidth(frame) | frame.width |
cgrectgetheight(frame) | frame.height |
cgrectcontainspoint(frame, point) | frame.contains(point) |
- swift中指针的处理
详细的介绍可以查看这篇文章:
下面是一个使用oc库regexkitlite中的一个例子,block中返回值是指针类型的,需要转换为对应的对象类型
func composeattrstr(text: string) -> nsattributedstring { // 表情的规则 let emotionpattern = "\\[[0-9a-za-z\\u4e00-\\u9fa5]+\\]"; // @的规则 let atpattern = "@[0-9a-za-z\\u4e00-\\u9fa5-_]+"; // #话题#的规则 let topicpattern = "#[0-9a-za-z\\u4e00-\\u9fa5]+#"; // url链接的规则 let urlpattern = "\\b(([\\w-]+://?|www[.])[^\\s()<>]+(?:\\([\\w\\d]+\\)|([^[:punct:]\\s]|/)))"; let pattern = "\(emotionpattern)|\(atpattern)|\(topicpattern)|\(urlpattern)" var textparts = [textpart]() (text as! nsstring).enumeratestringsmatched(byregex: pattern) { (capturecount: int, capstring: unsafepointer<nsstring?>?, caprange: unsafepointer<nsrange>?, stop: unsafemutablepointer<objcbool>?) in let capturestring = capstring?.pointee as! string let capturerange = caprange?.pointee as! nsrange let part = textpart() part.text = capturestring part.isspecial = true part.range = capturerange textparts.append(part) } // ... }
- 只有类才能实现的protocol 有一种场景,protocol作为delegate,需要使用weak关键字修饰的时候,需要指定delegate的类型为ptotocol型,这个ptotocol需要添加class修饰符,比如下面的这个protocol,因为类类型的对象才有引用计数,才有weak的概念,没有引用计数的struct型是没有weak概念的
/// imageviewer和imagecell交互使用的协议 protocol ytimagecellprotocol : class { // cell的点击事件,处理dismiss func imagecell(_ imagecell: ytimagecell, didsingletap: bool); }
上一篇: 刘强东案149页警方档案公布
下一篇: js原型,原型链
推荐阅读
-
Android APK反编译技巧深入讲解
-
详解Spring Boot配置使用Logback进行日志记录的实战
-
详解Spring Boot实战之Filter实现使用JWT进行接口认证
-
pr2020字幕字体样式怎么设置? premiere字幕实现上宽下窄效果的技巧
-
微信朋友圈视频盗用怎么投诉? 微信举报朋友圈视频的技巧
-
Soul怎么录制声音名片? SOUI创建声音名片的技巧
-
微博如何设置单条不能评论? 单条微博设置禁止评论的技巧
-
2018大学生网络赚钱的门路和技巧,手机也可以操作的方法!
-
premiere怎么制作漂亮粒子logo动画? pr做创意片头粒子效果的技巧
-
冬季嘴唇干裂护理技巧 唇部湿敷别用热水