总结一下多年来所学习到的 Swift 编码技巧
1.从 Data 中获取 bytes
///OutStream 中有一个
open func write(_ buffer: UnsafePointer<UInt8>, maxLength len: Int) -> Int 方法
复制代码
如何将数据以流的形式存储呢
let data = Data
///事实上 data.bytes 其实就是 unsigned char *的数组 在 Swift 中可以用[UInt8]数组来表示
///或者使用(data as NSData).bytes 并不优雅 毕竟要尽量脱离OC的框架
///data是结构体 使用[UInt8]构造方法得到data的byte数组
let bytes = [UInt8](data)
///使用UnsafePointer<UInt8>构造方法生成指针
outputStream?.write(UnsafePointer<UInt8>(bytes), maxLength: bytes.count)
复制代码
2.遍历元组
按道理元组是没必要遍历的,但是在 swift 中还是有一些应用场景的,比如获取设备型号
///在结构体utsname中 设备型号machine的定义如下(在OC中是一个char *指针)
public var machine: (Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8) /* [XSI] Hardware type */
复制代码
256个元素的元组 用 0,1,2,3 这样取要到什么时候,最然可能10位以前就能碰到\0
提前退出了 可以使用反射来得到一个元素的数组
var systemInfo = utsname()
uname(&systemInfo)
let mirror = Mirror(reflecting: systemInfo.machine)
let type = mirror.children.map {String(UnicodeScalar(UInt8( $0.value as! Int8)))}.joined()
print(type)/// iPhone8,1
复制代码
3.Swift 中 KVO 的使用
let view = UIView()
var observation = view.observe(\UIView.frame, options: [.new]) { (_, change) in
///frame的类型时CGRect 不像原来从字典取值还需要转换
let frame = change.newValue
}
///invalidate() will be called automatically when an NSKeyValueObservation is deinited
/// 监听对象会在销毁的时候自动调用invalidate()方法的 所以要提前强引用监听对象 然后跟随引用者一起销毁就好了
observation.invalidate()
复制代码
4.闭包中使用不会引起循环引用的 self
事实上这是一个 bug,但是开发者很喜欢 不需要再定义 strongSelf 这样的起个新名字的变量了 当然 这样闭包中也不会在拿到真正的 self
了
var enclosure = {[weak self] in
guard let `self` = self else {return}
self.xxx
}
复制代码
5.Swift 自定义 log
func ASLog(_ value: Any... , fileName : String = #file,function : String = #function, line : Int32 = #line ){
#if DEBUG
print("文件名称:\((fileName as NSString).lastPathComponent) Function: \(function) Line:\(line)")
print("调试信息:\(value)")
print("============================================")
#endif
}
ASLog("哈哈")
文件名称:coding.playground Function: __lldb_expr_1 Line:31
调试信息:["哈哈"]
============================================
复制代码
6. 抛异常,消 error (眼不见心不烦)
有返回值得方法 暂时可能不会写逻辑 提前 return 一个值就好了 也可以直接 fatalError() 这样你要是忘写代码了 还能直接给你崩溃
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
fatalError()
///fatalError("implement later")
}
复制代码
7.方法中泛型的使用
泛型的好处不多说了
方法中标记了某个类型,返回值也是跟这个类型相关
这个泛型的类型在合适的时候确定即可
下面的例子则是由等号左边的值得类型确定的
方法举例:
定义一个解析工具类,传入一个 json 返回一个模型的数组 (HandyJSON 本身就可以用[T].self.self.deserialize(from: json)解析)
protocol HandyJSON {}
struct Book: HandyJSON {
var id = 0
var name = ""
}
struct Student: HandyJSON {
var id = 0
var name = ""
}
class Parse {
class func returnModels<T: HandyJSON>(_ json: String) -> [T] {
return []
}
}
var res1: [Book] = Parse.returnModels("")
var res2: [Student] = Parse.returnModels("")
var res3: [Book]
res3 = Parse.returnModels("")
复制代码
像 Array 的 map 方法也是一个带泛型函数
@inlinable public func map<T>(_ transform: (Element) throws -> T) rethrows -> [T]
复制代码
泛型的类型可以通过结果值来确定,也可以在闭包中返回值确定
var names1: [String] = res1.map { $0.name }
var names2 = res2.map { (s) -> String in
return s.name
}
复制代码
一句话:只需要在 T 出现的地方确定类型就可以了
8.使用 NOT 代替 ! 做非的判断(然并卵)
有的语言是用if NOT condition : expression
来做非的判断
当然我会觉得!更简单一些
那么如何在 Swift 中实现这种非的判断呢,请看下面的代码,骚操作,无卵用
let NOT = (!)
let condition = true
if NOT(condition) {
expression
}
复制代码