oc的block和Swift闭包相互调用
swift调用oc的block:
//oc
typedef void(^ResultBlock)(NSError *error);
@interface LGTest : NSObject
+ (void)testBlockCall:(ResultBlock)block;
@end
//swift
LGTest.testBlockCall{ error in
let errorcast = error as NSError
print(errorcast)
}
func test(_ block: ResultBlock){
let error = NSError.init(domain: NSURLErrorDomain, code: 400, userInf
block(error)
}
oc调用swift的闭包:
//swift
//注意类要继承自 NSobject,闭包前加 @objc 标识
class LGTeacher: NSObject{
@objc static var closure: (() -> ())?
}
+ (void)test{
LGTeacher.test{}
LGTeacher.closure = ^{
NSLog(@"end");
};
}
LGTest.test()
LGTeacher.closure = ^{
}
LGTeacher.closure!()
@convention
作用:用于修饰函数类型
- 修饰Swift中的函数类型(调用c函数的时候)
- 调用OC方法时,修饰swift函数类型
例子:
在c文件中定义一个c方法
//.h
int TesctCFUnction(int (callBack)(int a, int b));
//.cpp
int TesctCFUnction(int (callBack)(int a, int b)){
return callBack(10, 20);
}
在swift中调用:
let result = TesctCFUnction { (a: Int32, b: Int32) -> Int32 in
return a + b
}
print(result) //30
但是如果这么写,就会报错:
let closure = {(a: Int32, b: Int32) -> Int32 in
return a + b
}
let result = TesctCFUnction(closure);
所以这个时候,就需要用上@convention:
defer
定义:
defer {}里的代码会在当前代码块返回的时候执行,无论当前代码块是从哪个分支return 的,即使程序抛出错误,也会执行。如果多个 defer 语句出现在同一作用域中,则它们出现的顺序与它们执行的顺序相反,也就是先出现的后执行。
func f() {
defer { print("First defer") }
defer { print("Second defer") }
print("End of function")
}
f()
// 打印结果
// End of function
// Second defer
// First defer
闭包捕获引用类型
来个例子
class LGTeacher{
var age = 10
}
func test(){
var t = LGTeacher()
let clousre = {
t.age += 10
}
clousre()
}
编译成ll代码来看看
结论: 闭包捕获引用类型的时候,不需要先将对象捕获到堆区,因为对象已经在堆区了,所以它只需要对对象的引用地址进行传递就可以了。
闭包捕获多个值
来个例子:
func makeIncrementer(_ amount: Int) -> () -> Int {
var runningTotal = 10
func incrementer() -> Int {
runningTotal += amount
return runningTotal
}
return incrementer
}
我们把这个结构体用swift还原一下:
//数据结构 : 闭包的执行地址 + 捕获变量堆空间的地址
struct ClosureData<T>{
var ptr: UnsafeRawPointer
var capatureValue: UnsafePointer<T>
}
struct TowParamsClosureData<T1, T2>{
var object: HeapObject
var value1: UnsafePointer<T1> //第一个变量
var value2: T2 //第二个变量
}
struct HeapObject{
var metadata: UnsafeRawPointer
var refcount1: Int32
var refcount2: Int32
}
跑个demo验证一下:
struct NoMeanStruct{
var f: () -> Int
}
var f = NoMeanStruct(f: makeIncrementer(20))
let ptr = UnsafeMutablePointer<NoMeanStruct>.allocate(capacity: 1)
ptr.initialize(to: f)
let ctx = ptr.withMemoryRebound(to: ClosureData<TowParamsClosureData<Int, Int>>.self, capacity: 1){
$0.pointee
}
print(ctx.ptr) //0x00000001000052f0
print(ctx.capatureValue.pointee.value1) //0x000000010812aa30
print(ctx.capatureValue.pointee.value2) //20
print("end")
逃逸闭包
定义: 当闭包作为一个实际参数传递给一个函数的时候,并且是在函数返回之后调用,我们就说这个闭包逃逸了。当我们声明一个接受闭包作为形式参数的函数时,你可以在形式参数前写 @escaping 来明确闭包是允许逃逸的。
1、使用逃逸闭包的第一种情况:闭包作为值来存储
class CTTeacher{
var completionHandle: ((Int) -> Void)?
func makeIncrementer(_ amout: Int, handler : @escaping (Int) -> Void) {
var runningTool = 10
runningTool += amout
self.completionHandle = handler
}
func dosomething(){
self.makeIncrementer(10) {
print($0)
}
}
}
var t = CTTeacher()
t.dosomething()
t.completionHandle?(20)
2、使用逃逸闭包的第二种情况:异步执行闭包
class CTTeacher{
var completionHandle: ((Int) -> Void)?
func makeIncrementer(_ amout: Int, handler : @escaping (Int) -> Void) {
var runningTool = 10
runningTool += amout
DispatchQueue.global().asyncAfter(deadline: .now() + 0.1) {
handler(runningTool)
}
}
func dosomething(){
self.makeIncrementer(10) {
print($0)
}
}
}
逃逸闭包:
- 作为函数的参数传递
- 当前闭包在函数内部异步执行或者被存储
- 函数结束,闭包被调用,生命周期结束
非逃逸闭包:
- 不会产生循环引用,函数作用域内释放。
- 非逃逸闭包编译器会做更多的性能优化。
- 上下文的内存保存在栈上,而不是堆上。
一般都使用非逃逸闭包,万不得已才使用逃逸闭包。
自动闭包
是一种用来把实际参数传递给函数表达式打包的闭包,不接受任何实际参数,当其调用时,返回内部表达式的值。
好处:用普通表达式代替闭包的写法,语法糖的一种
来个例子:
func debugOutPrint(_ condition: Bool , _ message: @autoclosure () -> String){
if condition {
print("lg_debug:\(message())")
}
}
func dosomthing() -> String{
//耗时的操作
return "Application Error Occured"
}
//String, () -> String
// {} -> String
debugOutPrint(true, dosomthing) //相当于 {return dosomthing()}
debugOutPrint(true, dosomthing())
Swift多线程
1、实现多线程的手段
//1、Operation
let operation = BlockOperation{
print("operation任务")
}
operation.start() //开始任务
operation.cancel() //取消任务
//2、GCD
let workItem = DispatchWorkItem{
print("gcd任务")
}
workItem.perform() //开始任务
workItem.cancel() //取消任务
GCD轮流执行:
let workItem1 = DispatchWorkItem{
print("workItem1")
}
let workItem2 = DispatchWorkItem{
print("workItem2")
}
let workItem3 = DispatchWorkItem{
print("workItem3")
}
workItem1.notify(queue: .global(), execute: workItem2)
workItem2.notify(queue: .global(), execute: workItem3)
DispatchQueue.global().async(execute: workItem1)
/*
workItem1
workItem2
workItem3
*/