Swift及SwiftUI学习笔记

持续更新中......

swift官方文档


swift官方文档(英文)

协议


swift主要基于协议编程的,所以协议无处不在。
先看看这篇文章:Swift学习:协议

官方的一些常用协议:
1. Equtable
在Swift中可以通过实现Equatable协议使自定义类型支持==以及!=这两种运算符。

2. Comparable
Comparable协议继承于Equatable,实现Comparable协议可以在Equatable的基础上使类型支持>,>=,<,<=四种运算符。

3. CustomStringConvertible
当类实现这个协议,可使用print打印类的自定义信息。

4. CustomDebugStringConvertible
当类实现这个协议,可使用debugPrint打印类的自定义信息。

5. Hashable
继承于Equatable。
一个类型为了存储在集合中,该类型必须是可哈希化的-该类型必须提供一种方法计算它的哈希值,一个哈希值为Int类型,相等的对象哈希值必须相同。
Swift的所有基本类型(形如String,Int,Double,Bool)默认是可哈希化的,可以作为集合的值的类型或者字典的键的类型。没有关联值的枚举成员值默认也是可哈希化的。

用我的话来说:当想把自定义对象当做key存入set和dict中时,那么这个key必须是哈希的,并且要重载等号来对比key之间的不同。

官方的文档说的比较清楚,这里有篇中文翻译:
Swift之Hashable协议

6. Codable
Codable = Decodable & Encodable
顾名思义,即编解码序列化。
具体参看以下文章:
Swift 4.0: Codable
Swift 4 踩坑之 Codable 协议

这里的“&”符号的意思是协议合成:
协议合成并不会生成新的、永久的协议类型,而是将多个协议中的要求合成到一个只在局部作用域有效的临时协议中。
协议合成的意思是都罗列的协议都需要遵循。
其实不仅仅是协议可以合成,类也可以跟协议一起使用“&”符号合成。

7. CaseIterable
一句话:CaseIterable被用于合成简单枚举类型的 allCases 静态属性。
Swift 4.2 新特性详解 CaseIterable.allCases
Swift--enum枚举,协议CaseIterable

8. Identifiable
这个协议只需要你定义一个 id 属性,这个属性必须是一个 Hashable 类型。

协议和泛型


加粗的这句话非常重要:

针对Class和Function,都是通过<Type>来定义。而当我们需要给协议实现一个泛型的时候,需要使用associatedtype关键字来定义泛型:这里需要注意,泛型协议并不能像普通协议那样作为一个类型使用,这是因为 GenericProtocol 表示一组类型,并不是一个单一类型。比如你有一个关于 GenericProtocol 的随机数组,并不能确定每个元素的 magic() 方法返回的类型到底是什么,因为数组中每个元素可能都是不同的。

泛型最终在使用时都要被推断出来,一种情况是实现的时候指定了类型,另一种在调用时明确类型。

参考:

  1. swift的泛型协议为什么不用<T>语法
  2. 为什么 Swift 关联类型的协议需要做为泛型约束使用(译)

元类型.Type 与 .self


一开始看到官方例子中有一行这样的代码:

func load<T: Decodable>(_ filename: String, as type: T.Type = T.self) -> T {
...
}
//调用方法
let landmarkData: [Landmark] = load("landmarkData.json")

对于as type: T.Type = T.self这一部分不理解,搞懂这个需要先学习元类型。

元类型就是类型的类型。

let n : Int = 5

变量n的类型是Int类型,这个很容易理解。
那么Int的类型又是什么呢?
Int的类型就是:Int.Type,类型的类型,即元类型。
说完类型来说值:
n的类型是Int,值是5。

let m: Int.Type = Int.self

那么变量m的类型是元类型Int.Type,m的值是Int.self

到这儿我们再回头来看上面的代码:

func load<T: Decodable>(_ filename: String, as type: T.Type = T.self) -> T {
...
}

as在这儿是标签名字,type是参数名,它的类型是:T.Type元类型,默认值是T.self
所以我们也可以这样调用方法,跟不写第2个参数是等价的:

let landmarkData: [Landmark] = load("landmarkData.json", as: [Landmark].self)

class和static的区别


class和static用于修饰方法和计算属性使其成为静态方法或者静态属性。

最大的区别:

  1. class只能在类中使用,static可以在类和结构中使用。
  2. class修饰的方法可以被子类重写,而static不能被重写。

其他细节的区别参看:
swift3.0 中class和static

ForEach和\.self


官方例子:

static var previews: some View {
        ForEach(["iPhone SE", "iPhone XS Max"], id: \.self) { deviceName in
            LandmarkList()
                .previewDevice(PreviewDevice(rawValue: deviceName))
                .previewDisplayName(deviceName)
        }
        .environmentObject(UserData())
    }

需要先学习这篇文章:
SwiftUI 和 Swift 5.1 新特性(3) Key Path Member Lookup

enum: if case,guard case,for case


模式匹配第四弹:if case,guard case,for case

关键字


associatedtype:
从字面上来理解,就是相关类型。意思也就是被associatedtype关键字修饰的变量,相当于一个占位符,而不能表示具体的类型。具体的类型需要让实现的类来指定。

typealias:
用来为已经存在的类型重新定义名字的,通过命名,可以使代码变得更加清晰。使用的语法也很简单,使用typealias 关键字像使用普通的赋值语句一样,可以将某个已经存在的类型赋值为新的名字。

Combine


Combine可以看作是简化版的RxSwift,Combine目前学习资料不多,可以先学RxSwift了解基本概念,再使用下面的对照速查表快速学习Combine。
RxSwift中文文档
RxSwift 使用详解系列
Swift Combine 入门导读
RxSwift到Apple的Combine速查表(Cheat Sheet)

Apple Combine 的开源实现:
有空可以看看,对于加深Combine的理解有好处。
有两个项目:

  1. OpenCombine
    项目地址:broadwaylamb/OpenCombine

  2. Apple Combine 的开源实现 CombineX 的第一个 beta 发布啦!
    项目地址:luoxiu/CombineX

SwiftUI学习资料


  1. 这个是官方Demo的中文翻译文档
    建议先从这里开始学,结合源码学的更快。
    WillieWangWei/SwiftUI-Tutorials

  2. 基本控件、状态流、手势等知识的简单说明和示范
    Jinxiansen/SwiftUI

3.SwiftUI之属性包装
讲解了以下属性包装:

@State
ObservableObject
@Published
@ObservedObject
@EnvironmentObject
@Environment
@Binding
@GestureState

学习SwiftUI遇到的问题和bug


  1. SwiftUI update navigation bar title color
  2. 滚动ScrollView到指定位置:
    SwiftUI ScrollView: How to modify .content.offset aka Paging?
  3. 键盘弹出/隐藏时修改布局
    How to show complete List when keyboard is showing up in SwiftUI
  4. SecureField
  • 只要在页面中使用了SecureField那么该页面的第三方输入法就被禁用,在其他TextField上也不能调出。
    在切换到另外页面中可以调出第三方键盘,不过因为在此页面中已经被切换到系统输入法,所以在别的页面需要手动切换第三方键盘。
  • 运行时焦点切换到SecureField会打印以下log:

[AutoFill] Cannot show Automatic Strong Passwords for app bundleID: xxx.xxx due to error: Cannot save passwords for this app. Make sure you have set up Associated Domains for your app and AutoFill Passwords is enabled in Settings

可以忽略不管。
参看此篇文章:WWDC18 iOS 自动生成强密码和自动填充验证码/密码

  1. 去掉导航头
.navigationBarHidden(true)
.navigationBarBackButtonHidden(true)
.navigationBarTitle("注册", displayMode:.inline)//tmd,必须设置这个才能真使.navigationBarHidden(true)有效
  1. xcode的一个bug
    在一个文件中SwiftUI预览时右边工具栏的属性栏始终出不来,另一个文件可以看到属性栏,折腾了半天把文件名一改属性栏居然出来了,再把文件名改回去也一切正常。
  2. 去掉List或者Form的左边空白
    加在List/Form的子级中:
.listRowInsets(EdgeInsets())

以上还会留一点点空白,使用以下把空白完全去除:

.listRowInsets(EdgeInsets(top: 0, leading: -8, bottom: 0, trailing: 0))

或者

.padding(.horizontal, -24)

以上的-8,-24是自己对着界面调出来的,不一定通用(可能在不同平台有不同表现)。一般问题不用太精确,凑合用着可以了。

  1. 不要随便用Button
    在Form的Section底下用了Button,当点击一栏中不被其他控件比如TextField完全填充的空白区域时都会激活Button的action事件,把Button换成Image并且使用onTapGesture事件就正常了。
    Image点击事件代码例子:
 Image(systemName: "xmark.circle.fill")
                                    .foregroundColor(.gray).opacity(0.5)
                                    .imageScale(.small)
                                    .onTapGesture {
                                           print("image click")
                                    }
  1. TextField在系统自带的简体拼音输入法时有bug
    首先是输入时键盘上的候选区闪动,另外输入会莫明其妙的被自动删除或者多出字符,总之该输入法在TextField中基本不能用。
    然后我换成UITextField后就没问题了,shit!
    目前iOS13.2.3依然有此bug。

  2. TextField和SecureField回车后无法自动切换到下一个输入框。

  3. 根据上面第9和第10条,TextField和SecureField最好还是别用,用UIKit版封装一下替代。

  4. 最好不要自定义previewDevice

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ForEach("iPhone SE","iPhone XS Max", "iPhone 11 ", "iPhone 11 Pro"], id: \.self) { deviceName in
            ContentView()
                .previewDevice(PreviewDevice(rawValue: deviceName))
                .previewDisplayName(deviceName)
        }
        .environmentObject(UserData())
    }
}
  • 以上"iPhone 11 "在我机器上一定要加后面那个空格,否则preview时一直出不来。
  • 我实际上只使用一个设备比如"iPhone XS Max"或者"iPhone 11 Pro",当使用Xcode一段时间后,Xcode的子进程:SourceKitService会疯狂占用内存,占用的内存多达几十G,机器变得非常慢,最后只好强制杀死SourceKitService进程。
    不使用以上自定义previewDevice,只使用以下默认代码则一切正常:
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
  1. 改变全屏颜色包括SafeArea区域
//  Color实际是个View,所以可以使用edgesIgnoringSafeArea来忽略安全区达到全屏效果
.background(Color(red: 0.9, green: 0.9, blue:0.9).edgesIgnoringSafeArea(.all))
  1. 当在xcode中打开多个Tab窗口时,只在一个Tab中开启Preview。如果在多个Tab中开启Preview的话可能会预览失败。

Font Icon和SF Symbols


Font Icon:
开源库好几个,我先选择了这个:
ranesr/SwiftIcons
不过后来发现苹果官方有SF Symbols

SF Symbols:
ios13以上系统自带SF Symbols,应该也是Font Icon,可以直接调用。
官方文档说明:
SF Symbols
要想知道所有符号名字需要下载上面页面提供的一个mac软件,不过直接下载很慢,使用迅雷快很多。

所以使用SwiftUI开发APP的话可以不使用第三方FontIcon直接使用SF Symbols
调用例子:

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