引子
鉴于React Native目前版本在iOS上开发遇到诸多问题,本以为搞RN只需理会Javascript开发,没想到冒出CocoaPod的一堆编译问题。所以横下一条心,决定直接进攻iOS本身。不管你是用React Native,还是用Flutter,iOS下的直接编程Swift或OC都是绕不过去的坎。
Xcode比Android Studio要香,模拟器运行快,当然配置更复杂。
2014年苹果发布了Swift , 2019年SwiftUI发布。从此iOS开发的面貌焕然一新。
Xcode工程结构核心概念
每一门编程语言都会有namespace, module, package这些基本概念,但定义上都存在一些差异。这些差异会影响到加载和相互调用关系。所以,学习一门编程语言,首要是弄清楚这些基本概念是如何定义的。
Xcode里有两个概念和其它开发工具不同,一个叫Schema,一个叫Target。Schema可以理解为解决方案,一个Schema可以对应不同的Target,生成物也不同。
- Project和Workspace
- Package:包是Swift Package Manager的概念,不是Swift语言的概念,包的根目录下需要存在一个Package.swift描述文件
- Target: 通常也被称为build target,也就是构建的目标
- 在创建项目的时候默认就会创建一个target,有时被称为主target
- 一个工程里可以创建多个target,每个target都对应相应的模板
- 一个包里可以有一个或多个target,也就是一个target列表。
- 一个target是一个app bundle 或 framework。每个target构建后对应一个库或一个可执行文件作为product。
- target之间存在依赖关系,可以在Xcode里定义某个target依赖哪些其它target
- Module:很多编程语言里一个文件对应一个module,但Swift不是。
- 模块是代码的集合,对应一个或多个文件,里面定义Swift的 类、函数等
- 一个模块对应一个发布单元
- 一个module就可以看成是一个project中的一个target,这个target的默认模块名称就是这个项目的名称(可以在target的Build Settings—Product Module Name配置)
- 在同一个模块中所有的Swift类处于同一个命名空间,它们之间不需要导入就可以相互访问
- namespace: 一个class或一个struct就定义一个namespace,或者说一个{}就对应一个namespace
- Swift有命名空间,而Objective-C没有。
- Swift并没有namespace这个关键字
- Bundle:Xcode 工程项目本身就是在一个 Bundle 之下,开发者可以使用 Bundle.main 来获取其中的资源
- Library 和 Framework:
Modules: Swift organizes code into modules. Each module specifies a namespace and enforces access controls on which parts of that code can be used outside of the module.
A program may have all of its code in a single module, or it may import other modules as dependencies. Aside from the handful of system-provided modules, such as Darwin on macOS or Glibc on Linux, most dependencies require code to be downloaded and built in order to be used.
When you use a separate module for code that solves a particular problem, that code can be reused in other situations. For example, a module that provides functionality for making network requests can be shared between a photo sharing app and a weather app. Using modules lets you build on top of other developers’ code rather than reimplementing the same functionality yourself.
Packages: A package consists of Swift source files and a manifest file. The manifest file, called Package.swift, defines the package’s name and its contents using the PackageDescription module.
A package has one or more targets. Each target specifies a product and may declare one or more dependencies.
namespace与文件名和路径无关,只与模块名有关。这一点不同于Java和Python。
Swift工程结构示例:
不管你是Run,还是Build,首先要明确你是针对哪个Schema。如下,你要选择对应的Schema才行。
创建了两个Target,其中一个是Unit Test,依赖主target。
Swift语法速记(TODO)
每一门编程语言都喜欢用不同的方式做和别人相同的事情。不知道这是故意标新立异,还是真的有某种道理,难道设计者不知道Java和C的语言风格已经成了大众的习惯吗?对于程序员来说只能选择接受。例如定义函数的关键字就有def, func, function等,Swift也不例外,也搞了一套自己的语法糖。
- 常量用let,变量用var
- 字符串可以用单引号或双引号,多行字符串用三个单引号或三个双引号
- 数组、Set、字典都是用中括号定义,都可以用for-in遍历
var shoppingList: [String] = ["Eggs", "Milk"] //数组
var favoriteGenres: Set<String> = ["Rock", "Classical", "Hip hop"] // 集合
var airports: [String: String] = ["YYZ": "Toronto Pearson", "DUB": "Dublin"] // 字典
- as, as?, as!的区别:as向上转,as!向下转。不确定向下转型可以成功时,用类型转换的条件形式(as?),只有你可以确定向下转型一定会成功时,才使用强制形式(as!)
- 扩展: 扩展可以给一个现有的类,结构体,枚举,还有协议添加新的功能。类似与Javascript的原型机制
- 协议:类似于Java的接口
- subscript:用来索引对象。下标可以定义在类、结构体和枚举中,是访问集合、列表或序列中元素的快捷方式。
常见问题
Xcode添加package时连接github超时
由于Xcode不能直接设置代理,所以稳妥方式是手工下载github代码,再添加时选Local:
刷新几把Xcode,有时需要关闭项目或关闭Xcode再重启,然后给target添加上对这些包的依赖即可:
官方给的解决方案是:
On the terminal xcodebuild -scmProvider system -resolvePackageDependencies -disablePackageRepositoryCache -workspace MyProject.xcworkspace -scheme MyScheme
On XCode after the xcodebuild finishes XCode - File - Packages - Resolve Package Versions.