我们经常将一个函数作为参数传入另一个函数。
那么在iOS上能作为一个函数参数的东西有哪些呢
- c的函数指针
- oc的block
- swift的闭包(closures)
ok回归正题,先说下@convention是干什么的。
他是用来修饰闭包的。他后面需要跟一个参数:
- @convention(swift) : 表明这个是一个swift的闭包
- @convention(block) :表明这个是一个兼容oc的block的闭包
- @convention(c) : 表明这个是兼容c的函数指针的闭包。
class Person:NSObject {
func doAction(action: @convention(swift) (String)->Void, arg:String){
action(arg)
}
}
let saySomething_c : @convention(c) (String)->Void = {
print("i said: \($0)")
}
let saySomething_oc : @convention(block) (String)->Void = {
print("i said: \($0)")
}
let saySomething_swift : @convention(swift) (String)->Void = {
print("i said: \($0)")
}
let person = Person()
person.doAction(action: saySomething_c, arg: "helloworld")
person.doAction(action: saySomething_oc, arg: "helloworld")
person.doAction(action: saySomething_swift, arg: "helloworld")
为啥今天要写这个呢?因为我在用runtime的imp_implementationWithBlock这个函数时不知道咋传参数。我用swift的闭包怎么都不对,看完@convention之后就知道该怎么办了。
class Person:NSObject {
//数 数字
dynamic func countNumber(toValue:Int){
for value in 0...toValue{
print(value)
}
}
}
//现在我们要替换数数函数的实现,给他之前和之后加上点广告语。
//拿到method
let methond = class_getInstanceMethod(Person.self, #selector(Person.countNumber(toValue:)))
//通过method拿到imp, imp实际上就是一个函数指针
let oldImp = method_getImplementation(methond!)
//由于IMP是函数指针,所以接收时需要指定@convention(c)
typealias Imp = @convention(c) (Person,Selector,NSNumber)->Void
//将函数指针强转为兼容函数指针的闭包
let oldImpBlock = unsafeBitCast(oldImp!, to: Imp.self)
//imp_implementationWithBlock的参数需要的是一个oc的block,所以需要指定convention(block)
let newFunc:@convention(block) (Person, NSNumber)->Void = {
(sself, toValue) in
print("数之前, 祝大家新年快乐")
oldImpBlock(sself, #selector(Person.countNumber(toValue:)), toValue)
print("数之后, 祝大家新年快乐")
}
let imp = imp_implementationWithBlock(unsafeBitCast(newFunc, to: AnyObject.self))
method_setImplementation(methond!, imp)
let person = Person()
person.countNumber(toValue: 50)
/**
输出将是
数之前, 祝大家新年快乐
0
1
3
。。。
。。。
49
50
数之后, 祝大家新年快乐
*/