【问题标题】:Selectors in Cocos2d schedule methodCocos2d 调度方法中的选择器
【发布时间】:2011-06-18 22:51:39
【问题描述】:

所以我这样做是为了初始化我的选择器:

//In .h

SEL selectors[3];

//In .m

selectors[0] = @selector(rotate);
selectors[1] = @selector(discharge);

这就是问题所在:

当我在 Cocos2d 的 init 方法中这样调用时:

[self performSelector:selectors[0]];

它工作得很好,但是当我在一个名为 moveThings 的方法中调用这行代码时,该方法在 Cocos2d 中的 init 方法结束时通过调度 ([self schedule:@selector(moveThings:)]) 调用,它给出了EXC_BAD_ACCESS。安排事情有什么问题?

更新:

我发现旋转函数存在问题(该函数存储在选择器 [0] 中)。这里是:

-(void)rotate:(ccTime)delta {
    if (((CCSprite *)[creature objectAtIndex:0]).rotation < 360) {
        ((CCSprite *)[creature objectAtIndex:0]).rotation++;
    }
    else {
        ((CCSprite *)[creature objectAtIndex:0]).rotation++;
    }
}

如果我将方法的内容注释掉,它在通过 moveThings 和 init 调用时可以正常工作。

如果我更改方法内容:

((CCSprite *)[creature objectAtIndex:0]).rotation++;

它失败了......但是,我想再次声明,如果我在我的 init 方法中调用它,所有这些东西都可以工作,甚至连续调用它两次,但它不会工作(除非我取出 rotate 方法的内容)如果我通过 moveThings: 方法调用它,该方法正在通过 schedule 方法调用它失败。

进一步更新:

如果我打电话:

((CCSprite *)[creature objectAtIndex:0]).rotation++;

在 moveThings 中(正如我之前所说,由 schedule:(SEL) 方法调用)它失败了。只要不是通过调度调用的方法调用它,它就可以工作。

【问题讨论】:

  • 崩溃日志到底说了什么?
  • @Deepak:对不起,我一直编辑错了...我没有粘贴它,应该有...选择器适用于 moveThings 只是不适用于选择器[0]...
  • @Deepak:崩溃日志显示Program recieved EXC_BAD_ACCESS
  • 哪一个失败了? [self schedule:@selector(moveThings:)];[self schedule:selectors[0]];
  • @Deepak: [self schedule:selectors[0]]; 在 moveThings 方法内部调用。

标签: objective-c cocos2d-iphone selector


【解决方案1】:

问题是当你调用 performSelector 时只有两个选项:

  1. 让您的选择器不带任何参数,并在 @selector(foo) 定义中保留“:”。
  2. 让您的选择器采用一个或两个参数这两个参数都必须是 NSObject 或子类

我怀疑是后者把你搞砸了。

这里是performSelector的三种形式:

- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;

您会注意到 withObject 参数都是 id 类型,它是一个 Objective C 对象。

您尝试使用的选择器采用 ccTime,它是 float不是作为参数的 Objective C 对象,这就是事情崩溃的原因:

-(void)rotate:(ccTime)delta;

一种选择是创建一个包装器方法,该方法采用包装后的ccTime 并将其解包并调用rotate:(ccTime) 方法:

- (void) wrappedRotate: (NSNumber*) inDelta
{
    [self rotate: [inDelta floatValue]];
}

然后使用

selectors[0] = @selector(wrappedRotate:);

然后通过以下方式调用:

[self schedule: @selector(moveThings:)]);  // cocos2d schedule

... 

- (void) moveThings: (ccTime) dt
{
   [self performSelector: selectors[0] withObject: [NSNumber numberWithFloat: dt]];
  ...
}

您感到困惑的一个原因是 Cocos2d 以某种更复杂的方式使用 @selector(具体参见 CCTimer::initWithTarget:selector:interval: 和 CCTimer::update: 方法中的 CCScheduler.m)。

免责声明:输入到 SO 中的代码因此未使用编译器进行检查,但您需要的内容的本质应该在这里。

【讨论】:

  • +1。系统想要保留传递的对象,而在普通浮点数上这样做会崩溃。
  • 谢谢,这是一个问题,我也忘了说self.creature...因为我只想要一个实例...
【解决方案2】:

一个问题是你使用了在.h 中声明的变量,同时在相对.m 中初始化它。根据链接,我不确定是否只存在一个变量selectors(因此包含.h 的不同文件会有不同的版本)。

首先我建议你尝试添加关键字extern来拥有

extern SEL selectors[3];

告诉您的链接器它已在相对 .m 中初始化并仅使用那个。

【讨论】:

  • 使用 extern 会报错...expected specifier-qualifier-list before 'extern'.
  • 不应该的,我刚在XCode里试过,应该有不一样的地方。也许你在一个类中声明 SEL?但它是一个实例变量还是只是一个变量?从你的问题看不清楚。
  • 是的,我在一个类中声明了选择器。我相信它是一个 ivar。
【解决方案3】:

我认为您的问题源于您的方法定义是 - (void)rotate; 而不是 - (void)rotate:(ccTime)dt;

你应该同样调整你的选择器。

【讨论】:

  • 不是它不会调用它,只是当我通过一个被调用的方法调用它时:[self schedule:(SEL)] 它不会工作。如果我只是调用 moveThings 方法而不使用 schedule 方法,它可以工作,如果我连续两次执行选择器,它也可以工作......
  • 哎呀,实际上,我已经按照您建议的方式定义了我也更改了它,在问题中写错了...
  • 不... 使用 rotate 我只是使用 .rotation = x; 更改 CCSprite 的旋转,其中 x 是用于更改旋转的浮点数。我不能使用CCRotateBy,因为我需要跟踪对象的当前旋转。
【解决方案4】:

如果您的方法没有任何参数,则不要在选择器调用中使用冒号。

// Requires @selector(foo:)
- (void) foo:(id)sender;
// Requires @selector(foo)
- (void) foo;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-12
    相关资源
    最近更新 更多