@discardableResult
在Swift 2.x的时候,带返回的方法我们如果在调用的时候后面使用到返回的参数,编译器不会有任何的警告,想要编译器给出警告的话需要自己在方法前面添加属性 @warn_unused_result , 如
@warn_unused_result func doSomething() -> Bool {
return true
}
这时候调用这个方法没有使用返回参数的情况下编译器就会给出警告:
Result of call to ‘doSomething()’ is unused
到了 Swift 3.0 我们不需要这样写了,默认情况下编译器就是会去检查返回参数是否有被使用,没有的话就会给出警告。如果你不想要这个警告,可以自己手动加上 @discardableResult ,如:
@discardableResult func doSomething() -> Bool {
return true
}
@available
@available放在函数(方法),类或者协议前面。表明这些类型适用的平台和操作系统。看下面一个例子:
@available(iOS 9, *)
func myMethod() {
// do something
}
@available(iOS 9, *)
必须包含至少2个特性参数,其中iOS 9表示必须在 iOS 9 版本以上才可用。如果你部署的平台包括 iOS 8 , 在调用此方法后,编译器会报错。
另外一个特性参数:星号(*),表示包含了所有平台,目前有以下几个平台:
- iOS
- iOSApplicationExtension
- OSX
- OSXApplicationExtension
- watchOS
- watchOSApplicationExtension
- tvOS
- tvOSApplicationExtension
一般来讲,如果没有特殊的情况,都使用*表示全平台。
@available(iOS 9, *)
是一种简写形式。全写形式是@available(iOS, introduced=9.0)
。introduced=9.0
参数表示指定平台(iOS)从 9.0 开始引入该声明。为什么可以采用简写形式呢?当只有introduced这样一种参数时,就可以简写成以上简写形式。同理:@available(iOS 8.0, OSX 10.10, *)
这样也是可以的。表示同时在多个平台上(iOS 8.0 及其以上;OSX 10.10及其以上)的可用性。
另外,@available还有其他一些参数可以使用,分别是:
-
deprecated=版本号
:从指定平台某个版本开始过期该声明 -
obsoleted=版本号
:从指定平台某个版本开始废弃(注意弃用的区别,deprecated
是还可以继续使用,只不过是不推荐了,obsoleted
是调用就会编译错误)该声明 -
message=信息内容
:给出一些附加信息 -
unavailable
:指定平台上是无效的 -
renamed=新名字
:重命名声明
#available
#available
用在条件语句代码块中,判断不同的平台下,做不同的逻辑处理,比如:
if #available(iOS 8, *) {
// iOS 8 及其以上系统运行
}
guard #available(iOS 8, *) else {
return //iOS 8 以下系统就直接返回
}
访问权限
从高到低排序如下:open >public> interal > fileprivate >private
-
private
:所修饰的属性或者方法只能在当前类里访问 -
fileprivate
: fileprivate访问级别所修饰的属性或者方法在当前的Swift源文件里可以访问。 -
interal
: 默认访问级别,internal修饰符可写可不写)internal访问级别所修饰的属性或方法在源代码所在的整个模块都可以访问。如果是框架或者库代码,则在整个框架内部都可以访问,框架由外部代码所引用时,则不可以访问。internal可以省略,默认的访问限定就是internal。如果是App代码,也是在整个App代码,也是在整个App内部可以访问。 -
public
: 可以被任何人访问。但其他module中不可以被override和继承,而在module内可以被override和继承。 -
open
: 可以被任何人使用,包括override和继承。
常量、变量、属性、下标索引的Getters
和Setters
的访问级别继承自它们所属成员的访问级别。
Setter
的访问级别可以低于对应的Getter
的访问级别,这样就可以控制变量、属性或下标索引的读写权限。在var或subscript定义作用域之前,你可以通过private(set)
或internal(set)
先为它门的写权限申明一个较低的访问级别。
defer
这里defer
代码块会被压入栈中,函数结束时执行。到底啥时候执行呢?是在return
后执行,如果return
调用了其他函数,这个函数会在defer
代码块执行之前被执行。
static 和 class
在类型的定义属性时,只能使用static
,在定义类型的方法时,enum
,struct
只能用static
, 类里面可以使用static
,也可以使用class
inout
inout
在写法上与C语言传递地址的写法十分类似,在调用函数传入参数是带有前缀&,就好像取地址传进去了一样,实则不然。
Swift
中 struct
是值类型的。
何为值,值是不能改变的,是immutable
的,任何对值的修改其实就是新构造了一个来替换原来的。这里的inout
也是如此,并不是传了地址进来,而是在这里构造了一个新的结构体,当函数结束时会复制回去替换原来的结构体。
当然,这个复制并不一定会真的复制。Swift
的copy on write
也会分情况,当值类型的引用只有一个时是不会复制的,这段在猫神的书里有提到。
associatedtype
associatedtype用于protocol中 associatedtype类型是在protocol中代指一个确定类型并要求该类型实现指定方法
比如 我们定义一个protocol
protocol Container {
associatedtype ItemType
mutating func append(_ item:ItemType)
var count:Int {
get
}
subscript(i:Int) -> ItemType {
get
}
}
之后实现这个协议
truct IntStack: Container {
// original IntStack implementation
var items = [Int]()
mutating func push(_ item:Int) {
items.append(item)
}
mutating func pop() -> Int {
return items.removeLast()
}
// conformance to the Container protocol
typealias ItemType = Int
mutating func append(_ item:Int) {
self.push(item)
}
var count:Int {
return items.count
}
subscript(i:Int) -> Int {
return items[i]
}
}
其中items实现了ItemType这个代指变量
由于swift的类型推断,你实际上并不需要声明一个具体ItemType的Int作为定义的一部分IntStack。由于IntStack符合所有的要求Container协议,swift可以推断出适当的ItemType使用,只需通过查看类型append(_:)方法的item参数和标的返回类型。事实上,如果你删除typealias ItemType = Int上面从代码行,一切仍然有效,因为很明显应该使用什么类型ItemType。