一. Swift
defer
在离开当前作用域之前, 执行
defer
内的代码. 如果有多个defer
的话, 由下往上, 由外往内执行.
func test { defer { print("second") defer { print("third") } } defer { print("first") }}复制代码
@testable
可测试性, 改变文件的访问级别, 如单元测试访问 Pods Project 中的模块时, 可以使用 @testable import Module 访问模块中 internal 级别的代码.
@testable import FooModule复制代码
@convention
修饰闭包, 使之满足不同场景的需求:
@convention(swift)
,@convention(block)
,@convention(c)
let methond = class_getInstanceMethod(Animal.self, #selector(Animal.eat(food:)))let imp = method_getImplementation(methond!)// ,使用 @convention(c) 来声明兼容 c 的闭包typealias Imp = @convention(c) (Animal, Selector, String) -> Void// 将原函数指针强转为带对应参数的指针let castImp = unsafeBitCast(imp, to: Imp.self)复制代码
class
修饰协议, 修饰后的协议只可被类遵守.
protocol Renderable: class {}复制代码
associatedtype
关联类型, 类似于类和结构体的反省, 但由于我们不会遵守一个
protocol\<A\>
, 又去遵守一个protocol\<B\>
协议, 所以在语义上区分开, 使用了关联类型.
protocol Renderable: class { associatedtype Shape func draw(with shape: Shape)}复制代码
fallthrough
用于 switch 中, 不同 case 的贯穿效果. 即上面的 case 执行完后, 如果有
fallthrough
修饰, 则继续执行下一个 case.
var age = 5switch age {case 0...5: print("baby") fallthroughcase 5..<18: print("teenager")case 18...100: print("adult")default: break}// log// baby// teenager复制代码
where
泛型约束
func eat(food: T) where T: Eatable {}复制代码
Self
在协议中用于指代遵守该协议的类. 如在协议扩展中, 使用
Self.self
输出类名.
protocol Eatable { var name: String { get }}extension Eatable { var name: String { return String(describing: Self.self) }}复制代码
Type
类类型: 作为方法声明的形参或属性的参数类型.
func test(type: UIView.Type) {}var test: UIView.Type = UIView.self复制代码
throw, throws
抛出一个异常, 可以使用
do-try-catch
捕获.
func sendMessage(_ message: String, to phone: Int) throws -> Void { guard message.count > 0 else { throw NSError(domain: "Illegal Message", code: 0, userInfo: nil) } // ...}复制代码
rethrows
抛出传入的闭包中的异常, 即传入的闭包抛出了异常, 则函数会重新将异常抛出到上一层.
func help(_ action: ((String, Int) throws -> Void)) rethrows -> Void { try action("", 110)}do { try help(self.sendMessage(_:to:)) }catch { // 接受到由 sendMessage throws-> help rethrows-> 的异常 print(error)}复制代码
operator
自定义操作符
prefix operator ++复制代码
prefix
用于自定义前置操作符声明, 或前置操作符方法的声明.
prefix operator ~+prefix func ~+ (good: String) -> String { return good + " Copyright © 2017 ABC"}复制代码
infix
自定义中置操作符
infix operator ~:AdditionPrecedencefunc ~ (left: String, right: String) -> String { return left + ":" + right}复制代码
postfix
自定义后置操作符
postfix operator ~-postfix func ~- (content: String) -> String { guard content.count > 2 else { return content } return content.substring(from: String.Index(encodedOffset: 2))}复制代码
asociativity, precedence
之前版本用于自定义操作符的结合性声明, 目前版本已无效, 使用
precedence group
.
infix operator ~:AdditionPrecedencefunc ~ (left: String, right: String) -> String { return left + " " + right}复制代码
left
之前版本用于自定义操作符的结合方向
right
之前版本用于自定义操作符的结合方向
convenience
便利构造器, 对自己的指定构造器的封装, 必须在实现内调用自己的指定构造器.
convenience init() { self.init(frame: CGRect.zero)}// 指定构造器override init(frame: CGRect) { super.init(frame: frame)}复制代码
dynamic
runtime 相关修饰符. 实际使用中需要多加留心.
- Objective-C 源项目中, 继承于 Objective-C 的 Swift 类将会全部注册到 runtime, 即所有的属性都会默认生成 setter 和 getter, 同时自定义的方法也会出现在 runtime 中.
- Swift 源项目中, 由于编译器偏向于将所有 Swift Class 优化为函数表派发(类比 C++的 vtable), 所以如果想在 Objective-C 代码中访问到属性或方法, 必须在 Swift 属性或方法前添加
dynamic
修饰, 注册到 runtime (仅仅由@objc
修饰的方法有可能会被编译器优化成函数表派发).
/// Objective-C 源项目class SomeClass { var name: String = "Scy" func test() {}}/// Swift 源项目中, 需要使用 dynamic 注册到 runtime, 才可以使用动态派发访问.class SomeClass { @objc dynamic var name: String = "Scy" @objc dynamic func test() {}}复制代码
indirect
枚举中的递归引用, 即在枚举中使用自身枚举类型.
indirect enum Animal { case Human(eat: Animal) case bird(eat: Worm)}struct Worm { var food = ["bugA", "bugB"]}复制代码
mutating
修饰方法, 用于在 Struct, Enum, Protocol 中用于改变自己的值. 需要注意的是在协议中的使用:
如果协议被结构体(枚举)实现, 且结构体需要改变自己的值, 则必须要在协议方法前添加
mutating
protocol Renameable { var name: String { set get } mutating func rename()}struct Dog: Renameable { var name: String func rename() { name = "happy" + name }}复制代码
nonmutating
修饰方法, 用于禁止 Struct, Enum, Protocol 中的方法改变自己的值, 不添加修饰符时的默认值.
protocol Renameable { var name: String { set get } nonmutating func rename()}复制代码
#available
修饰类或方法, 用于条件编译.
#colorLiteral
编码时, 使用这个关键字可以直接弹出自定义的颜色选择器.
#imageLiteral
编码时, 使用这个关键字可以直接弹出 assets 内的图片集选择器.
#column
同Objective-C 中的宏
__column__
, 输出当前列数.
#file
同Objective-C 中的宏
__file__
, 输出当前文件名.
#function
同Objective-C 中的宏
__function__
, 输出当前方法名.
#line
同Objective-C 中的宏
__line__
, 输出当前行数.
#sourceLocation
用于修改
#file
和#line
的值, 用于调试.
#sourceLocation(file: "DebugInfo", line: 100)// 此范围内的代码, 输出 #file = "DebugInfo", #line = 100#sourceLocation()// 恢复正常输出复制代码
二. Objective-C
__packed
可以使得变量或者结构体成员使用最小的对齐方式, 在 c 语言结构体中比较常用.
struct Person { int age;} __attribute__ ((__packed__));struct __packed Person;复制代码
goto
已经被历史所抛弃, 但是 Swift 使用
break
,continue
跳转语句部分实现了这个功能.
loop: if (n<200){ n++; goto loop;}复制代码
Nil
用于表示类对象为空, 同
nil
, 只是语义上的一个区分.
// Nil = nil = ((void *)0)Class FooClass = Nil;复制代码
voletile
直接存取原始内存地址, 忽略编译器优化. 防止在多线程时, 读取寄存器缓存, 造成数据不同步的错误.
void cFunction(volatile int *ptr) {}@interface FooClass : NSObject{ volatile int *_ptr;}@property (nonatomic) volatile int pointee;@end复制代码
assign/strong, readwrite, nonable, atomic
未添加修饰符时, 默认的修饰符.
@property NSString *name;复制代码
atomic
默认实现带
@synthesized(self)
的 setter 和 getter, 保证相对的线程安全, 因为通过直接访问实例变量还是会出现线程竞态. Swift 中的属性引入 Objective-C, 默认为nonatomic
.
@interface FooClass()@property (atomic) NSString *property;@end// 相当于为 setter 和 getter 添加了锁. 但是通过@impletation FooClass@synthesize property = _property;- (void)setProperty:(NSString *)property { @synchronized(self) { if (_property != property) { [_property release]; _property = [property retain]; } }}- (NSString *)property { @synchronized(self) { return _property; }}@end复制代码
nonable, nonnull
修饰
@property
, 与 Swift 同期出现的, 用于 Objective-C 编译期检测指针是否可为空, 并抛出一个 warning. 混编时对应 Swift 中的可选值和非可选值.事实上这些 null 相关的修饰主要用于桥接到 Swift, 在 Objective-C 中更多是为了约束编码者.
@property (nullable) NSString *firstName;@property (nonnull) NSString *lastName;复制代码
_Nullable, _Nonnull, __nonnull, __nullable
修饰参数和返回值, Objective-C 中用于约束参数传递, 错误时将抛出一个警告. 混编时对应 Swift 中的可选值和非可选值.
- (NSString *_Nullable)hello;- (NSString *_Nonnull)hi;复制代码
null_resetable
修饰@property, 值绝对不能为空, 但是 set 可以为空, 即[obj setProperty:nil] 是合法的, 只是需要重写 setter 方法, 处理空的情况.
@interface FooClass : NSObject@property (null_resettable) NSString *name;@end @impletation FooClass- (void)setName:(NSString *)name { if (name == nil) { // .... }}@end复制代码
null_unspecified
修饰
@property
, 用于提醒编码者该属性有可能为空. 在 Swift 中使用null_unspecified
修饰的属性时, 属性为 Swift 中的可选值.
@property (null_unspecified) NSString *name;复制代码
@synthesize
用于合成成员变量, setter 和 getter.
@implementation FooClass@synthesize property = _property;@end复制代码
@dynamic
编译时不自动生成成员变量, setter 和 getter. 如
CoreData
中的NSManagedObject
, 在运行时动态创建setter 和 getter,这就是所谓的动态绑定.
@implementation FooClass@dynamic property;@end复制代码
@available
编译指令, 一般用于版本约束.
if (@available(iOS 9, *)) { // code for iOS 9}复制代码
@encode
给定一个类型, 输出一位或多位的编码, 在方法签名时常用, 这里有.
@encode(type)复制代码
@package
访问权限修饰符, 分三种情况.
32bit compiler 下 为
@public
64bit 下, 同一个 framework 内为
@public
64bit 下, 不同 framework 为
@private
@interface NSURLResponse : NSObject{ @package NSURLResponseInternal *_internal;}复制代码