您当前的位置: 首页 > 

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

发布时间:2015-10-02 11:54:22 ,浏览量:0

在 如何用代码禁用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_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和上面类似,不再赘述。

关注
打赏
1688896170
查看更多评论

暂无认证

  • 0浏览

    0关注

    108697博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文
立即登录/注册

微信扫码登录

0.3429s