一. 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 = 5
switch age {
case 0...5:
print("baby")
fallthrough
case 5..<18:
print("teenager")
case 18...100:
print("adult")
default:
break
}
// log
// baby
// teenager
复制代码
where
泛型约束
func eat<T>(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 ~:AdditionPrecedence
func ~ (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 ~:AdditionPrecedence
func ~ (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 <NSSecureCoding, NSCopying>
{
@package
NSURLResponseInternal *_internal;
}
复制代码