Swift實戰技巧json
從OC轉戰到Swift,差異仍是蠻大的,本文記錄了我再從OC轉到Swift開發過程當中遇到的一些問題,而後把我遇到的這些問題記錄造成文章,大致上是一些Swift語言下面的一些技巧,但願對有須要的人有幫助swift
給OC調用的方法須要添加@objc
標記,通常的action-target的處理方法,通知的處理方法等須要添加@objc標記api
@objc func onRefresh(){ self.refreshCallback?() }
使用方法型如 #selector(方法名稱)
eg.網絡
`#selector(self.onRefresh))`
更加詳細的介紹能夠看這篇文章: http://swifter.tips/selector/閉包
下面是使用MJRefresh給mj_header
和mj_footer
添加回調處理函數的例子app
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
等等async
下面是網絡請求線程間調用的例子ide
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()
URLSession.shared.dataTask(with: requestURL) {[weak self] (data, response, error) in guard let weakSelf = self else { return } weakSelf.tableView.reloadData() }
@escaping
關鍵字修飾@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) }) } }
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") } }
class Feed: NSObject, HandyJSON { // 使用KVC添加@objc關鍵字 @objc var id = 0 var type = "" var payload: PayLoad? var user: PostUser? required override init() {} }
CGRect
類型的操做swift中簡化了CGRect
類型的操做,好比有一個CGRect的類型實例爲frame
,如下例舉了OC中對應的在swift下的語法
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) |
詳細的介紹能夠查看這篇文章:http://swifter.tips/unsafe/
下面是一個使用OC庫RegexKitLite中的一個例子,block中返回值是指針類型的,須要轉換爲對應的swift對象類型
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) } // ... }
/// ImageViewer和ImageCell交互使用的協議 protocol YTImageCellProtocol : class { // Cell的點擊事件,處理dismiss func imageCell(_ imageCell: YTImageCell, didSingleTap: Bool); }