Swift
文章平均质量分 57
Swift
HumorousGhost
iOS开发
展开
-
Swift - 多元组(Tuple)
多元组是我们的“新朋友”,多尝试使用这个新特性,会让工作轻松不少。比如交换输入,程序员“亘古以来”可能都是这么写的func swapMe<T>(a : inout T, b : inout T) { let temp = a a = b b = temp}但是要是使用多元组的话,我们不适用额外空间就可以完成交换,一下子就实现了该操作func swapMe<T>(a : inout T, b : inout T) { (a, b) = (b,原创 2021-03-11 14:31:28 · 271 阅读 · 1 评论 -
Swift - final
final 关键字可以用在class、func 和var 前面进行修饰,表示不允许对该内容进行继承或者重写操作。这个关键字的作用和 C# 中的sealed 相同,而sealed 其实在C# 算是一个饱受争议的关键字。有一些程序员认为,类似这样的禁止继承和重写的做法是非常有益的,它可以更好的对代码进行版本控制,发挥更佳的性能,以及使代码更安全。因此他们甚至认为语言应当是默认不允许继承的,只有在显式的指出可以继承的时候才能子类化。在这里我不打算对这样的想法做出判断或者评价,虽然上面列举的优点都是事实,但是另原创 2021-03-22 10:58:12 · 497 阅读 · 0 评论 -
Swift - 条件编译
在C 语言中,可以使用#if 或者#ifdef 之类的编译条件分支来控制哪些代码需要编译,哪些代码不需要。Swift 中没有宏定义的概念,因此我们不能使用#ifdef 的方法来检查某个符号是否经过了定义。但是为了控制编译流程和内容,Swift 还是为我们提供了几种简单的机制来根据需求定制的编译内容的。首先#if 这一套编译标记还是存在的,使用的语法也和原来没有区别:#if <condition>#elseif <condition>#else#endif当然,#e原创 2021-03-23 16:52:44 · 823 阅读 · 0 评论 -
Swift - Selector
@selector 是Objective-C 时代的一个关键字,它可以将一个方法转换并赋值给一个SEL 类型,它的表现很类似一个动态的函数指针。在Objective-C 中selector 非常常用,从设定 target-action,到自举询问是否响应某个方法,再到指定接受通知时需要调用的方法等等,都是有selector 来负责的。在Objective-C 里生成一个selector 的方法一般是这样的:- (void)callMe { // ...}- (void)callMeWithP原创 2021-03-23 14:43:45 · 1478 阅读 · 0 评论 -
Swift - AnyClass、元类型和 .self
在Swift 中能够表示“任意”这个概念的除了Any 和 AnyObject 以外,还有一个AnyClass。AnyClass在Swift 中被一个typealias 所定义:public typealias AnyClass = AnyObject.Type通过AnyObject.Type 这种方式所得到的是一个元类型(Meta)。在声明时我们总是在类型的名称后面加上 .Type,比如A.Type 代表的是A 这个类型的类型。也就是说,我们可以声明一个元类型来存储A 这个类型本身,而从A 中取出其类原创 2021-03-19 11:51:00 · 629 阅读 · 0 评论 -
Swift - Optional Map
我们经常会对Array 类型使用map 方法,这个方法能对数组中的所有元素应用某个规则,然后返回一个新的数组。@inlinable public func map<T>(_ transform: (Element) throws -> T) rethrows -> [T]举一个简单的使用例子:let arr = [1, 2, 3]let doubled = arr.map { $0 * 2 }print(doubled)// 输出// [2, 4, 6]这很方便原创 2021-03-23 10:55:35 · 341 阅读 · 0 评论 -
Swift - 可选接口
Objective-C 中的protocol 里存在 @optional 关键字,被这个关键字修饰的方法非必须要被实现。我们可以通过接口定义一系列方法,然后由实现接口的类选择性的实现其中几个方法。在Cocoa API 中很多情况下接口方法都是可选的,这点和Swift 中的 protocol 的所有方法都必须实现这一特性完全不同。那些如果没有实现则接口就无法正常工作的方法一般是必不可少的,而像作为事件通知或者对非关键属性进行配置的方法一般都是可选的。最好的例子我想应该是UITableViewDataSour原创 2021-03-24 17:12:55 · 280 阅读 · 0 评论 -
Swift - Options
不要误会,我们谈的是Options,不是Optional。后者已经被谈论太多了,我不想再在上面补充什么了。我们来说说Options,或者Objective-C 中的NS_OPTIONS,在Swift 中是怎样的形式吧。在Objective-C 中,我们有很多需要提供某些选项的API,它们一般用来控制API 的具体行为配置等。举个例子,常用的UIView 动画的API 在使用时就可以进行选项指定:[UIView animateWithDuration:0.3 delay:0.0 options:UIVi原创 2021-04-01 15:05:02 · 412 阅读 · 0 评论 -
Swift - ... 和 ..<
在很多脚本语言中(比如Perl 和Ruby),都有类似 0..3或者 0...3 这样的Range操作符,用来简单的指定一个从X 开始连续计数到Y 的范围。这个特性不论在哪个社区,都是令人爱不释手的写法,Swift 中将其光明正大的“借用”过来,也就不足为奇了。最基础的用法当然还是在两边指定数字, 0...3就表示从0 开始到3 为止并包含3 这个数字的范围,我们将其称为全闭合的范围操作。而在某些时候(比如操作数组的index 时),我们更常用的是不包括最后一个数字的范围。这在Swift中被用一个看起来有原创 2021-03-19 10:40:46 · 694 阅读 · 0 评论 -
Swift - 初始化返回nil
在Objective-C中,init 方法除了返回 self 以外,其实和一个普通的实例方法并没有太大的区别。如果你喜欢的话,甚至可以多次进行调用,这都没有限制。一般来说,我们还会在初始化失败(比如输入不满足要求无法正确的初始化)的时候返回nil 来通知调用者这次初始化没有正确完成。但是,在Swift中默认情况下初始化方法是不能写return语句来返回值的,也就是说我们没有机会初始化一个Optional的值。一个很典型的例子就是初始化一个 url。在Objective-C中。如果我们使用一个错误的字符串来原创 2021-03-17 15:20:15 · 818 阅读 · 0 评论 -
Swift - 属性观察
属性观察(Property Observers)是Swift中一个很特殊的性质,利用属性观察我们可以在当前类型内监视对于属性的设定,并做出一些响应。Swift 中为我们提供了两个属性观察的方法,它们分别是willSet 和didSet使用这两个方法十分简单,我们只要在声明属性的时候添加相应的代码块,就可以对将要设定的值和已经设定的值进行监听了:class MyClass { var date: Date { willSet { print("即将将日期从\原创 2021-03-19 17:09:27 · 281 阅读 · 0 评论 -
Swift -字面量转换
所谓字面量,就是指像特定的数字、字符串和布尔值这样,能够直截了当的指出自己的类型并为变量进行赋值的值。我们看下面的例子:let aNumber = 3let aString = "hello"let aBool = true其中的3、hello和true就称为字面量在Swift中,Array和Dictionary在使用简单的描述赋值的时候,使用的也是字面量,比如:let anArray = [1, 2, 3]let aDictionary = ["key1": "value1", "key2原创 2021-03-15 11:05:02 · 207 阅读 · 0 评论 -
Swift - protocol 组合
众所周知,在Swift中我们可以使用 Any 来表示任意类型。充满好奇心的读者已经发现,Any这个类型的定义十分奇怪,它是一个 protocol<> 的同名类型。像protocol<>这种形式的写法在Swift的日常使用中并不多见,这其实是Swift的接口组合的用法。标准的语法形式是下面这样的:ProtocolA & ProtocolB & ProtocolC尖括号内是具体接口的名称,这里表示将名称为ProtocolA, ProtocolB及ProtocolC原创 2021-03-17 17:28:31 · 277 阅读 · 0 评论 -
Swift - @main 与 @UIApplicationMain
因为Cocoa 开发环境已经在新建一个项目时帮助我们进行了很多配置,这导致了不少刚接触iOS 的开发者都存在基础比较薄弱的问题,其中一个最显著的现象就是很多人无法说清一个App 启动的流程。程序到底是怎么开始的,AppDelegate 到底是什么,xib 或者storyboard 是怎么被加载到屏幕上的? 这一系列的问题,我们在开发中虽然不会每次都会去关心和配置,但是如果能进行一些了解的话,对于程序各个部分的职责的明确会很有帮助。在C 语言中,程序的入口都是main 函数。对于一个Objective-C原创 2021-03-24 10:53:32 · 3475 阅读 · 1 评论 -
Swift - 下标
下标相信大家都很熟悉了,在绝大多数的语言中使用下标来读写类似数组和字典等数据结构的做法,似乎已经是业界标准。在Swift中,Array和Dictionary当然也实现了下标读写:var arr = [1, 2, 3]let a = arr[2] // 2arr[2] = 4 // [1, 2, 4] var dic = ["cat": "meow", "goat": "mie"]let d = dic["cat"] // meowdic["cat"] = "miao" // ["原创 2021-03-15 15:12:18 · 481 阅读 · 0 评论 -
Swift - Any 和 AnyObject
Any 和 AnyObject是Swift中两个妥协的产物,也是很让人迷惑的概念。在Swift官方变成指南中指出:AnyObject 可以代表任何Class类型的实例Any 可以表示任意类型,甚至包括方法(func)类型AnyObject先来说说AnyObject吧。写过Objective-C的读者可能会知道在Objective-C中有一个叫做id的神奇的东西。编译器不会对申明为id的变量进行类型检查,它可以表示任意类的实例。在 Cocoa 框架中很多地方都使用了id来进行像参数传递和方法返回这原创 2021-03-16 11:02:36 · 1358 阅读 · 1 评论 -
Swift - 列举enum 类型
设想我们有这样一个需求,根据一副扑克牌和牌面大小的enum 类型,凑出一套不含大小王的扑克牌的数组。扑克牌花色和牌面大小分别由下面两个enum 来定义:enum Suit: String { case Spades = "黑桃" case Hearts = "红桃" case Clubs = "草花" case Diamods = "方片"}enum Rank: Int { case Ace = 1 case Two, Three, Four, Fi原创 2021-04-15 14:14:39 · 273 阅读 · 0 评论 -
Swift - 初始化方法顺序
与Objective-C不同,Swift的初始化方法需要保证类型的所有属性都被初始化,所以初始化方法的调用顺序就很有讲究。在某个类的子类中,初始化方法里语句的顺序并不是随意的,我们需要保证在当前子类实例的成员初始化完成后才能调用父类的初始化方法:class Cat { var name: String init() { name = "cat" }}class Tiger: Cat { let power: Int override init(原创 2021-03-17 10:21:40 · 329 阅读 · 0 评论 -
Swift - Mirror
熟悉Java 的读者可能会知道反射(Reflection)。这是一种在运行时检测、访问或者修改类型的行为的特性。一般的静态语言类型的结构和方法的调用等都需要在编译时决定,开发者能做的很多时候只是使用控制流(比如 if 或者 switch)来决定做出怎样的设置或是调用哪个方法。而反射特性可以让我们有机会在运行的时候通过某些条件实时的决定调用的方法,或者向某个类型动态的设置甚至加入属性及方法,是一种非常灵活和强大的语言特性。Objective-C中我们不会经常提及“反射”这样的词语,因为Objective-C原创 2021-03-22 16:10:38 · 315 阅读 · 0 评论 -
Swift - 判等
我们在Objective-C 时代,通常使用 - isEqualToString: 来在已经能确定比较对象和待比较对象都是NSString 的时候进行字符串判等。Swift 中的String 类型中是没有- isEqualToString: 或者 - isEqual: 这样的方法的,因为这些毕竟是NSObject 的东西。Swift 的字符串内容判等,我们简单的使用== 操作符来进行:let str1 = "快乐的字符串"let str2 = "快乐的字符串"let str3 = "开心的字符串"原创 2021-03-30 17:53:30 · 1600 阅读 · 0 评论 -
Swift - 获取对象类型
我们一再强调,如果遵循规则的话,Swift 会是一门相当安全的语言:不会存在类型的疑惑,绝大多数内容应该能在编译期间就唯一确定。但是不论是Objective-C 里很多开发者早已习惯的灵活性,还是程序时间里总是千变万化的需求,都不可能保证一成不变。我们有时候也需要引入一定的动态特性。而其中最为基本却最为有用的技巧是获取任意一个实例类型。在Objective-C 中我们可以轻而易举的做到这件事,使用 - class 方法就可以拿到对象的类,我们甚至可以用NSStringFromClass 将它转换为一个能够原创 2021-03-29 11:53:43 · 1092 阅读 · 0 评论 -
Swift - 调用C 动态库
C 是程序世界的宝库,在我们面向的设备系统中,也内置了大量的C 动态库帮助我们完成各种任务。比如涉及压缩的话我们很可能借助于libz.dylib 或libz.tbd,而像xml 的解析的话一眼链接libxml.dylib 或libxml.tbd 就会方便一些。因为Objective-C 是C 的超集,因此在以前我们可以无缝的访问C 的内容,只需要指定依赖并且导入头文件就可以了。但是骄傲的Swift 的目的之一就是甩开C 的历史包袱,所以现在在Swift 中直接使用C 代码或者C 的库是不可能的。举个例子,原创 2021-04-01 10:53:19 · 1128 阅读 · 0 评论 -
Swift - 数学和数字
Darwin 里的math.h 定义了很多和数学相关的内容,它在Swift 中也被进行了module 映射,因此在Swift 中我们是可以直接使用的。有了这个保证,我们就不需要担心在进行数学计算的时候会和标准有什么差距。比如,我们可以轻易的使用圆周率来计算周长,也可以使用各种三角函数来完成需要的屏幕位置计算等:func circlePerimeter(radius: Double) -> Double { return 2 * M_PI * radius}func yPosition(原创 2021-04-12 17:03:04 · 591 阅读 · 0 评论 -
Swift - func 的参数修饰
在声明一个Swift的方法的时候,我们一般不去指定参数前面的修饰符,而是直接声明参数:func incrementor(variable: Int) -> Int { return variable + 1}这个方法接受一个int的输入,然后通过将这个输入加1,返回一个新的比输入大1的Int,这其实就是一个简单的“+1器”在C/C++中我们学过 ++ 这样的“自增”运算符,再加上做了不少关于 “判断一个数被各种前置 ++ 和后置 ++ ‘折磨’后的输出是什么” 的题,所以之后写代码时原创 2021-03-12 14:46:50 · 370 阅读 · 0 评论 -
Swift - 溢出
对于目前的iOS开发中,已经越来越不需要考虑溢出的概念了,因为自从IPhone 5s 手机发布后,都使用的是64位的操作系统了,而IPhone 5 之前的手机基本上都更换了新手机了。但是我们还是需要了解一下曾经困扰开发者的问题----溢出。举个例子,在Swift 中我们一般简单的使用Int 来表示整数,在32位的设备中,这个类型其实等同于Int32,而在64位 设备中表示的是Int64(这点和Objective-C 中的NSInteger 表现是完全一样的,事实上,在Swift 中NSInteger 只是原创 2021-04-13 17:26:49 · 351 阅读 · 0 评论 -
Swift - @autoclosure 和 ?? 操作符
@autoclosure@autoclosure 可以说事Apple的一个非常神奇的创造,因为这更多的是像在“hack”这门语言。简单的说,@autoclosure做的事情就是把一句表达式自动的封装成一个闭包(closure),这样有时候在语法上会非常漂亮比如我们有一个方法接收一个闭包,当闭包执行的结果为true的时候进行打印func logIfTrue(_ predicate: () -> Bool) { if predicate() { print("True")原创 2021-03-11 15:44:24 · 260 阅读 · 0 评论 -
Swift - UnsafePointer
Swift 本身从设计上来说是一门非常安全的语言,在Swift 的思想中,所有的引用或者变量的类型都是确定并且正确对应它们的实际类型的,你应当无法进行任意的类型转换,也不能直接通过指针做出一些“出格”的事情。这种安全性在日常的程序开发中对于避免不必要的bug,以及迅速而且稳定的找出代码错误是非常有帮助的。但是凡事都有两面性,在安全性高的同时,Swift 也相应的丧失了部分的灵活性。现阶段想要完全抛弃C 的一套东西还是相当困难的,特别是在很多“上古”级别的C API框架还在使用(或者被简介使用)。开发者,尤原创 2021-03-26 17:25:52 · 533 阅读 · 1 评论 -
Swift - 数组enumerate
使用NSArray 时一个很常见的需求是在枚举数组内元素的同时也想使用对应的下标索引,在Objective-C 中最方便的方式是使用NSArray 的enumerateObjectsUsingBlock: 方法。因为通过这个方法可以显式的同时得到元素和下标索引,这会有最好的可读性,并且block 也意味着可以方便的在不同的类之间传递和复用这些代码。NSArray *arr = @[@1, @2, @3, @4, @5];__block NSInteger result = 0;[arr enumera原创 2021-04-01 16:38:57 · 893 阅读 · 0 评论 -
Swift -序列(Sequence)
Swift的for...in 可以用在所有实现了SequenceType的类型上,而为了实现SequenceType你首先需要实现一个GeneratorType。比如一个实现了反向generator和Sequence可以这么写protocol GeneratorType { associatedtype Element func next() -> Element?}// 先定义一个实现了 GeneratorType protocol 的类型// Generator原创 2021-03-11 10:41:07 · 539 阅读 · 0 评论 -
Swift - NSNull
NSNull 出场最多的时候就是在JSON 解析了。在Objective-C 中,因为NSDictionary 和NSArray 只能存储对象,对于像JSON 中可能存在的null 值,NSDictionary 和NSArray 中就只能用NSNull 对象来表示。Objective-C 中的nil 实在是太方便了,我们向nil 发送任何消息时都将返回默认值,因此很多时候我们过于依赖这个特性,而不再去进行检查就直接使用对象。大部分时候这么做没有问题,但是在处理JSON 时,NSNull 却无法使用像nil原创 2021-04-13 11:50:12 · 648 阅读 · 0 评论 -
Swift - @autoreleasepool
Swift 在内存管理上使用的是自动引用计数(ARC)的一套方法,在ARC 中虽然不需要手动的调用retain、release 和 autorelease 这样的方法来管理引用计数,但是这些方法还是都会被调用的----只不过是编译时在合适的地方帮我们加入了而已。其中retain 和release 都很直接,就是将对象的引用计数加1 或者减1。但是autorelease 就比较特殊一些,它会将接受该消息的对象放到一个预先建立的自动释放池(auto release pool)中,并在自动释放池收到drain 消原创 2021-03-25 17:01:54 · 1241 阅读 · 0 评论 -
Swift - Toll-Free Bridging 和 Unmanaged
有经验的读者看到标题就能知道我们要谈论的是Core Foundation。Swift 对于Core Foundation(以及其他一系列Core 开头的框架)在内存管理上进行了一系列简化,大大降低了与这些Core Foundation(以下简称CF)API 打交道的复杂程度。首先值得一提的是对于Cocoa 中Toll-Free Bridging 的处理。Cocoa 框架中的大部分NS 开头的类其实在CF 中都有对应的类型存在,可以说NS 只是对CF 在更高层面的一个封装。比如NSURL 和它在CF 中的C原创 2021-04-07 15:17:38 · 314 阅读 · 0 评论 -
Swift - 类簇
虽然可能不太被重视,但类簇(class cluster)确实是Cocoa 框架中广泛使用的设计模式之一。简单来说类簇就是使用一个统一的公共的类来订制单一的接口,然后在表面之下对应若干个私有类进行实现的方式,这么做做大的好处是避免公开很多子类造成混乱,一个最典型的例子是NSNumber,我们有一系列不同的方法可以从整数、浮点数或者布尔值来生成一个NSNumber 对象,而实际上它们可能是不同的私有子类对象:NSNumber *num1 = [[NSNumber alloc] initWithInt:1];原创 2021-03-31 14:46:51 · 283 阅读 · 0 评论 -
Swift - 接口和类方法中的Self
我们在一些接口的定义时,可能会注意到首字母大写的Self 出现在类型的位置上,例如:protocol IntervalType { /// Return `rhs` clamped to `self`. The bounds of the result, even /// if it is empty, are always whin the bounds of `self` func clamp(intervalToClamp: Self) -> Self}上面这个I原创 2021-03-19 15:12:33 · 322 阅读 · 0 评论 -
Swift -宏定义 define
Swift 中没有宏定义。宏定义确实是一个让人又爱又恨的特性,合理利用的话,可以让我们写出很多简洁漂亮的代码,但是同时,不可否认的是宏定义无法受益于IDE 工具,难以重构和维护,很可能隐藏很多bug,这对于开发其实并不是一件好事。Swift 中将宏定义彻底从语言中拿掉了,并且Apple 给了我们一些替代的建议:使用作用范围合适的let 或者 get 属性来替代原来的宏定义值,例如很多Darwin 中的C 的define 值就是这么做的:@inlinable public static var p原创 2021-04-14 14:22:50 · 1861 阅读 · 0 评论 -
Swift - delegate
Cocoa 开发中接口-委托(protocol-delegate)模式是一种常用的设计模式,它贯穿于整个Cocoa 框架中,为代码之间的关系清理和解耦合做出了不可磨灭的贡献。在ARC 中,对于一般的delegate,我们会在声明中将其指定为weak,在这个delegate 实际的对象被释放的时候,会被重置回nil。这可以保证即使delegate 已经不存在,我们也不会由于访问到已被回收的内存而导致崩溃。ARC的这个特性杜绝了Cocoa 开发中一种非常常见的崩溃错误,说是救万千程序员于水火之中也毫不为过。原创 2021-04-06 15:39:24 · 292 阅读 · 0 评论 -
Swift - 多类型和容器
Swift 中有两个原生的容器类型,Array和Dictionary:@frozen public struct Array<Element> { }@frozen public struct Dictionary<Key, Value> where Key : Hashable {}它们都是泛型的,也就是说我们在一个集合中只能放同一个类型的元素,比如:let numbers = [1, 2, 3, 4, 5]// numbers 的类型是[Int]原创 2021-03-18 14:55:25 · 365 阅读 · 0 评论 -
Swift - GCD 和延时调用
GCD 是一种非常方便的使用多线程的方式。通过使用GCD,我们可以在确保语法尽量简单的前提下进行灵活的多线程编程。在“复杂必死”的多线程编程中,保持简单就是避免错误的金科玉律。好消息是在Swift 中是可以无缝使用GCD 的API 的,而且得益于闭包特性的加入,使用起来比之前在Objective-C 中更加简单方便。在这里我不打算花费很多时间介绍GCD 的语法和要素,否则就可以专门为GCD 写上一节了。下面给出了一个日常生活中最常使用的例子(说这个例子能覆盖到日常GCD 使用的50% 以上也不为过),来展示原创 2021-03-29 11:03:20 · 1800 阅读 · 0 评论 -
Swift - 编译标记
在 Objective-C 中,我们经常在代码中插入 #param 符号来标记代码的区间,这样在Xcode 的导航栏中我们就可以看到组织分块后的方法列表。这在单个文件方法较多的时候进行快速定位非常有用。在Swift 中也有类似的方式,我们可以在代码中合适的地方添加 // MARK: 这样的标记(注意大写),并在后面接上名称,Xcode将在代码中寻找这样的注释,然后以粗体标签的形式将名称显示在导航栏中,比如:另外我们还可以在冒号的后面加一个横杠 - ,让标记更明显。除了 // MARK: 以外,Xco原创 2021-03-23 17:21:26 · 237 阅读 · 0 评论 -
Swift - 断言
断言(assertion)在Cocoa 开发里一般用来检查输入参数是否满足一定条件,并对其进行“论断”。这是一个编码世界中的哲学问题,我们代码的使用者(有可能是别的程序员,也可能是未来的自己)很难做到在不知道实现细节的情况下去对自己的输入进行限制。大多数时候编译器可以帮助我们进行输入类型的检查,但是如果代码需要在特定的输入条件下才能正确运行的话,这种更细致的条件就难以控制了。在超过边界条件的输入的情况下,我们的代码可能无法正确工作,这就需要我们在代码实现中进行一些额外工作。一种容易想到的做法是在方法内使用原创 2021-04-09 10:21:08 · 390 阅读 · 0 评论