T.T写点runtime总结

项目中有,先记点runtime:

一. runtime基础

1.objc_object,objc_class,meta class,objc_method,objc_selector,SEL,IMP,method_types

首先oc中所有实例的本质其实是一个结构体指针,叫做objc_object,里面只有一个属性,叫isa指针,他是一个叫指向做objc_class的结构体指针。

struct objc_object {
    Class _Nonnull isa;       // objc_object 结构体的实例指针
};

/// A pointer to an instance of a class.
typedef struct objc_object *id;
/// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;

struct objc_class {
    Class _Nonnull isa;                                          // objc_class 结构体的实例指针

#if !__OBJC2__
    Class _Nullable super_class;                                 // 指向父类的指针
    const char * _Nonnull name;                                  // 类的名字
    long version;                                                // 类的版本信息,默认为 0
    long info;                                                   // 类的信息,供运行期使用的一些位标识
    long instance_size;                                          // 该类的实例变量大小;
    struct objc_ivar_list * _Nullable ivars;                     // 该类的实例变量列表
    struct objc_method_list * _Nullable * _Nullable methodLists; // 方法定义的列表
    struct objc_cache * _Nonnull cache;                          // 方法缓存
    struct objc_protocol_list * _Nullable protocols;             // 遵守的协议列表
#endif

};

所以定义了一个实例,其中的指向关系是,objc_object中的isa指向objc_class,objc_class的isa指向metaclass(元类)

objc_class中的methodlist是一个数组,存储的是这个类当中的方法的地址

每个方法的类型叫做objc_method 

typedef struct objc_method *Method;

struct objc_method {
    SEL _Nonnull method_name;                    // 方法名
    char * _Nullable method_types;               // 方法类型
    IMP _Nonnull method_imp;                     // 方法实现
};
/// An opaque type that represents a method selector.
typedef struct objc_selector *SEL;
/// A pointer to the function of a method implementation. 
#if !OBJC_OLD_DISPATCH_PROTOTYPES
typedef void (*IMP)(void /* id, SEL, ... */ ); 
#else
typedef id _Nullable (*IMP)(id _Nonnull, SEL _Nonnull, ...); 
#endif

 

SEL 是一个指向 objc_selector 结构体 的指针,但是在 runtime 相关头文件中并没有找到明确的定义。不过,通过测试我们可以得出: SEL 只是一个保存方法名的字符串。
 IMP的实质是一个函数指针,所指向的就是方法的实现。IMP用来找到函数地址,然后执行函数。

二.消息转发

oc中的方法查找过程:首先查objc_object的isa,然后查objc_class的缓存cache,没有就查methodlist,没有再查父类,以此类推,如果查到最后都没找到,那么就是接下来要说的消息转发机制。

调用 [receiver selector]; 后,进行的流程:

  1. 编译阶段:[receiver selector]; 方法被编译器转换为:
    1. objc_msgSend(receiver,selector) (不带参数)
    2. objc_msgSend(recevier,selector,org1,org2,…)(带参数)
  2. 运行时阶段:消息接受者 recever 寻找对应的 selector
    1. 通过 recevierisa 指针 找到 recevierclass(类)
    2. Class(类)cache(方法缓存) 的散列表中寻找对应的 IMP(方法实现)
    3. 如果在 cache(方法缓存) 中没有找到对应的 IMP(方法实现) 的话,就继续在 Class(类)method list(方法列表) 中找对应的 selector,如果找到,填充到 cache(方法缓存) 中,并返回 selector
    4. 如果在 class(类) 中没有找到这个 selector,就继续在它的 superclass(父类)中寻找;
    5. 一旦找到对应的 selector,直接执行 recever 对应 selector 方法实现的 IMP(方法实现)
    6. 若找不到对应的 selector,Runtime 系统进入消息转发机制。
  3. 运行时消息转发阶段:
    1. 动态解析:通过重写 +resolveInstanceMethod: 或者 +resolveClassMethod:方法,利用 class_addMethod 方法添加其他函数实现;
    2. 消息接受者重定向:如果上一步添加其他函数实现,可在当前对象中利用 -forwardingTargetForSelector: 方法将消息的接受者转发给其他对象;
    3. 消息重定向:如果上一步没有返回值为 nil,则利用 -methodSignatureForSelector:方法获取函数的参数和返回值类型。
      1. 如果 -methodSignatureForSelector: 返回了一个 NSMethodSignature 对象(函数签名),Runtime 系统就会创建一个 NSInvocation 对象,并通过 -forwardInvocation: 消息通知当前对象,给予此次消息发送最后一次寻找 IMP 的机会。
      2. 如果 -methodSignatureForSelector: 返回 nil。则 Runtime 系统会发出 -doesNotRecognizeSelector: 消息,程序也就崩溃了。

三. method swizzing

这是oc的一种消息交换机制,可以在运行时动态的交换两个方法的实现 。

具体可参考网上资料:iOS 开发:『Runtime』详解(二)Method Swizzling - 掘金

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个基于固定点约束的机器人运动学参数标定代码的简单示例。代码使用MATLAB编写,需要使用Robotics Toolbox for MATLAB进行运算。 首先,我们需要定义机器人的DH参数和关节角度,以及机器人的初始姿态。 ```matlab % Define robot parameters L1 = Link('d', 0.5, 'a', 0, 'alpha', pi/2); L2 = Link('d', 0, 'a', 0.5, 'alpha', 0); robot = SerialLink([L1 L2], 'name', 'robot'); % Define joint angles and initial pose q = [0.5, 0]; T = robot.fkine(q); ``` 然后,我们需要定义机器人的固定点,并将它们转换为机器人坐标系中的坐标。 ```matlab % Define fixed points in robot base frame P1 = [0.1, 0.1, 0.1]; P2 = [0.1, -0.1, 0.1]; P3 = [-0.1, -0.1, 0.1]; % Transform fixed points to robot coordinate frame P1 = T * [P1, 1]'; P2 = T * [P2, 1]'; P3 = T * [P3, 1]'; ``` 接下来,我们可以使用机器人的正逆运动学函数来计算机器人的末端执行器位置和姿态,并将其转换为机器人坐标系中的坐标。然后,我们可以使用固定点的坐标和机器人末端执行器的坐标来计算误差。 ```matlab % Calculate robot end-effector position and orientation T = robot.fkine(q); p = T.t; R = T.R; % Transform end-effector position to robot coordinate frame p = T * [p, 1]'; % Calculate error between fixed points and end-effector position e1 = P1(1:3) - p(1:3); e2 = P2(1:3) - p(1:3); e3 = P3(1:3) - p(1:3); ``` 最后,我们可以使用误差来计算机器人的运动学参数,并进行迭代计算,直到误差收敛到一个可接受的范围。 ```matlab % Initialize robot parameters a1 = 0.5; a2 = 0.5; % Calculate Jacobian matrix J = robot.jacob0(q); % Iterate until error is small enough while norm([e1, e2, e3]) > 0.001 % Calculate delta_a using pseudoinverse delta_a = pinv(J) * [e1; e2; e3]; % Update robot parameters a1 = a1 + delta_a(1); a2 = a2 + delta_a(2); % Update robot DH parameters robot.links(1).a = a1; robot.links(2).a = a2; % Recalculate Jacobian matrix J = robot.jacob0(q); % Calculate error between fixed points and end-effector position e1 = P1(1:3) - p(1:3); e2 = P2(1:3) - p(1:3); e3 = P3(1:3) - p(1:3); end ``` 这是一个非常简单的机器人运动学参数标定代码示例,实际应用中可能需要更复杂的算法和方法来提高精度和稳定性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值