iOS performSelector多参数传递解决方案以及objc_msgSend的使用注意事项

Objective-C与C语言关系解析:从语法到苹果开发生态 C语言作为编译型语言的代表,其语法结构和指针操作奠定了现代编程语言的基础。通过引入Smalltalk的消息传递机制,Objective-C在C语言之上构建了动态的面向对象模型,实现了运行时多态和动态绑定。这种设计使得Objective-C能够与C++代码混合编译,形成Objective-C++模式,为高性能计算和复用现有C++库提供了技术路径。在苹果开发生态中,这一技术价值体现在Cocoa框架的构建和Xcode工具链的深度整合上,使得开发者能够高效构建macOS和iOS应用。本文围绕C系语言谱系、Objec 阅读详情

iOS performSelector多参数传递解决方案


以及objc_msgSend的使用注意事项



iOS中使用performSelector:withObject:withObject:方法最多传递两个参数

    [self performSelectorOnMainThread:<#(nonnull SEL)#> withObject:<#(nullable id)#> waitUntilDone:<#(BOOL)#>]

解决方案:1. 使用NSInvocation进行消息转发从而实现对performSelector的多参数传递

               2. 使用runtime中的objc_msgSend进行消息的发送


方案一:

以下是对NSObject类的扩展方法:

NS_REQUIRES_NIL_TERMINATION:是对多参数传递值得一个宏

va_list args:定义一个指向个数可变的参数列表指针;

va_start(args,object):object为第一个参数,也就是最右边的已知参数,这里就是获取第一个可选参数的地址.使参数列表指针指向函数参数列表中的第一个可选参数,函数参数列表中参数在内存中的顺序与函数声明时的顺序是一致的。

va_arg(args,id):返回参数列表中指针所指的参数,返回类型为id,并使参数指针指向参数列表中下一个参数。

va_end(args):清空参数列表,并置参数指针args无效。

其他说明见代码注释

-(id)glt_performSelector:(SEL)selector withObject:(id)object,...NS_REQUIRES_NIL_TERMINATION;
{
    //根据类名以及SEL 获取方法签名的实例
    NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:selector];
    if (signature == nil) {
        NSLog(@"--- 使用实例方法调用 为nil ---");
        signature = [self methodSignatureForSelector:selector];
        if (signature == nil) {
            NSLog(@"使用类方法调用 也为nil, 此时return");
            return nil;
        }
    }
    //NSInvocation是一个消息调用类,它包含了所有OC消息的成分:target、selector、参数以及返回值。
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
    invocation.target = self;
    invocation.selector = selector;
    NSUInteger argCount = signature.numberOfArguments;
    // 参数必须从第2个索引开始,因为前两个已经被target和selector使用
    argCount = argCount > 2 ? argCount - 2 : 0;
    NSMutableArray *objs = [NSMutableArray arrayWithCapacity:0];
    if (object) {
        [objs addObject:object];
        va_list args;
        va_start(args, object);
        while ((object = va_arg(args, id))){
            [objs addObject:object];
        }
        va_end(args);
    }
    if (objs.count != argCount){
        NSLog(@"--- objs.count != argCount! please check it! ---");
        return nil;
    }
    //设置参数列表
    for (NSInteger i = 0; i < objs.count; i++) {
        id obj = objs[i];
        if ([obj isKindOfClass:[NSNull class]]) {
            continue;
        }
        [invocation setArgument:&obj atIndex:i+2];
    }
    [invocation invoke];
    //获取返回值
    id returnValue = nil;
    if (signature.methodReturnLength != 0 && signature.methodReturnLength) {
        [invocation getReturnValue:&signature];
    }
    return returnValue;
}



注意:在Swift中没有NSMethodSignature和NSInvocation方法,暂时只能通过桥接解决,Swift中给出了这样一句:

NS_SWIFT_UNAVAILABLE("NSInvocation and related APIs not available")
如果在Swift中谁有好的方法可以扩展,请求大神告知!不胜感激!

方案二:

objc_msgSend :

objc_msgSend(<#id self#>, <#SEL op, ...#>)

概念:其实每个类中都有一张方法列表去存储这个类中有的方法,当发出objc_msgSend方法时候,就会顺着列表去找这个方法是否存在,如果不存在,则向该类的父类继续查找,直到找到位置。如果始终没有找到方法,那么就会进入到消息转发机制;objc_msgSend被分为2个过程:1)在cache中寻找SEL。2)在MethodTable寻找SEL。

具体使用介绍:

在一个列中有以下两个方法:

@implementation CustomClass

-(void)fun
{
    NSLog(@"fun");
}

-(void)eat:(NSString *)food say:(NSString *)some
{
    NSLog(@"%@ %@",food, some);
}

@end

当我们使用的时候,使用objc_msgSend进行调用,如下:这样便调用了类中的fun方法

TestClass *cls = [[TestClass alloc] init];

objc_msgSend(cls, @selector(fun)); //错误写法(arm64崩溃偶尔发生)

((void (*)(id, SEL))objc_msgSend)(cls, @selector(fun)); //正确写法

//具体原因见下面解释 objc_msgSend arm64 崩溃问题


使用注意1:使用objc_msgSend crash解决方案



使用注意2:objc_msgSend arm64 崩溃问题
之前一直用objc_msgSend,但是没注意apple的文档提示,所以突然objc_msgSend crash了。
按照文档 64-Bit Transition Guide for Cocoa Touch 给出了以下代码片段:

- (int) doSomething:(int) x { ... }
- (void) doSomethingElse {
    int (*action)(id, SEL, int) = (int (*)(id, SEL, int)) objc_msgSend;
    action(self, @selector(doSomething:), 0);
}
所以必须先定义原型才可以使用,这样才不会发生崩溃,调用的时候则如下:

void (*glt_msgsend)(id, SEL, NSString *, NSString *) = (void (*)(id, SEL, NSString *, NSString *))objc_msgSend;

glt_msgsend(cls, @selector(eat:say:), @"123", @"456");













        
IPhone对@selector的函数如何传参数 立即下载

相关推荐

点餐系统数据库设计--SQL Server

友情链接 1、学生成绩管理系统数据库设计–MySQL 学生成绩管理系统数据库设计–MySQL 2、医疗信息管理系统数据库–MySQL 医疗信息管理系统数据库–MySQL 3、邮件管理数据库设计–MySQL 邮件管理数据库设计–MySQL 4、SQL Server医疗信息管理系统数据库【英文版-源码】–(Medical Management System Database) SQL Server医疗信息管理系统数据库【英文版-源码】–(Medical Management System Database) 5

若如初见 8万+

80_iOS干货43_调用OC方法传递多个参数的11种方法

一,方法中写多个参数调用 - (void)test1 { [self testFunctionWithParams1:6 :@"234131#"]; } - (void)testFunctionWithParams1:(int )number :(NSString *)string { NSLog(@"方法多个参数:%i%@",number, string); } 二,per...

a_horse的博客 3496

EEGnet模型论文讲解(画图详解三种卷积层操作)

我录了一个讲解视频:https://www.bilibili.com/video/BV1si4y1s7g7/ 目录 一、整体介绍 二、梳理激活函数 三、图解三种卷积层 (核心内容) 四、总结 一、整体介绍 EEGnet是为专门一般的脑电图识别任务而设计的通用且紧凑的卷积神经网络。(设计思路借鉴了MobileNet) 下图是EEGnet的整体结构图,只有三个卷积模块,重点是depthwise conv 和separable conv这两个卷积模块。 表格表明了EEGnet的...

Amigo_1997的博客 2万+

iOS中perform+@selector多参数传递

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_33738578的博客 348

[技术解析] SGDC驱动的轻量级IoT入侵检测:特征选择与模型优化的实战指南

本文深入解析了如何利用SGDC驱动的轻量级入侵检测系统保护IoT设备安全。通过实战指南,详细阐述了SGDC模型在资源受限环境下的优势,并结合特征选择技术优化模型性能,实现高效、低耗的异常流量检测,为物联网安全部署提供了一套可行的解决方案。

weixin_29192211的博客 350

【对比学习+分割】CRIS:CLIP驱动RIS图像分割(CVPR 2022)

CRIS: CLIP-Driven Referring Image Segmentation

这个博客太懒了什么都没说 3324

performSelectorOnMainThread支持多个参数

iOS 的 NSObject对象提供了一种在不同线程中执行其方法的机制。 最常见的是需要在主线程即UI线程中去执行一些方法 performSelectOnMainThread:withObject:waitUntilDone: 但是这个默认的方法只支持一个参数。 performSelector:withObject:withObject: 这个不是在主程线中运行的…只能

疯休止的专栏 4450

基于matlab的CNN食物识别分类系统,matlab深度学习分类,训练+数据集+界面

饮食在人们的日常生活、营养与医疗建议以及运动员等专业人士的训练上起着越来越重要的作用。随着互联网的发展和医学的进步,人们普遍上传分享和记录的食物图像形成了非常多的数据库,为了改善饮食结构,塑造更健康的生活方式,分析食物的种类、热量和进食时间成为了营养学上非常重要的研究方法,本文的使用深度学习算法可以根据用户上传的食物图像自动分析食物种类。深度学习是机器学习领域的一个研究方向。深度学习通过对数据特征的学习将原始数据转化为计算机可以理解的抽象数据,根据学习到的特征,可以对原始数据进行检测或分类。

在职AI算法工程师,擅长计算机视觉,YOLO目标检测、分割等,擅长web、pyqt界面可视化,好内容持续更新中,来这里跟大家一起学习,共同进步 4719

iOS中performSelector+@selector多参数传递解决方法

关于performSelector传递参数一般不能超过2个,但是现实开发中我们有时需要用到传递大于2以上的参数,这个时候performSelector就不能满足要求了。所以这里总结了开发中解决的办法,有二种: 1.用NsInvocation代替performSelector可以实现传递多个参数 2.就是将参数进行封装成一个结构体,Class,z字典或其他的集合,然后定义一个传递单参的方法也可以

公子纠的博客 9733

JavaScript教程-字符集,Unicode转义序列,标识符,数据类型,数字,未定义值,浮点数,字符串,引用数据类型,类型检测,类型转换,运算符,关系运算符,

前端学习

VAN 211

【AI智能体】Coze 数据库从使用到实战操作详解

Coze 数据库使用到实战详解

congge 5911

performSelector多个参数

需求如题所示。。。。。 我们都知道 - (id)performSelector:(SEL)aSelector; - (id)performSelector:(SEL)aSelector withObject:(id)object; - (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;在N

chmod_R_755的专栏 2805

【DRAM存储器六十一】LPDDR5介绍--LPDDR5/5X/4/4X IO结构

简述LPDDR5/5X/4/4X IO结构及等效电路下的VREF理论值计算

highman110的博客 480

Objective-C中一种消息处理方法performSelector: withObject:

Objective-C中调用函数的方法是“消息传递”,这个和普通的函数调用的区别是,你可以随时对一个对象传递任何消息,而不需要在编译的时候声明这些方法。所以Objective-C可以在runtime的时候传递人和消息。   首先介绍两个方法 SEL和@selector 根据AppleObjective-C Runtime Reference官方文档这个传递消息的函数就是 id o

Ale 509

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

如何在OC中没有显示声明的方法?

在OC中调用方法时,可以直接使用显式 //NSMutableArray调用array类方法 NSMutableArray *arr = [NSMutableArray array]; //NSMutableArray对象调用addObject方法 [arr addObject:@"element"]; 经常会需要执行没有显示声明的方法,比如动态添加的方法,私有方法等,这些方法都不能使用 ...

王二东的博客 649

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

消息处理之performSelector

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_34353714的博客 262

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

OC performSelector和传递参数

performSelector和直接调用方法的区别 performSelector: withObject:是在iOS中的一种方法调用方式。他可以向一个对象传递任何消息,而不需要在编译的时候声明这些方法。所以这也是runtime的一种应用方式。 所以performSelector和直接调用方法的区别就在与runtime。直接调用编译是会自动校验。如果方法不存在,那么直接调用 在编译时候就能够发现,编译器会直接报错。 但是使用performSelector的话一定是在运行时候才能发现,如果此方...

迦南的专栏 2698

iOS之@selector的函数传递多个参数

1、一般情况,使用self performSelector:SEL withObject:id方法 [self performSelectorOnMainThread:@selector(testAA:) withObject:[NSArray arrayWithObjects:@"1",@"2", nil] waitUntilDone:NO]; -(void) testAA:(NSAr...

LVXIANGAN的专栏 1万+

实现performSelector 传递多个参数

- (id)performSelector:(SEL)selector withObjects:(NSArray *)objects   {       // 方法签名(方法的描述)       NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:selector];       i

sharpyl的专栏 1287

performSelector多参数

http://www.cnblogs.com/zhao-jie-li/p/5850489.html [self performSelector:@selector(SelectorOneParameter:) withObject:@"firstParameter"];- (void)SelectorOneParameter:(NSString *)first{ NSLog(@"

lxs_kevin的专栏 272

DIY雪花灯制作:从电路设计到流体动力学的创意电子实践

电子DIY项目是学习电路原理和动手实践的绝佳途径,其核心在于将基础电子学知识与物理效应相结合,创造出具有实用价值或观赏性的装置。理解电路设计、焊接技术以及简单流体力学,能够帮助爱好者实现从概念到成品的完整构建过程。这类项目不仅巩固了电子元器件的应用技能,如使用TP4056充电模块管理锂电池供电,还涉及光学与流体介质的调配,以模拟特定的视觉效果。其技术价值在于低成本、高成功率的实践体验,并能灵活扩展至智能控制等进阶应用。典型的应用场景包括创意氛围灯、教学演示模型或艺术装置制作。本文以制作一个利用LED光源、甘

weixin_33690963的博客 414

[Xcode]编译时objc_msgSend错误的解决办法

之前开发的代码中需要强制使用一些苹果的私有API,用了objc_msgSend方法进行调用,最近使用最新版本的Xcode进行编译时一致无法通过,后来通过度娘解决了这个问题,在此记录一下,修改方法也很简单,将ENABLE_STRICT_OBJC_MSGSEND的属性值设置为NO就OK,至少目前还没发现程序有什么问题。参考地址http://www.ruanman.net/swift/learn/104

李大仁博客 1591

深入解构objc_msgSend函数的实现

熟悉OC语言的Runtime(运行时)机制以及对象方法调用机制的开发者都知道,所有OC方法调用在编译时都会转化为对C函数objc_msgSend的调用。/*下面的例子是在arm64体系下的函数调用实现,本文中如果没有特殊说明都是指在arm64体系下的结论*/系统的Runtime库通过函数objc_msgSend以及OC对象中隐藏的isa数据成员来实现多态和运行时方法查找以及执行。每个对象的isa中保存着这个对象的类对象指针,

yz_weixiao的博客 2536

ios performSelector 延时传值

通过给Object传值swwwww,下面的testPerForm就会收到swwwww,然后打印出来 [self performSelector:@selector(testPerForm:) withObject:@"swwwww" afterDelay:1]; - (void)testPerForm:(NSString*)str { NSLog(@"testPerForm-----%

robinson_911的专栏 2337

ios如何用perform selector调用超过两个以上参数的方法

Cocoa内置只支持两个参数,要超过两个参数以上怎么办呢,下面代码展示了如何实现一个自己的方法来调用超过7个参数(来自three20) 

- (id)performSelector:(SEL)selector withObject:(id)p1 withObject:(id)p2 withObject:(id)p3
 withObject:(id)p4 withObject:(id)p5 w...

renzhelife 258
上一篇: iOS GPUImage音视频采集以及美颜功能
下一篇: swift 屏幕旋转以及状态栏问题解决方案
glt_code
博客等级 码龄10年 40粉丝 27原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值