可选型optional
- 可选型本质上是一个枚举类型enum
enum Optional<T> {// The <T> is a generic like as in Array<T>
case none
case some(T)
}
以下两种写法是等价的
let x:String? = nil
... is ...
let y = Optional<String>.none
let x:String? = "Hello"
... is ...
let x = Optional<String>.some("Hello")
// unwrap
let y = x!
...is...
switch x {
case .some(let value):y = value
case .none:// raise an excepiton
}
let x:String? = ...
if let y = {
// do someting with y
}
... is ...
switch x {
case .some(let y):// do something with y
case .none:break
}
- 可选型是可以链式传递的
var display:UILabel?
if let temp1 = display {
if let temp2 = temp1.text {
let x = temp2.hashValue
//...
}
}
// 等价于 链式解包如果中间有一个为nil,返回的值为nil
if let x = display?.text.hashValue // x is an Int
let x = display?.text.hashValu // x is an Int?
//因此在链式解包时使用?而不是!
-
可选默认值操作符??
如果可选型解包值为nil,则赋予默认值
let s: String? = ...
if s != nil {
display.text = s
}else {
display.text = ""
}
// 等价于
display.text = s??""
元组 tuple
tuple is a grouping of values
You can use it anywhere you can use a type.
let x: (String,Int,Double) = ("Hello",5,0.85)// the tyoe of x is a tuple
let (word,number,value) = x// this names the tuple emlements when accessing the tuple 当元组被访问时,命名元组内的元素
print(word)// hello
print(number)// 5
print(value)// 0.85
// 当元组被声明的时候也可以为元组元素命名 建议使用这种,tuple 可以通过点语法访问元组内的元素
let y:(x:String,i:Int,v:Double) = ("Hello",5,0.85)
print(y.x)
print(y.i)
print(y.v)
// 可以使用下划线忽略元组中元素
let (word,_,value) = x
Range
A range in swift is just tow end Points.
A range can represent things like a selection in some text or a portion of an Array
Range is generic(e.g. Range<T>), but T is restricted(e.g. comparable).
类似于这种
struct Range<T> {
var startIndex:T
var endIndex:T
}
CountableRange 包含的值可以迭代或者用下标访问
创建Range有一种特殊的语法
..< 不包含上限。
...包含上限
CountableRange 可以用for in 遍历
// C-like : for (i = 0;i<20;i++)
for i in 0..<20 {
}
// 浮点数不是countable的 对于 for(i=0.5;i<=15.25;i+=3) 是无法直接使用forin的,但是有一个通用的方法可以从浮点数创建一个CountableRange
for i in stride(from:0.5,through:12.25,by:0.3){
}
数据结构 struct,enum,class
相似点:
语法声明相似
class ViewController: ... {
}
struct Calculation {
}
enum Opration {
}
都可以拥有属性和方法
func doit(agrx agri:Type)->ReturnValue{
}
var storedProperty =<initial value>(not enum)
var computedProperty:Type {
get{}
set{}
}
初始化(not enum)
init(arg1x arg1i:Type,arg2x arg2i:Type ...){
}
不同点:
-
只有class可以继承
-
struct 和 enum是值(value)类型,而class是引用类型(inference)
值类型(如struct,enum)特点如下:
Copied when passed as an argument to a founction
Copied when assigned to a different variable
Immutable if assigned to a variable with let (function parameters are
let
)You must note any
func
that can mutate a struct/enum with the keywordmutating
引用类型(如class)特点如下:
Stored in the heap and reference counted(automatically)
Constant Pointers to a class (
let
) still can mutate by calling methods and changing propertiesWhen passed as an argument, does note make a copy (just passing a pointer to same instance)
参数名称
对于所有的方法而言所有的参数都有一个内部名称和外部名称,
内部名称是在方法内使用的局部变量
外部名称是调用者调用方法时使用的名称
如果不想让调用者使用外部名称,可以使用下划线忽略外部名称,
如果只提供了一个参数名,这个参数名即是外部名称又是外部名称
类型和方法都可以拥有方法和属性
类型的方法和属性都需要使用static关键词修饰
比如Double这个struct类型有一系列变量和方法在这个类型上
比如访问 Double.pi 访问的不是实例的属性而是类型的属性
属性观察
可以通过willSet和didSet来观察属性值的更改。
如果修改了一个结构体,也会包含这种变化
var someStoredProperty:Int = 42 {
willSet{newValue is the new value}
didSet{oleValue is the old value}
}
// 继承的属性也可以观察 重新父类的属性和方法都需要使用关键词override
override var inheritedProperty:String{
willSet{newValue is the new value}
didSet{oleValue is the old value}
}
// 架构体的变化也可以捕获
var opertaions:Dictionary<String,Operation>=[...]{
willSet{will be executed if an opreation is added/removed}
didSet {will be executed if an opreation is added/removed}
}
懒加载
使用lazy关键词修饰,这种变量只有在访问的时候才会初始化,可以通过执行闭包或者调用方法来创建一个对象
lazy var brain = CalulatorBrain()
lazy var someProperty:Type = {
// construct the value of someProperty
return <the constructed value>
}()
lazy var myProperty = self.initialiedMyProperty()
初始化
- 什么时候需要init方法
init方法不是非常常见,因为
- 属性可以使用=赋予默认值
- 属性也可以使用可选型,这种情况下初始值为nil
- 属性也可以使用懒加载
因此,当上述方面不能满足时,需要初始化方法。
- 有些初始化方法不用自己写就可以使用
- 基类的init()方法
- 如果结构体没有初始化方法,会有默认的初始化方法包含所有的参数
-
在init方法中需要做什么
当初始化完成之后,所有属性都应当有值(可选型可以为nil)
在class中有两种初始化方法 convenience and designated
- a designated init must (and can only) call a designated init that is in its immediate supercalss
- you must initialize all properties introduced by your calss before calling a supercalss' init
- You must call a supercalss' init before you assign a value to an inherited property
- a convenience init must ( and can only) call an init in its own class
- a convenience init must call that init before it can set any property values
-
可以失败的初始化
如果init声明为init?,它将返回一个可选型,初始化失败时为nil
比如
let image = UIImage(named:"foo")// image is an Optional
类型转换
可以使用as?来进行类型转换,尤其在有使用到Any类型,以及父类像子类转换时很常见
断言
可以使用assert在调试时帮助调试,
assert(()->Bool,"message") 这个函数的参数时自动闭包,所以不需要{}
条件为假时,给出后面的信息。
当编辑为release版本时,断言会完全被忽略。
网友评论