枚举(Enumerations)
Swift的枚举比OC的多了很多内容, OC的枚举就2点:
- 普通枚举,不带类型(和c语言一样)
- 带类型枚举 (因为最开始OC出来的时候, c和C++语言还不支持带类型枚举,所以oc打了个补丁来支持这种特性)
普通枚举, 有好几种写法,详细见(http://blog.163.com/redhumor@126/blog/static/1955478420114333815940/)
typedef enum _TTGState {
TTGStateOK = 0,
TTGStateError,
TTGStateUnknow
} TTGState;
//指明枚举类型
TTGState state = TTGStateOK;
带类型枚举, 只支持2种类型,int和option, 所以如果swift的其它类型的enum是转换不到oc的。
//NS_ENUM,定义状态等普通枚举
typedef NS_ENUM(NSUInteger, TTGState) {
TTGStateOK = 0,
TTGStateError,
TTGStateUnknow
};
//NS_OPTIONS,定义选项
typedef NS_OPTIONS(NSUInteger, TTGDirection) {
TTGDirectionNone = 0,
TTGDirectionTop = 1 << 0,
TTGDirectionLeft = 1 << 1,
TTGDirectionRight = 1 << 2,
TTGDirectionBottom = 1 << 3
};
Lazy属性
Swift比oc多了一个lazy属性,简单来说,就是当访问到的时候才赋值:
class DataManager {
lazy var importer = DataImporter()
var data = [String]()
// 这里会提供数据管理功能
}
如果没有lazy,那么DataImporter在class DataManager初始化的时候就会赋值,但是有了lazy后,只有在importer被访问到的时候才会赋值。
但是,如果一个被标记为lazy的属性在没有初始化时就同时被多个线程访问,则无法保证该属性只会被初始化一次。
Closure vs Block
Swift 的Closure和OC的block很相似, 但是有些微不同。
打印结果是42, block其实是对值做了一个copy。
int anInteger = 42;
void (^testBlock)(void) = ^{
NSLog(@"Integer is: %i", anInteger);
};
anInteger = 84;
testBlock();
结果是2,closure是做了一个引用
var first = 1
let numberClosure = {
print("\(first)")
}
first = 2
numberClosure()
当oc用了__block 以后,就和swift一样了, 结果是84, 同样用了__block以后,在block里面可以更改变量的值,
__block int anInteger = 42;
void (^testBlock)(void) = ^{
NSLog(@"Integer is: %i", anInteger);
};
anInteger = 84;
testBlock();
如果block或者closure里面不是引用的值类型的变量的话,那么都是用强引用指向外部对象。 所以都有可能会产生循环引用。
那么是如何解决的呢?
OC是用__weak 关键字:
- (void)configureBlock {
XYZBlockKeeper * __weak weakSelf = self;
self.block = ^{
[weakSelf doSomething]; // capture the weak reference
// to avoid the reference cycle
}
}
Swift是用unowned或者weak关键字,如果修饰的对象是不会为nil的用unowned, 如果对象可能为nil用weak, 所以用weak修饰的对象应该是一个optional。[unowned self, weak delegate = self.delegate!] 就是所谓的capture list, 放在传入参数的前面。
lazy var someClosure: (Int, String) -> String = {
[unowned self, weak delegate = self.delegate!] (index: Int, stringToProcess: String) -> String in
// closure body goes here
}
如果没有传入参数:
lazy var someClosure: Void -> String = {
[unowned self, weak delegate = self.delegate!] in
// closure body goes here
}
Protocol
oc的协议里面可以是属性或者函数:
在.h 文件里面声明:
@protocol XYZPieChartViewDataSource
- (NSUInteger)numberOfSegments;
- (CGFloat)sizeOfSegmentAtIndex:(NSUInteger)segmentIndex;
- (NSString *)titleForSegmentAtIndex:(NSUInteger)segmentIndex;
@end
在.m 文件里面声明一个变量,conform这个协议:
@interface XYZPieChartView : UIView
@property (weak) id <XYZPieChartViewDataSource> dataSource;
...
@end
协议可以是optional的:
@protocol XYZPieChartViewDataSource
- (NSUInteger)numberOfSegments;
- (CGFloat)sizeOfSegmentAtIndex:(NSUInteger)segmentIndex;
@optional
- (NSString *)titleForSegmentAtIndex:(NSUInteger)segmentIndex;
@end
因为协议是optional的, 所以用的时候要用respondsToSelector检测:
NSString *thisSegmentTitle;
if ([self.dataSource respondsToSelector:@selector(titleForSegmentAtIndex:)]) {
thisSegmentTitle = [self.dataSource titleForSegmentAtIndex:index];
}
协议也可以继承于其它协议:
@protocol MyProtocol <NSObject>
...
@end
但是,如果想给协议里面的方法提供缺省实现,或者想给协议做一个扩展(category),都是不可以的,只有class才可以做这些。当然,可以下载第3方的库来实现这些功能。
但是值得高兴的是,Swift都是可以做的。
Swift的语法参考见这里
下面是一些比较特别的知识点:
协议要求声明属性到底是不是可读可写的, 协议总是用 var 关键字来声明变量属性,在类型声明后加上 { set get } 来表示属性是可读可写的,可读属性则用 { get } 来表示:
protocol SomeProtocol {
var mustBeSettable: Int { get set }
var doesNotNeedToBeSettable: Int { get }
}
如果要定义类类型的属性/方法,相当于OC里面的+, 用static关键字。
如果要在class(类)里面声明一个类属性,可以用static或者class关键字。
protocol AnotherProtocol {
static var someTypeProperty: Int { get set }
}
protocol SomeProtocol {
static func someTypeMethod()
}
结构struct也可以conform一个协议, 注意struct里面并没有写初始化方法,来对fullName初始化, 如果是class,是会报错的。
struct Person: FullyNamed {
var fullName: String
}
let john = Person(fullName: "John Appleseed")
如果协议里面的函数会更改当前实例的变量,如果当前的实例是struct或者enum,那么加mutating, 协议要加,当前的实例的声明中也要加。
protocol Togglable {
mutating func toggle()
}
enum OnOffSwitch: Togglable {
case Off, On
mutating func toggle() {
switch self {
case Off:
self = On
case On:
self = Off
}
}
}
协议可以要求conform它的实现者,实现初始化函数, 这个初始化函数可以是可失败构造器。init?(xxx)
protocol SomeProtocol {
init(someParameter: Int)
}
实现者要加require
class SomeClass: SomeProtocol {
required init(someParameter: Int) {
// 这里是构造器的实现部分
}
}
如果SomeClass继承于superClass,那么要加override
protocol SomeProtocol {
init()
}
class SomeSuperClass {
init() {
// 这里是构造器的实现部分
}
}
class SomeSubClass: SomeSuperClass, SomeProtocol {
// 因为采纳协议,需要加上 required
// 因为继承自父类,需要加上 override
required override init() {
// 这里是构造器的实现部分
}
}
协议可以像其他普通类型一样使用,使用场景如下:
- 作为函数、方法或构造器中的参数类型或返回值类型
- 作为常量、变量或属性的类型
- 作为数组、字典或其他容器中的元素类型
这就非常cool了,还有更有用的特性: 协议可以扩展:
protocol TextRepresentable {
var textualDescription: String { get }
}
extension TextRepresentable {
var textualDescription: String {
return "A sided dice"
}
}
上面的扩展实际上是协议的实现, 类可以conform TextRepresentable,可以直接使用textualDescription, 也可以重新对textualDescription赋值。用上面这种设计模式,就可以用组合的方式而不是继承的方式来实现框架。
而扩展也可以conform协议,这是我经常用的设计模式,这样代码更加清晰。比如: 当界面有一个textField组件的时候,都要写好几个delegete,这时候直接把他们写到扩展里面
extension SnakesAndLadders: PrettyTextRepresentable {
。。。。。。。
}
在扩展协议的时候,可以指定一些限制条件,例如,你可以扩展 CollectionType 协议,但是只适用于集合中的元素采纳了 TextRepresentable 协议的情况:
extension CollectionType where Generator.Element: TextRepresentable {
var textualDescription: String {
let itemsAsText = self.map { $0.textualDescription }
return "[" + itemsAsText.joinWithSeparator(", ") + "]"
}
}
可以限定协议只能被类(class)使用,用class关键字,这个特性觉得什么用处:
protocol SomeClassOnlyProtocol: class, SomeInheritedProtocol {
// 这里是类类型专属协议的定义部分
}
可以将2个协议合成一个变量用, 用
protocol Named {
var name: String { get }
}
protocol Aged {
var age: Int { get }
}
struct Person: Named, Aged {
var name: String
var age: Int
}
func wishHappyBirthday(celebrator: protocol<Named, Aged>) {
print("Happy birthday \(celebrator.name) - you're \(celebrator.age)!")
}
let birthdayPerson = Person(name: "Malcolm", age: 21)
wishHappyBirthday(birthdayPerson)
// 打印 “Happy birthday Malcolm - you're 21!”
wishHappyBirthday这个函数并不关心是哪一个对象调用它,它只关心对象是否遵循了
@objc protocol CounterDataSource {
optional func incrementForCount(count: Int) -> Int
optional var fixedIncrement: Int { get }
}
本文对比Swift和Objective-C在枚举、懒加载属性、闭包和协议方面的差异。Swift的枚举更丰富,支持更多类型;懒加载属性提供延迟初始化;闭包与OC的Block类似但有细微差别,Swift通过unowned或weak避免循环引用;协议方面,Swift允许更详细的声明和扩展,甚至可以为协议方法提供默认实现。
245

被折叠的 条评论
为什么被折叠?



