upload
This commit is contained in:
@ -1,7 +1,6 @@
|
|||||||
> 翻译:[老码团队翻译组-Arya](http://weibo.com/littlekok/)
|
> 翻译:[老码团队翻译组-Arya](http://weibo.com/littlekok/)
|
||||||
> 校对:[老码团队翻译组-Oberyn](http://weibo.com/u/5241713117)
|
> 校对:[老码团队翻译组-Oberyn](http://weibo.com/u/5241713117)
|
||||||
|
|
||||||
|
|
||||||
# Access Control 权限控制的黑与白
|
# Access Control 权限控制的黑与白
|
||||||
|
|
||||||
如果您之前没有接触过权限控制,先来听一个小故事:
|
如果您之前没有接触过权限控制,先来听一个小故事:
|
||||||
@ -41,7 +40,7 @@ Private(私有级别)的权限最严格,它可以用来隐藏某些功能
|
|||||||
除了可以给整个声明设权限,Swift还允许大家在需要的时候,把某个属性(property)的取值权限比赋值权限设得更加开放。
|
除了可以给整个声明设权限,Swift还允许大家在需要的时候,把某个属性(property)的取值权限比赋值权限设得更加开放。
|
||||||
|
|
||||||
#####举个例子:
|
#####举个例子:
|
||||||
|
```swift
|
||||||
public class ListItem {
|
public class ListItem {
|
||||||
|
|
||||||
// ListItem这个类,有两个公开的属性
|
// ListItem这个类,有两个公开的属性
|
||||||
@ -69,7 +68,7 @@ Private(私有级别)的权限最严格,它可以用来隐藏某些功能
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
当我们使用Objective-C和Swift混合开发时,需要注意:
|
当我们使用Objective-C和Swift混合开发时,需要注意:
|
||||||
|
|
||||||
@ -82,7 +81,4 @@ Private(私有级别)的权限最严格,它可以用来隐藏某些功能
|
|||||||
如果您想了解更多关于权限控制的内容,可以查看苹果官方最新的《The Swift Language》和《Using Swift with Cocoa and Objective-C》指南,
|
如果您想了解更多关于权限控制的内容,可以查看苹果官方最新的《The Swift Language》和《Using Swift with Cocoa and Objective-C》指南,
|
||||||
这两本指南在iBooks里面可以下载更新喔。
|
这两本指南在iBooks里面可以下载更新喔。
|
||||||
|
|
||||||
-----------------
|
本文由翻译自Apple Swift Blog :https://developer.apple.com/swift/blog/?id=5
|
||||||
本章节不是老码的原创,老码认真的阅读了苹果的官方博客,且自己的练习总结,如果小伙伴们费了吃奶的劲还是看不懂,请找度娘谷歌,还是看不懂请到老码[官方微博](http://weibo.com/u/5241713117)咆哮。
|
|
||||||
|
|
||||||
##### 本文由翻译自Apple Swift Blog :[Access Control](https://developer.apple.com/swift/blog/?id=5)
|
|
||||||
|
|||||||
@ -21,10 +21,12 @@
|
|||||||
来我们先看一下OCBool的定义。
|
来我们先看一下OCBool的定义。
|
||||||
|
|
||||||
#####代码示例如下:
|
#####代码示例如下:
|
||||||
1. enum OCBool{
|
```swift
|
||||||
2. case ocTrue
|
enum OCBool{
|
||||||
3. case ocFalse
|
case ocTrue
|
||||||
4. }
|
case ocFalse
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
#####注意:
|
#####注意:
|
||||||
|
|
||||||
@ -34,12 +36,13 @@
|
|||||||
<a name="imp-default"></a>
|
<a name="imp-default"></a>
|
||||||
####实现默认值
|
####实现默认值
|
||||||
行,我们给了一个漂亮的定义,不过按照传统语言的经验,Bool值默认情况下是假, 所以我们的OCBool也应该如此,我们使用类型扩展技术增加这个默认特性:
|
行,我们给了一个漂亮的定义,不过按照传统语言的经验,Bool值默认情况下是假, 所以我们的OCBool也应该如此,我们使用类型扩展技术增加这个默认特性:
|
||||||
|
```swift
|
||||||
1. extension OCBool{
|
extension OCBool{
|
||||||
2. init(){
|
init(){
|
||||||
3. self =.ocFalse
|
self =.ocFalse
|
||||||
4. }
|
}
|
||||||
5. }
|
}
|
||||||
|
```
|
||||||
|
|
||||||
#####注意:
|
#####注意:
|
||||||
- 代码中第1行:extension关键字,非常强大,小伙伴们可以通过此创造出许多好玩的东西,建议各位去Github上看一个名为“Swiftz”的项目,它将扩展用到了极致。
|
- 代码中第1行:extension关键字,非常强大,小伙伴们可以通过此创造出许多好玩的东西,建议各位去Github上看一个名为“Swiftz”的项目,它将扩展用到了极致。
|
||||||
@ -47,50 +50,55 @@
|
|||||||
现在我们可以使用如下方法使用这个Bool类型。
|
现在我们可以使用如下方法使用这个Bool类型。
|
||||||
|
|
||||||
#####代码示例如下:
|
#####代码示例如下:
|
||||||
|
```swift
|
||||||
1. var result:OCBool = OCBool()
|
var result:OCBool = OCBool()
|
||||||
2. var result1:OCBool = .ocTrue
|
var result1:OCBool = .ocTrue
|
||||||
|
```
|
||||||
|
|
||||||
<a name="init-by-bool"></a>
|
<a name="init-by-bool"></a>
|
||||||
####支持基本布尔型初始化
|
####支持基本布尔型初始化
|
||||||
正如上述代码所述,我们只能通过类型或者枚举项目赋值,这是组合类型的用法,但是编码的日子里,我们总是希望和true,false直接打交道,也就是说,我们希望这么做,
|
正如上述代码所述,我们只能通过类型或者枚举项目赋值,这是组合类型的用法,但是编码的日子里,我们总是希望和true,false直接打交道,也就是说,我们希望这么做,
|
||||||
代码示例如下:
|
代码示例如下:
|
||||||
|
```swift
|
||||||
1. var isSuccess:OCBool = true
|
var isSuccess:OCBool = true
|
||||||
|
```
|
||||||
|
|
||||||
如果小伙伴们直接这么用,则会出现如下错误:
|
如果小伙伴们直接这么用,则会出现如下错误:
|
||||||
|
```
|
||||||
1. /Users/tyrion-OldCoder/Documents/Learning/BoolType/BoolType/main.swift:30:24: Type 'OCBool' does not conform to protocol 'BooleanLiteralConvertible'
|
/Users/tyrion-OldCoder/Documents/Learning/BoolType/BoolType/main.swift:30:24: Type 'OCBool' does not conform to protocol 'BooleanLiteralConvertible'
|
||||||
|
```
|
||||||
编译器咆哮的原因是,我们的类型没有遵从“布尔字面量转换协议”,接下来修正这个问题,
|
编译器咆哮的原因是,我们的类型没有遵从“布尔字面量转换协议”,接下来修正这个问题,
|
||||||
#####代码示例如下:
|
#####代码示例如下:
|
||||||
|
|
||||||
1. import Foundation
|
```swift
|
||||||
2.
|
import Foundation
|
||||||
3. println("Hello, World!")
|
|
||||||
4.
|
println("Hello, World!")
|
||||||
5. enum OCBool{
|
|
||||||
6. case ocTrue
|
enum OCBool{
|
||||||
7. case ocFalse
|
case ocTrue
|
||||||
8. }
|
case ocFalse
|
||||||
9.
|
}
|
||||||
10.
|
|
||||||
11. extension OCBool: BooleanLiteralConvertible{
|
|
||||||
12. static func convertFromBooleanLiteral( value: Bool) ->OCBool{
|
extension OCBool: BooleanLiteralConvertible{
|
||||||
13. return value ? ocTrue : ocFalse
|
static func convertFromBooleanLiteral( value: Bool) ->OCBool{
|
||||||
14. }
|
return value ? ocTrue : ocFalse
|
||||||
15. }
|
}
|
||||||
16.
|
}
|
||||||
17. var isSuccess:OCBool = true
|
|
||||||
|
var isSuccess:OCBool = true
|
||||||
|
```
|
||||||
|
|
||||||
#####注意:
|
#####注意:
|
||||||
- 代码中的第11行是重点,我的类型OCBool支持了BooleanLiteralConvertible协议,这个协到底是干什么的呢,小伙伴们在Xcode代码编辑器,按住Command键,然后点击第11行中的BooleanLiteralConvertible协议名,则会进入它的定义,
|
- 代码中的第11行是重点,我的类型OCBool支持了BooleanLiteralConvertible协议,这个协到底是干什么的呢,小伙伴们在Xcode代码编辑器,按住Command键,然后点击第11行中的BooleanLiteralConvertible协议名,则会进入它的定义,
|
||||||
#####其定义如下:
|
#####其定义如下:
|
||||||
|
```swift
|
||||||
1. protocol BooleanLiteralConvertible {
|
protocol BooleanLiteralConvertible {
|
||||||
2. typealias BooleanLiteralType
|
typealias BooleanLiteralType
|
||||||
3. class func convertFromBooleanLiteral(value: BooleanLiteralType) -> Self
|
class func convertFromBooleanLiteral(value: BooleanLiteralType) -> Self
|
||||||
4. }
|
}
|
||||||
|
```
|
||||||
|
|
||||||
- 这个定义中有个类方法convertFromBooleanLiteral,它的参数为BooleanLiteralType类型,也就是我传入的Bool类型, 且返回值为实现这个协议的类型本身,在我们的OCBool类型中,其返回值就是OCBool本身。经过这个定义,我们可以直接对OCBool类型直接进行布尔字面量初始化了。
|
- 这个定义中有个类方法convertFromBooleanLiteral,它的参数为BooleanLiteralType类型,也就是我传入的Bool类型, 且返回值为实现这个协议的类型本身,在我们的OCBool类型中,其返回值就是OCBool本身。经过这个定义,我们可以直接对OCBool类型直接进行布尔字面量初始化了。
|
||||||
|
|
||||||
@ -98,64 +106,66 @@
|
|||||||
####支持Bool类型判断
|
####支持Bool类型判断
|
||||||
小伙伴们不安分, 肯定想着我怎么用它实现逻辑判断,所以如果你这么写,
|
小伙伴们不安分, 肯定想着我怎么用它实现逻辑判断,所以如果你这么写,
|
||||||
#####代码示例如下:
|
#####代码示例如下:
|
||||||
|
```swift
|
||||||
|
var isSuccess:OCBool = true
|
||||||
|
|
||||||
1. var isSuccess:OCBool = true
|
if isSuccess {
|
||||||
2.
|
println( "老码请你吃火锅!")
|
||||||
3. if isSuccess {
|
}
|
||||||
4. println( "老码请你吃火锅!")
|
```
|
||||||
5. }
|
|
||||||
|
|
||||||
你永远吃不到老码的火锅,因为这里编译器会咆哮:
|
你永远吃不到老码的火锅,因为这里编译器会咆哮:
|
||||||
|
```
|
||||||
1. /Users/tyrion-OldCoder/Documents/Learning/BoolType/BoolType/main.swift:27:4: Type 'OCBool' does not conform to protocol 'LogicValue'
|
/Users/tyrion-OldCoder/Documents/Learning/BoolType/BoolType/main.swift:27:4: Type 'OCBool' does not conform to protocol 'LogicValue'
|
||||||
|
```
|
||||||
OCBool现在只能用bool类型初始化,而不能直接返回bool型,小火把们还记得在《老码说编程之白话Swift江湖》中,老码多次提到,妈妈再也不担心我们 if a = 1{}的写法了, 因为等号不支持值返回了, 所以在if判断是后面的条件必须有返回值,OCBool没有,所以编译器哭了。我们解决这个问题。
|
OCBool现在只能用bool类型初始化,而不能直接返回bool型,小火把们还记得在《老码说编程之白话Swift江湖》中,老码多次提到,妈妈再也不担心我们 if a = 1{}的写法了, 因为等号不支持值返回了, 所以在if判断是后面的条件必须有返回值,OCBool没有,所以编译器哭了。我们解决这个问题。
|
||||||
|
|
||||||
#####代码示例如下:
|
#####代码示例如下:
|
||||||
|
```swift
|
||||||
|
import Foundation
|
||||||
|
|
||||||
1. import Foundation
|
println("Hello, World!")
|
||||||
2.
|
|
||||||
3. println("Hello, World!")
|
enum OCBool{
|
||||||
4.
|
case ocTrue
|
||||||
5. enum OCBool{
|
case ocFalse
|
||||||
6. case ocTrue
|
}
|
||||||
7. case ocFalse
|
|
||||||
8. }
|
|
||||||
9.
|
extension OCBool: BooleanLiteralConvertible{
|
||||||
10.
|
static func convertFromBooleanLiteral( value: Bool) ->OCBool{
|
||||||
11. extension OCBool: BooleanLiteralConvertible{
|
return value ? ocTrue : ocFalse
|
||||||
12. static func convertFromBooleanLiteral( value: Bool) ->OCBool{
|
}
|
||||||
13. return value ? ocTrue : ocFalse
|
}
|
||||||
14. }
|
|
||||||
15. }
|
extension OCBool: LogicValue{
|
||||||
16.
|
func getLogicValue() ->Bool {
|
||||||
17. extension OCBool: LogicValue{
|
var boolValue: Bool{
|
||||||
18. func getLogicValue() ->Bool {
|
switch self{
|
||||||
19. var boolValue: Bool{
|
case .ocTrue:
|
||||||
20. switch self{
|
return true
|
||||||
21. case .ocTrue:
|
case .ocFalse:
|
||||||
22. return true
|
return false
|
||||||
23. case .ocFalse:
|
}
|
||||||
24. return false
|
}
|
||||||
25. }
|
return boolValue
|
||||||
26. }
|
}
|
||||||
27. return boolValue
|
}
|
||||||
28. }
|
|
||||||
29. }
|
|
||||||
30.
|
var isSuccess:OCBool = true
|
||||||
31.
|
|
||||||
32. var isSuccess:OCBool = true
|
if isSuccess {
|
||||||
33.
|
println( "老码请你吃火锅!")
|
||||||
34. if isSuccess {
|
}
|
||||||
35. println( "老码请你吃火锅!")
|
```
|
||||||
36. }
|
|
||||||
|
|
||||||
####运行结果如下:
|
####运行结果如下:
|
||||||
|
```
|
||||||
1. Hello, World!
|
Hello, World!
|
||||||
2. 老码请你吃火锅!
|
老码请你吃火锅!
|
||||||
3. Program ended with exit code: 0
|
Program ended with exit code: 0
|
||||||
|
```
|
||||||
#####注意:
|
#####注意:
|
||||||
- 如果小伙伴们现在用的是Beta版的Xcode,注意苹果官方Blog中,在代码第17行如果在Xcode Beta4下是错误的,这里的协议是,LogicValue而不是BooleanVue,所以记得看错误提示才是好习惯。
|
- 如果小伙伴们现在用的是Beta版的Xcode,注意苹果官方Blog中,在代码第17行如果在Xcode Beta4下是错误的,这里的协议是,LogicValue而不是BooleanVue,所以记得看错误提示才是好习惯。
|
||||||
- 注意代码第34行,完美支持if判断,且输出结果为“老码请你吃火锅”,老码也是说说而已,请不要当真。
|
- 注意代码第34行,完美支持if判断,且输出结果为“老码请你吃火锅”,老码也是说说而已,请不要当真。
|
||||||
@ -165,34 +175,35 @@ OCBool现在只能用bool类型初始化,而不能直接返回bool型,小火
|
|||||||
小伙伴们,江湖风险,门派众多,老码有自己的OCBool类型,可能嵩山少林有自己的SSBool类型,甚至连郭美美都可能有自己的MMBool类型,所以OCBool必须能够识别这些类型,这些各门各派的类型,只要支持LogicValue协议,就应该可以被识别,看老码怎么做,
|
小伙伴们,江湖风险,门派众多,老码有自己的OCBool类型,可能嵩山少林有自己的SSBool类型,甚至连郭美美都可能有自己的MMBool类型,所以OCBool必须能够识别这些类型,这些各门各派的类型,只要支持LogicValue协议,就应该可以被识别,看老码怎么做,
|
||||||
|
|
||||||
#####代码示例如下:
|
#####代码示例如下:
|
||||||
|
```swift
|
||||||
|
extension OCBool{
|
||||||
|
init( _ v: LogicValue )
|
||||||
|
{
|
||||||
|
if v.getLogicValue(){
|
||||||
|
self = .ocTrue
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
self = .ocFalse
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
1. extension OCBool{
|
}
|
||||||
2. init( _ v: LogicValue )
|
|
||||||
3. {
|
var mmResult: Bool = true
|
||||||
4. if v.getLogicValue(){
|
var ocResult:OCBool = OCBool(mmResult)
|
||||||
5. self = .ocTrue
|
|
||||||
6. }
|
|
||||||
7. else{
|
if ocResult {
|
||||||
8. self = .ocFalse
|
println( "老码没钱,郭美美请你吃火锅!")
|
||||||
9. }
|
}
|
||||||
10. }
|
```
|
||||||
11.
|
|
||||||
12. }
|
|
||||||
13.
|
|
||||||
14. var mmResult: Bool = true
|
|
||||||
15. var ocResult:OCBool = OCBool(mmResult)
|
|
||||||
16.
|
|
||||||
17.
|
|
||||||
18. if ocResult {
|
|
||||||
19. println( "老码没钱,郭美美请你吃火锅!")
|
|
||||||
20. }
|
|
||||||
|
|
||||||
#####代码运行结果如下:
|
#####代码运行结果如下:
|
||||||
|
```
|
||||||
1. Hello, World!
|
Hello, World!
|
||||||
2. 老码没钱,郭美美请你吃火锅!
|
老码没钱,郭美美请你吃火锅!
|
||||||
3. Program ended with exit code: 0
|
Program ended with exit code: 0
|
||||||
|
```
|
||||||
漂亮!我们的OCBool类型现在支持了所有的逻辑变量初始化。
|
漂亮!我们的OCBool类型现在支持了所有的逻辑变量初始化。
|
||||||
|
|
||||||
#####注意:
|
#####注意:
|
||||||
@ -202,73 +213,74 @@ OCBool现在只能用bool类型初始化,而不能直接返回bool型,小火
|
|||||||
####完善OCBool的布尔基因体系:
|
####完善OCBool的布尔基因体系:
|
||||||
小伙伴们,bool类型的价值就是在于各种判断,诸如==,!=, &,|,^,!,以及各种组合逻辑运算,我们OCBool也要具备这些功能,否则就会基因缺陷,且看老码如何实现:
|
小伙伴们,bool类型的价值就是在于各种判断,诸如==,!=, &,|,^,!,以及各种组合逻辑运算,我们OCBool也要具备这些功能,否则就会基因缺陷,且看老码如何实现:
|
||||||
|
|
||||||
1. extension OCBool: Equatable{
|
```swift
|
||||||
2. }
|
extension OCBool: Equatable{
|
||||||
3.
|
}
|
||||||
4. //支持等值判断运算符
|
|
||||||
5. func ==( left: OCBool, right: OCBool )->Bool{
|
|
||||||
6. switch (left, right){
|
|
||||||
7. case (.ocTrue, .ocTrue):
|
|
||||||
8. return true
|
|
||||||
9. default:
|
|
||||||
10. return false
|
|
||||||
11. }
|
|
||||||
12. }
|
|
||||||
13. //支持位与运算符
|
|
||||||
14. func &( left:OCBool, right: OCBool)->OCBool{
|
|
||||||
15.
|
|
||||||
16. if left{
|
|
||||||
17. return right
|
|
||||||
18. }
|
|
||||||
19. else{
|
|
||||||
20. return false
|
|
||||||
21. }
|
|
||||||
22. }
|
|
||||||
23. //支持位或运算符
|
|
||||||
24. func |( left:OCBool, right: OCBool)->OCBool{
|
|
||||||
25.
|
|
||||||
26. if left{
|
|
||||||
27. return true
|
|
||||||
28. }
|
|
||||||
29. else{
|
|
||||||
30. return right
|
|
||||||
31. }
|
|
||||||
32. }
|
|
||||||
33.
|
|
||||||
34. //支持位异或运算符
|
|
||||||
35. func ^( left:OCBool, right: OCBool)->OCBool{
|
|
||||||
36. return OCBool( left != right )
|
|
||||||
37. }
|
|
||||||
38. //支持求反运算符
|
|
||||||
39. @prefix func !( a:OCBool )-> OCBool{
|
|
||||||
40. return a ^ true
|
|
||||||
41. }
|
|
||||||
42. //支持组合求与运算符
|
|
||||||
43. func &= (inout left:OCBool, right:OCBool ){
|
|
||||||
44. left = left & right
|
|
||||||
45. }
|
|
||||||
46.
|
|
||||||
47.
|
|
||||||
48. var isHasMoney:OCBool = true
|
|
||||||
49. var isHasWife:OCBool = true
|
|
||||||
50. var isHasHealty:OCBool = true
|
|
||||||
51. var isHasLover:OCBool = true
|
|
||||||
52.
|
|
||||||
53. isHasMoney != isHasHealty
|
|
||||||
54. isHasHealty == isHasMoney
|
|
||||||
55. isHasWife ^ isHasLover
|
|
||||||
56. isHasWife = !isHasLover
|
|
||||||
57.
|
|
||||||
58. if (isHasMoney | isHasHealty) & isHasHealty{
|
|
||||||
59. println( "人生赢家,就像老码一样!")
|
|
||||||
60. }else
|
|
||||||
61. {
|
|
||||||
62. println("人生最苦的事事,人死了钱没花了,人生最苦的事是,人活着,钱没了!")
|
|
||||||
63. }
|
|
||||||
|
|
||||||
好了,到这里就到这里了,窗外的雷声叫醒了老码,现在应该去吃饭了,以上老码给大家展示了如果制造一个自己的类型,记得老码的示例是在Xcode6 Beta4下测试的,至于Beta5的改变还没有涉及,小伙伴们要好生练习,以后各种自定类型都是基于这个思想。
|
//支持等值判断运算符
|
||||||
|
func ==( left: OCBool, right: OCBool )->Bool{
|
||||||
|
switch (left, right){
|
||||||
|
case (.ocTrue, .ocTrue):
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//支持位与运算符
|
||||||
|
func &( left:OCBool, right: OCBool)->OCBool{
|
||||||
|
|
||||||
-----------------
|
if left{
|
||||||
本章节不是老码的原创,老码认真的阅读了苹果的官方博客,且自己的练习总结,如果小伙伴们费了吃奶的劲还是看不懂,请找度娘谷歌,还是看不懂请到老码[官方微博](http://weibo.com/u/5241713117)咆哮。
|
return right
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//支持位或运算符
|
||||||
|
func |( left:OCBool, right: OCBool)->OCBool{
|
||||||
|
|
||||||
##### 本文由翻译自Apple Swift Blog :[Bool](https://developer.apple.com/swift/blog/?id=8)
|
if left{
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return right
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//支持位异或运算符
|
||||||
|
func ^( left:OCBool, right: OCBool)->OCBool{
|
||||||
|
return OCBool( left != right )
|
||||||
|
}
|
||||||
|
//支持求反运算符
|
||||||
|
@prefix func !( a:OCBool )-> OCBool{
|
||||||
|
return a ^ true
|
||||||
|
}
|
||||||
|
//支持组合求与运算符
|
||||||
|
func &= (inout left:OCBool, right:OCBool ){
|
||||||
|
left = left & right
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var isHasMoney:OCBool = true
|
||||||
|
var isHasWife:OCBool = true
|
||||||
|
var isHasHealty:OCBool = true
|
||||||
|
var isHasLover:OCBool = true
|
||||||
|
|
||||||
|
isHasMoney != isHasHealty
|
||||||
|
isHasHealty == isHasMoney
|
||||||
|
isHasWife ^ isHasLover
|
||||||
|
isHasWife = !isHasLover
|
||||||
|
|
||||||
|
if (isHasMoney | isHasHealty) & isHasHealty{
|
||||||
|
println( "人生赢家,就像老码一样!")
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
println("人生最苦的事事,人死了钱没花了,人生最苦的事是,人活着,钱没了!")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
好了,到这里就到这里了,窗外的雷声叫醒了老码,现在应该去吃饭了,以上老码给大家展示了如果制造一个自己的类型,记得老码的示例是在Xcode6 Beta4下测试的,至于Beta5的改变还没有涉及,小伙伴们要好生练习,以后各种自定类型都是基于这个思想。还有这个章节不是老码的原创,老码认真的阅读了苹果的官方博客,且自己的练习总结,如果小伙伴们费了吃奶的劲还是看不懂,请找度娘谷歌,还是看不懂请到老码官方微博:http://weibo.com/u/5241713117咆哮。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
本文由翻译自Apple Swift Blog :https://developer.apple.com/swift/blog/?id=8
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
> 翻译:[老码团队翻译组-Arya](http://weibo.com/littlekok/)
|
> 翻译:[老码团队翻译组-Arya](http://weibo.com/littlekok/)
|
||||||
> 校对:[老码团队翻译组-Jame](http://weibo.com/u/5241713117)
|
> 校对:[老码团队翻译组-](Jame)
|
||||||
|
|
||||||
# WWDC里面的那个“大炮打气球”
|
# WWDC里面的那个“大炮打气球”
|
||||||
|
|
||||||
@ -15,8 +15,4 @@ Ballons不但展现了playgrounds许多很赞的特性,还让我们看到写
|
|||||||
这个playground文件用到了SpriteKit的新特性,因此需要最新beta版本的Xcode 6和Yosemite系统来支持它运行。
|
这个playground文件用到了SpriteKit的新特性,因此需要最新beta版本的Xcode 6和Yosemite系统来支持它运行。
|
||||||
|
|
||||||
|
|
||||||
-----------------
|
本文由翻译自Apple Swift Blog的博文:[Ballons](https://developer.apple.com/swift/blog/?id=9)
|
||||||
本章节不是老码的原创,老码认真的阅读了苹果的官方博客,且自己的练习总结,如果小伙伴们费了吃奶的劲还是看不懂,请找度娘谷歌,还是看不懂请到老码[官方微博](http://weibo.com/u/5241713117)咆哮。
|
|
||||||
|
|
||||||
##### 本文由翻译自Apple Swift Blog :[Balloons](https://developer.apple.com/swift/blog/?id=9)
|
|
||||||
|
|
||||||
|
|||||||
@ -13,77 +13,57 @@
|
|||||||
|
|
||||||
Objective-C和C的API常常会需要用到指针。Swift中的数据类型都原生支持基于指针的Cocoa API,不仅如此,Swift会自动处理部分最常用的将指针作为参数传递的情况。这篇文章中,我们将着眼于在Swift中让C语言指针与变量、数组和字符串共同工作。
|
Objective-C和C的API常常会需要用到指针。Swift中的数据类型都原生支持基于指针的Cocoa API,不仅如此,Swift会自动处理部分最常用的将指针作为参数传递的情况。这篇文章中,我们将着眼于在Swift中让C语言指针与变量、数组和字符串共同工作。
|
||||||
|
|
||||||
<a name="inout-para-pointer"></a>
|
|
||||||
####用以输入/输出的参数指针
|
####用以输入/输出的参数指针
|
||||||
|
|
||||||
C和Objective-C并不支持多返回值,所以Cocoa API中常常将指针作为一种在方法间传递额外数据的方式。Swift允许指针被当作`inout`参数使用,所以你可以用符号`&`将对一个变量的引用作为指针参数传递。举例来说:`UIColor`中的`getRed(_:green:blue:alpha:)`方法需要四个`CGFloat*`指针来接收颜色的组成信息,我们使用`&`来将这些组成信息捕获为本地变量:
|
C和Objective-C并不支持多返回值,所以Cocoa API中常常将指针作为一种在方法间传递额外数据的方式。Swift允许指针被当作`inout`参数使用,所以你可以用符号`&`将对一个变量的引用作为指针参数传递。举例来说:`UIColor`中的`getRed(_:green:blue:alpha:)`方法需要四个`CGFloat*`指针来接收颜色的组成信息,我们使用`&`来将这些组成信息捕获为本地变量:
|
||||||
|
```swift
|
||||||
####Swift代码
|
var r: CGFloat = 0, g: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 0
|
||||||
|
color.getRed(&r, green: &g, blue: &b, alpha: &a)
|
||||||
var r: CGFloat = 0, g: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 0
|
```
|
||||||
color.getRed(&r, green: &g, blue: &b, alpha: &a)
|
|
||||||
|
|
||||||
另一种常见的情况是Cocoa中`NSError`的习惯用法。许多方法会使用一个`NSError**`参数来储存可能的错误的信息。举例来说:我们用`NSFileManager`的`contentOfDirectoryAtPath(_:error:)`方法来将目录下的内容列表,并将潜在的错误指向一个`NSError?`变量:
|
另一种常见的情况是Cocoa中`NSError`的习惯用法。许多方法会使用一个`NSError**`参数来储存可能的错误的信息。举例来说:我们用`NSFileManager`的`contentOfDirectoryAtPath(_:error:)`方法来将目录下的内容列表,并将潜在的错误指向一个`NSError?`变量:
|
||||||
|
```swift
|
||||||
####Swift代码
|
var maybeError: NSError?
|
||||||
|
if let contents = NSFileManager.defaultManager()
|
||||||
var maybeError: NSError?
|
|
||||||
if let contents = NSFileManager.defaultManager()
|
|
||||||
.contentsOfDirectoryAtPath("/usr/bin", error: &maybeError) {
|
.contentsOfDirectoryAtPath("/usr/bin", error: &maybeError) {
|
||||||
// Work with the directory contents
|
// Work with the directory contents
|
||||||
} else if let error = maybeError {
|
} else if let error = maybeError {
|
||||||
// Handle the error
|
// Handle the error
|
||||||
}
|
}
|
||||||
|
```
|
||||||
为了安全性,Swift要求被使用`&`传递的变量已经初始化。因为无法确定这个方法会不会在写入数据前尝试从指针中读取数据。
|
为了安全性,Swift要求被使用`&`传递的变量已经初始化。因为无法确定这个方法会不会在写入数据前尝试从指针中读取数据。
|
||||||
|
|
||||||
<a name="array-as-para-pointer"></a>
|
|
||||||
####作为数组使用的参数指针
|
####作为数组使用的参数指针
|
||||||
|
|
||||||
在C语言中,数组和指针的联系十分紧密,而Swift允许数组能够作为指针使用,从而与基于数组的C语言API协同工作更加简单。一个固定的数组可以使用一个常量指针直接传递,一个变化的数组可以用`&`运算符将一个非常量指针传递。就和输入/输出参数指针一样。举例来说:我们可以用Accelerate框架中的`vDSP_vadd`方法让两个数组`a`和`b`相加,并将结果写入第三个数组`result`。
|
在C语言中,数组和指针的联系十分紧密,而Swift允许数组能够作为指针使用,从而与基于数组的C语言API协同工作更加简单。一个固定的数组可以使用一个常量指针直接传递,一个变化的数组可以用`&`运算符将一个非常量指针传递。就和输入/输出参数指针一样。举例来说:我们可以用Accelerate框架中的`vDSP_vadd`方法让两个数组`a`和`b`相加,并将结果写入第三个数组`result`。
|
||||||
|
```swift
|
||||||
|
import Accelerate
|
||||||
|
|
||||||
####Swift
|
let a: [Float] = [1, 2, 3, 4]
|
||||||
|
let b: [Float] = [0.5, 0.25, 0.125, 0.0625]
|
||||||
|
var result: [Float] = [0, 0, 0, 0]
|
||||||
|
|
||||||
import Accelerate
|
vDSP_vadd(a, 1, b, 1, &result, 1, 4)
|
||||||
|
|
||||||
let a: [Float] = [1, 2, 3, 4]
|
// result now contains [1.5, 2.25, 3.125, 4.0625]
|
||||||
let b: [Float] = [0.5, 0.25, 0.125, 0.0625]
|
```
|
||||||
var result: [Float] = [0, 0, 0, 0]
|
|
||||||
|
|
||||||
vDSP_vadd(a, 1, b, 1, &result, 1, 4)
|
|
||||||
|
|
||||||
// 结果包含[1.5, 2.25, 3.125, 4.0625]
|
|
||||||
|
|
||||||
<a name="string-as-para-pointer"></a>
|
|
||||||
####用作字符串参数的指针
|
|
||||||
|
|
||||||
|
#用作字符串参数的指针
|
||||||
C语言中用`cont char*`指针来作为传递字符串的基本方式。Swift中的`String`可以被当作一个无限长度UTF-8编码的`const char*`指针来传递给方法。举例来说:我们可以直接传递一个字符串给一个标准C和POSIX库方法
|
C语言中用`cont char*`指针来作为传递字符串的基本方式。Swift中的`String`可以被当作一个无限长度UTF-8编码的`const char*`指针来传递给方法。举例来说:我们可以直接传递一个字符串给一个标准C和POSIX库方法
|
||||||
|
```swift
|
||||||
|
puts("Hello from libc")
|
||||||
|
let fd = open("/tmp/scratch.txt", O_WRONLY|O_CREAT, 0o666)
|
||||||
|
|
||||||
####swift
|
if fd < 0 {
|
||||||
|
|
||||||
puts("Hello from libc")
|
|
||||||
let fd = open("/tmp/scratch.txt", O_WRONLY|O_CREAT, 0o666)
|
|
||||||
|
|
||||||
if fd < 0 {
|
|
||||||
perror("could not open /tmp/scratch.txt")
|
perror("could not open /tmp/scratch.txt")
|
||||||
} else {
|
} else {
|
||||||
let text = "Hello World"
|
let text = "Hello World"
|
||||||
write(fd, text, strlen(text))
|
write(fd, text, strlen(text))
|
||||||
close(fd)
|
close(fd)
|
||||||
}
|
}
|
||||||
|
```
|
||||||
<a name="security-of-pointer-cast"></a>
|
|
||||||
####指针参数转换的安全性
|
|
||||||
|
|
||||||
|
#指针参数转换的安全性
|
||||||
Swift很努力地使与C语言指针的交互更加便利,因为它们广泛地存在于Cocoa之中,同时保持一定的安全性。然而,相比你的其他Swift代码与C语言的指针交互具有潜在的不安全性,所以务必要小心使用。其中特别要注意:
|
Swift很努力地使与C语言指针的交互更加便利,因为它们广泛地存在于Cocoa之中,同时保持一定的安全性。然而,相比你的其他Swift代码与C语言的指针交互具有潜在的不安全性,所以务必要小心使用。其中特别要注意:
|
||||||
|
|
||||||
- 如果被调用者为了在其返回值之后再次使用而保存了C指针的数据,那么这些转换使用起来并不安全。转换后的指针仅在调用期间保证有效。甚至你将同样的变量、数组或字符串作为多指针参数再次传递,你每次都会收到一个不同的指针。这个异常将全局或静态地储存为变量。你可以安全地将这段地址当作永久唯一的指针使用。例如:作为一个KVO上下文参数使用的时候。
|
- 如果被调用者为了在其返回值之后再次使用而保存了C指针的数据,那么这些转换使用起来并不安全。转换后的指针仅在调用期间保证有效。甚至你将同样的变量、数组或字符串作为多指针参数再次传递,你每次都会收到一个不同的指针。这个异常将全局或静态地储存为变量。你可以安全地将这段地址当作永久唯一的指针使用。例如:作为一个KVO上下文参数使用的时候。
|
||||||
|
|
||||||
- 当指针类型为`Array`或`String`时,溢出检查不是强制进行的。 基于C语言的API无法增加数组和字符串大小,所以在你将其传递到基于C语言的API之前,你必须确保数组或字符的大小正确。
|
- 当指针类型为`Array`或`String`时,溢出检查不是强制进行的。 基于C语言的API无法增加数组和字符串大小,所以在你将其传递到基于C语言的API之前,你必须确保数组或字符的大小正确。
|
||||||
|
|
||||||
如果你需要使用基于指针的API时没有遵守以上指导,或是你重写了接受指针参数的Cocoa方法,于是你可以在Swift中直接用不安全的指针来使用未经处理的内存。在未来的文章中我们将着眼于更加高级的情况。
|
如果你需要使用基于指针的API时没有遵守以上指导,或是你重写了接受指针参数的Cocoa方法,于是你可以在Swift中直接用不安全的指针来使用未经处理的内存。在未来的文章中我们将着眼于更加高级的情况。
|
||||||
|
|
||||||
-----------------
|
|
||||||
本章节不是老码的原创,老码认真的阅读了苹果的官方博客,且自己的练习总结,如果小伙伴们费了吃奶的劲还是看不懂,请找度娘谷歌,还是看不懂请到老码[官方微博](http://weibo.com/u/5241713117)咆哮。
|
|
||||||
|
|
||||||
##### 本文由翻译自Apple Swift Blog :[Interacting with C Pointers](https://developer.apple.com/swift/blog/?id=6)
|
|
||||||
@ -23,25 +23,27 @@
|
|||||||
|
|
||||||
值类型和引用类型最基本的分别在复制之后的结果。当一个值类型被复制的时候,相当于创造了一个完全独立的实例,这个实例保有属于自己的独有数据,数据不会受到其他实例的数据变化影响:
|
值类型和引用类型最基本的分别在复制之后的结果。当一个值类型被复制的时候,相当于创造了一个完全独立的实例,这个实例保有属于自己的独有数据,数据不会受到其他实例的数据变化影响:
|
||||||
|
|
||||||
|
```swift
|
||||||
// 下面是一个值类型的例子
|
// 下面是一个值类型的例子
|
||||||
struct S { var data: Int = -1 }
|
struct S { var data: Int = -1 }
|
||||||
var a = S()
|
var a = S()
|
||||||
var b = a // b是a的拷贝
|
var b = a // b是a的拷贝
|
||||||
a.data = 42 // 更改a的数据,b的不受影响
|
a.data = 42 // 更改a的数据,b的不受影响
|
||||||
println("\(a.data), \(b.data)") // 输出结果 "42, -1"
|
println("\(a.data), \(b.data)") // 输出结果 "42, -1"
|
||||||
|
```
|
||||||
|
|
||||||
值类型就好像身份证复印件一样,复印出来之后,修改原件上面的内容,复印件上的内容不会变。
|
值类型就好像身份证复印件一样,复印出来之后,修改原件上面的内容,复印件上的内容不会变。
|
||||||
|
|
||||||
另一方面,复制一个引用类型的时候,实际上是默默地创造了一个共享的实例分身,两者是共用一套数据。因此修改其中任何一个实例的数据,也会影响到另外那个。
|
另一方面,复制一个引用类型的时候,实际上是默默地创造了一个共享的实例分身,两者是共用一套数据。因此修改其中任何一个实例的数据,也会影响到另外那个。
|
||||||
|
|
||||||
|
```swift
|
||||||
// 下面是一个引用类型的例子
|
// 下面是一个引用类型的例子
|
||||||
class C { var data: Int = -1 }
|
class C { var data: Int = -1 }
|
||||||
var x = C()
|
var x = C()
|
||||||
var y = x // y是x的拷贝
|
var y = x // y是x的拷贝
|
||||||
x.data = 42 // 更改x的数据,等于同时修改了y
|
x.data = 42 // 更改x的数据,等于同时修改了y
|
||||||
println("\(x.data), \(y.data)") // 输出结果 "42, 42"
|
println("\(x.data), \(y.data)") // 输出结果 "42, 42"
|
||||||
|
```
|
||||||
|
|
||||||
<a name="act-in=mutation"></a>
|
<a name="act-in=mutation"></a>
|
||||||
#### Mutation(修改)在安全中扮演的角色
|
#### Mutation(修改)在安全中扮演的角色
|
||||||
@ -72,3 +74,4 @@
|
|||||||
本章节不是老码的原创,老码认真的阅读了苹果的官方博客,且自己的练习总结,如果小伙伴们费了吃奶的劲还是看不懂,请找度娘谷歌,还是看不懂请到老码[官方微博](http://weibo.com/u/5241713117)咆哮。
|
本章节不是老码的原创,老码认真的阅读了苹果的官方博客,且自己的练习总结,如果小伙伴们费了吃奶的劲还是看不懂,请找度娘谷歌,还是看不懂请到老码[官方微博](http://weibo.com/u/5241713117)咆哮。
|
||||||
|
|
||||||
##### 本文由翻译自Apple Swift Blog :[Value and Reference Types](https://developer.apple.com/swift/blog/?id=10)
|
##### 本文由翻译自Apple Swift Blog :[Value and Reference Types](https://developer.apple.com/swift/blog/?id=10)
|
||||||
|
|
||||||
|
|||||||
@ -31,7 +31,7 @@ Swift支持了访问控制后,大家给我们的反馈都很不错。而有的
|
|||||||
Swift的访问控制等级和继承无关,是单维度、非常清楚明了的。我们认为这样的模式更简洁,同时满足了最主要的需求:将一个类、或一个框架的实现细节隔离保护起来。这可能和你以前用过的不同,但我们鼓励你试试看。
|
Swift的访问控制等级和继承无关,是单维度、非常清楚明了的。我们认为这样的模式更简洁,同时满足了最主要的需求:将一个类、或一个框架的实现细节隔离保护起来。这可能和你以前用过的不同,但我们鼓励你试试看。
|
||||||
|
|
||||||
-----------------
|
-----------------
|
||||||
本章节不是老码的原创,老码认真的阅读了苹果的官方博客,且自己的练习总结,如果小伙伴们费了吃奶的劲还是看不懂,请找度娘谷歌,还是看不懂请到老码[官方微博](http://weibo.com/u/5241713117)咆哮。
|
本章节不是老码的原创,是老码认真的阅读了苹果的官方博客,自己的练习总结,如果小伙伴们费了吃奶的劲还是看不懂,请找度娘谷歌。还是看不懂?请到老码[官方微博](http://weibo.com/u/5241713117)咆哮。
|
||||||
|
|
||||||
##### 本文由翻译自Apple Swift Blog :[Access Control and Protected](原文地址:https://developer.apple.com/swift/blog/?id=11)
|
##### 本文由翻译自Apple Swift Blog :[Access Control and Protected](原文地址:https://developer.apple.com/swift/blog/?id=11)
|
||||||
|
|
||||||
|
|||||||
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
在Swift中,```Dictionary```类没有类似```objectsForKeys```的函数,为了说明问题,我们动手加一个,并且使其成为操作字典值的通用方法。我们可以用```extension```来实现:
|
在Swift中,```Dictionary```类没有类似```objectsForKeys```的函数,为了说明问题,我们动手加一个,并且使其成为操作字典值的通用方法。我们可以用```extension```来实现:
|
||||||
|
|
||||||
```
|
```swift
|
||||||
extension Dictionary{
|
extension Dictionary{
|
||||||
func valuesForKeys(keys:[K], notFoundMarker: V )->[V]{
|
func valuesForKeys(keys:[K], notFoundMarker: V )->[V]{
|
||||||
//具体实现代码后面会写到
|
//具体实现代码后面会写到
|
||||||
@ -32,7 +32,7 @@ extension Dictionary{
|
|||||||
以上就是我们实现的Swift版本,这个和Objective-C版本有很大区别。在Swift中,因为其强类型的原因限制了返回的结果数组只能包含单一类型的元素,所以我们不能放```NSNull```在字符串数组中,但是,Swift有更好的选择,我们可以返回一个可选类型数据。我们所有的值都封包在可选类型中,而不是```NSNull```, 我们只用```nil```就可以了。
|
以上就是我们实现的Swift版本,这个和Objective-C版本有很大区别。在Swift中,因为其强类型的原因限制了返回的结果数组只能包含单一类型的元素,所以我们不能放```NSNull```在字符串数组中,但是,Swift有更好的选择,我们可以返回一个可选类型数据。我们所有的值都封包在可选类型中,而不是```NSNull```, 我们只用```nil```就可以了。
|
||||||
|
|
||||||
|
|
||||||
```
|
```swift
|
||||||
extension Dictionary{
|
extension Dictionary{
|
||||||
func valuesForKeys(keys: [Key]) -> [Value?] {
|
func valuesForKeys(keys: [Key]) -> [Value?] {
|
||||||
var result = [Value?]()
|
var result = [Value?]()
|
||||||
@ -50,7 +50,7 @@ extension Dictionary{
|
|||||||
|
|
||||||
小伙伴们可能会问,为什么Swift中不需要实现这么一个API呢?其实其有更简单的实现,如下面代码所示:
|
小伙伴们可能会问,为什么Swift中不需要实现这么一个API呢?其实其有更简单的实现,如下面代码所示:
|
||||||
|
|
||||||
```
|
```swift
|
||||||
extension Dictionary {
|
extension Dictionary {
|
||||||
func valuesForKeys(keys: [Key]) -> [Value?] {
|
func valuesForKeys(keys: [Key]) -> [Value?] {
|
||||||
return keys.map { self[$0] }
|
return keys.map { self[$0] }
|
||||||
@ -62,7 +62,7 @@ extension Dictionary {
|
|||||||
|
|
||||||
接下来,我们实验几个例子:
|
接下来,我们实验几个例子:
|
||||||
|
|
||||||
```
|
```swift
|
||||||
var dic: Dictionary = [ "1": 2, "3":3, "4":5 ]
|
var dic: Dictionary = [ "1": 2, "3":3, "4":5 ]
|
||||||
|
|
||||||
var t = dic.valuesForKeys(["1", "4"])
|
var t = dic.valuesForKeys(["1", "4"])
|
||||||
@ -80,7 +80,7 @@ t = dic.valuesForKeys([])
|
|||||||
|
|
||||||
现在,如果我们为每一个结果调用```last```方法,看下结果如何?
|
现在,如果我们为每一个结果调用```last```方法,看下结果如何?
|
||||||
|
|
||||||
```
|
```swift
|
||||||
var dic: Dictionary = [ "1": 2, "3":3, "4":5 ]
|
var dic: Dictionary = [ "1": 2, "3":3, "4":5 ]
|
||||||
|
|
||||||
var t = dic.valuesForKeys(["1", "4"]).last //结果为:Optional(Optional(5))
|
var t = dic.valuesForKeys(["1", "4"]).last //结果为:Optional(Optional(5))
|
||||||
@ -98,7 +98,7 @@ var t = dict.valuesForKeys([]).last
|
|||||||
|
|
||||||
我们回过头看看```last```属性的定义:
|
我们回过头看看```last```属性的定义:
|
||||||
|
|
||||||
```
|
```swift
|
||||||
var last:T? { get }
|
var last:T? { get }
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -106,7 +106,7 @@ var last:T? { get }
|
|||||||
|
|
||||||
如果在Objective-C中重新调用上述方法,我们将使用```NSNull```作为占位符,Objective-C的调用语法如下所示:
|
如果在Objective-C中重新调用上述方法,我们将使用```NSNull```作为占位符,Objective-C的调用语法如下所示:
|
||||||
|
|
||||||
```
|
```swift
|
||||||
[dict valuesForKeys:@[@"1", @"4"] notFoundMarker:[NSNull null]].lastObject
|
[dict valuesForKeys:@[@"1", @"4"] notFoundMarker:[NSNull null]].lastObject
|
||||||
// 5
|
// 5
|
||||||
[dict valuesForKeys:@[@"1", @"3"] notFoundMarker:[NSNull null]].lastObject
|
[dict valuesForKeys:@[@"1", @"3"] notFoundMarker:[NSNull null]].lastObject
|
||||||
@ -122,7 +122,7 @@ var last:T? { get }
|
|||||||
|
|
||||||
进一步封装,如果我字典中的某个或某些元素不存在,我们想提供一个默认值怎么办呢?实现方法很简单:
|
进一步封装,如果我字典中的某个或某些元素不存在,我们想提供一个默认值怎么办呢?实现方法很简单:
|
||||||
|
|
||||||
```
|
```swift
|
||||||
extension Dictionary {
|
extension Dictionary {
|
||||||
func valuesForKeys( keys:[Key], notFoundMarker: Value)->[Value]{
|
func valuesForKeys( keys:[Key], notFoundMarker: Value)->[Value]{
|
||||||
return self.valueForKeys(kes).map{ $0 ?? notFoundMarker }
|
return self.valueForKeys(kes).map{ $0 ?? notFoundMarker }
|
||||||
|
|||||||
Reference in New Issue
Block a user