如何取得ChipmunkConstraint实例对象的私有属性

如何用代码禁用SpriteBuilder中创建的关节 一篇中提到了要想禁用一个关节就需要将其无效化。

然后我们在重新创建新关节时,可以参考该关节的原始参数。

但是代码中只能直接访问到bodyA和bodyB两个属性,anchorA、anchorB以及minDistance、maxDistance等4个属性无法直接访问到,书上称之为这些属性为私有属性(private property)。其实只要你包含了对应的头文件,就可以在自己的代码中直接引用它们。

由于这些属性值在例子中永不变化,所以书中使用了硬编码的方法来赋给新的关节,代码如下:

_lockJoint = [CCPhysicsJoint connectedDistanceJointWithBodyA:_lockJoint.bodyA
                                bodyB:_lockJoint.bodyB anchorA:ccp(0.0, -300.0)
                                anchorB:ccp(32.0, 32.0) minDistance:223.0
                                                     maxDistance:223.0];

但是需要知道的是,以上4个属性毫无疑问是存放在_lockJoint中的,只是无法直接访问到,下面就想办法从代码中直接取到这4个属性。

首先,obj-c中不存在真正的所谓私有方法,我们一般将不在interface中或在interface () 中声明的方法称之为私有方法。这种私有方法,不能直接通过[obj privagteMethod]的方式调用,编译器会抱怨一个错误的:告知类中没有该实例方法。

我们首先可以尝试用performSelector来取得该属性(因为不管啥属性其实也就是对应的2个方法;这里不考虑set方法,只考虑get方法)。

[obj performSelector:@selector(privateMethod)];

这样是可以调用到该私有方法,看上去很美 ;)
但是且慢,返回值不是id类型怎么办!?
对于返回值小于等于4bytes(因为在我的mac上sizeof(id)返回4)的方法,或许可以试试强制转换。但是double和CGPoint都大于4bytes,这样返回的值会被截断,结果肯定不正确。

我们可以看一下这4个属性在对于头文件中的声明:

@interface ChipmunkSlideJoint : ChipmunkConstraint

/**
    Create an autoreleased slide joint between the two bodies with the given anchor points and distance range.
*/
+ (ChipmunkSlideJoint *)slideJointWithBodyA:(ChipmunkBody *)a bodyB:(ChipmunkBody *)b anchorA:(cpVect)anchorA anchorB:(cpVect)anchorB min:(cpFloat)min max:(cpFloat)max;

/**
    Initialize a slide joint between the two bodies with the given anchor points and distance range.
*/
- (id)initWithBodyA:(ChipmunkBody *)a bodyB:(ChipmunkBody *)b anchorA:(cpVect)anchorA anchorB:(cpVect)anchorB min:(cpFloat)min max:(cpFloat)max;

/// The anchor point on the first body.
@property(nonatomic, assign) cpVect anchorA;

/// The anchor point on the second body.
@property(nonatomic, assign) cpVect anchorB;

/// The minimum allowed distance between anchor points.
@property(nonatomic, assign) cpFloat min;

/// The maximum allowed distance between anchor points.
@property(nonatomic, assign) cpFloat max;

@end

可以知道cpFloat和cpVect实际分别对应于double和CGPoint。

我们先来搞定返回值为double的属性(sizeof(double)为8)。大家知道调用对象的方法实际是向该对象发消息(performSelector内部也是如此),由此引出一个返回double的专有函数:

#import <objc/message.h>
objc_msgSend_fpret(instance,selector,...);

上面selector就是@selector(min)或者@selector(max),但是instance是神马呢?其实CCPhysicsJoint实例中有一个constraint属性,该属性又是另一个“私有”类ChipmunkConstraint的实例,所以我们要先取到constraint属性:

id cs = [_lockJoint performSelector:@selector(constraint)];

因为该私有方法正好返回一个id所以可以直接用performSelector来取得该属性。下面我们来取min和max的值:

double min = objc_msgSend_fpret(cs, @selector(min));
double max = objc_msgSend_fpret(cs, @selector(max));

that’s all!

接下来是返回CGPoint的anchorA、anchorB方法。
对于取得返回为结构这种情况,我们可以考虑用obj-c的invocation机制来完成。

首先用方法签名创建一个NSInvocation对象:

NSInvocation *invo = [NSInvocation invocationWithMethodSignature:[[Constraint class]
                                                    instanceMethodSignatureForSelector:@selector(anchorA)]];

这里的Constraint不可以用ChipmunkConstraint,而必须用其对应的子类ChipmunkSlideJoint。因为anchorA、anchorB方法是在这些子类中定义的。这个不像前面的向一个对象sendMsg的情况,前面会动态根据实际对象类型执行特定方法,这是在运行时完成的。而这里取得方法签名是在编译时完成的,如果该方法不在对应类类(即使在其子类中),instanceMethodSignaturForSelector会返回nil,从而使得invocationWithMethodSignature:抛出异常。

所以我们有:

Class Constraint = NSClassFromString(@"ChipmunkSlideJoint");

NSInvocation *invo = [NSInvocation invocationWithMethodSignature:[[Constraint class]
                                                    instanceMethodSignatureForSelector:@selector(anchorA)]];
        [invo setSelector:@selector(anchorA)];
        [invo setTarget:cs];
        [invo invoke];
        CGPoint pa;
        [invo getReturnValue:&pa];

取anchorA和上面类似,不再赘述。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大熊猫侯佩

赏点钱让我买杯可乐好吗 ;)

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值