EXC_BAD_ACCESS 从 NSTimer 调用 c++ class 方法
EXC_BAD_ACCESS calling c++ class method from NSTimer
在使用 Xcode4 构建 cocoa 应用时尝试混合使用 C++ 和 objective-c 时遇到问题。
问题是当我使用 NSTimer 调用 handleFrame 函数时,它调用了 class.
的虚函数
这是我正在尝试做的事情:
1.创建监视器;
2.创建处理程序;
3.将处理程序分配给监视器(初始化函数)
4. 调用期望调用处理程序的虚方法的monitor->update()。
5.代码在 applicationDidFinishLaunching 函数中按预期工作,但是 NSTimer 在 handleFrame 中导致 EXC_BAD_ACCESS 异常。
//
// AppDelegate.h
// Concept5
//
#import <Cocoa/Cocoa.h>
#include "monitor.h"
#include "Derived.h"
@interface AppDelegate : NSObject <NSApplicationDelegate>
{
Monitor *monitor;`enter code here`
NSTimer *gameTimer;
}
@property (assign) IBOutlet NSWindow *window;
- (void)handleFrame:(NSTimer *)timer;
@end
AppDelegate implementation (.mm)
//
// AppDelegate.mm
// Concept5
//
#import "AppDelegate.h"
@implementation AppDelegate
- (void)dealloc
{
[super dealloc];
}
- (id) init {
self = [super init];
if(self) {
monitor = new Monitor();
}
return self;
}
- (void)handleFrame:(NSTimer *)timer {
monitor->update();
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
Derived derived;
monitor->init(derived);
monitor->update();
gameTimer = [[NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:@selector(handleFrame:)
userInfo:nil
repeats:YES] retain];
monitor->update();
}
@end
//
// Monitor.cpp
// Concept5
//
#include "Monitor.h"
void Monitor::init (Base& handler)
{
_handler = &handler;
}
void Monitor::update()
{
if (_handler != NULL)
{
_handler->speak(); // <-- EXC_BAD_ACCESS exception.
}
}
//
// Monitor.h
// Concept5
#ifndef __Concept5__Monitor__
#define __Concept5__Monitor__
#include <iostream>
#include "Base.h"
class Monitor
{
private:
Base* _handler;
public:
void init (Base& handler);
void update();
};
#endif /* defined(__Concept5__Monitor__) */
//
// Base.cpp
// Concept5
#include "Base.h"
void Base::speak()
{
std::cout << "Base speaks" << std::endl;
}
//
// Base.h
// Concept5
#ifndef __Concept5__Base__
#define __Concept5__Base__
#include <iostream>
class Base
{
public:
virtual void speak();
};
#endif /* defined(__Concept5__Base__) */
//
// Derived.cpp
// Concept5
#include "Derived.h"
void Derived::speak()
{
std::cout << "Derived speaks" << std::endl;
}
//
// Derived.h
// Concept5
//
#ifndef __Concept5__Derived__
#define __Concept5__Derived__
#include <iostream>
#include "Base.h"
class Derived : public Base
{
public:
void speak();
};
#endif /* defined(__Concept5__Derived__) */
我不是 Objective-C 专家,但 EXC_BAD_ACCESS 意思是您正在尝试访问带有错误指针的内容,可能是 nil 指针。
由于您的计时器在 Monitor 实例上调用 INSTANCE 方法而不是 CLASS 方法,因此当您的计时器触发时,您 更好 有一个监视器实例。我 猜测 是你不知道。如果我更像是一个 Objective-C 人,我可能会看看你的代码并看到这个,但实际上我必须 运行 你的代码才能告诉你。但我敢打赌这就是问题所在。
综上所述,使用实例方法调用计时器是一个冒险的想法,除非您绝对确定该实例仍然存在并且您知道自己在做什么。在计时器上只调用 class 方法更安全。
我从未使用过 Objective-C,但以下内容看起来像是一个问题:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
Derived derived;
monitor->init(derived);
//....
}
由于Derived
是局部变量,作用域不会超出applicationDidFinishLaunching
函数。因此调用 init()
(它接受一个指针),当上面的函数 returns.
时,将持有一个无效的对象。
如果这是 C++,解决方案是确保对象的生命周期足够长。通常的解决方案是:
1) 使对象成为全局对象,或者
2) 使用new
或
动态创建对象
3) 创建一个智能指针(可能 std::shared_ptr
)并使用它代替原始指针。
在使用 Xcode4 构建 cocoa 应用时尝试混合使用 C++ 和 objective-c 时遇到问题。 问题是当我使用 NSTimer 调用 handleFrame 函数时,它调用了 class.
的虚函数这是我正在尝试做的事情: 1.创建监视器; 2.创建处理程序; 3.将处理程序分配给监视器(初始化函数) 4. 调用期望调用处理程序的虚方法的monitor->update()。 5.代码在 applicationDidFinishLaunching 函数中按预期工作,但是 NSTimer 在 handleFrame 中导致 EXC_BAD_ACCESS 异常。
//
// AppDelegate.h
// Concept5
//
#import <Cocoa/Cocoa.h>
#include "monitor.h"
#include "Derived.h"
@interface AppDelegate : NSObject <NSApplicationDelegate>
{
Monitor *monitor;`enter code here`
NSTimer *gameTimer;
}
@property (assign) IBOutlet NSWindow *window;
- (void)handleFrame:(NSTimer *)timer;
@end
AppDelegate implementation (.mm)
//
// AppDelegate.mm
// Concept5
//
#import "AppDelegate.h"
@implementation AppDelegate
- (void)dealloc
{
[super dealloc];
}
- (id) init {
self = [super init];
if(self) {
monitor = new Monitor();
}
return self;
}
- (void)handleFrame:(NSTimer *)timer {
monitor->update();
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
Derived derived;
monitor->init(derived);
monitor->update();
gameTimer = [[NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:@selector(handleFrame:)
userInfo:nil
repeats:YES] retain];
monitor->update();
}
@end
//
// Monitor.cpp
// Concept5
//
#include "Monitor.h"
void Monitor::init (Base& handler)
{
_handler = &handler;
}
void Monitor::update()
{
if (_handler != NULL)
{
_handler->speak(); // <-- EXC_BAD_ACCESS exception.
}
}
//
// Monitor.h
// Concept5
#ifndef __Concept5__Monitor__
#define __Concept5__Monitor__
#include <iostream>
#include "Base.h"
class Monitor
{
private:
Base* _handler;
public:
void init (Base& handler);
void update();
};
#endif /* defined(__Concept5__Monitor__) */
//
// Base.cpp
// Concept5
#include "Base.h"
void Base::speak()
{
std::cout << "Base speaks" << std::endl;
}
//
// Base.h
// Concept5
#ifndef __Concept5__Base__
#define __Concept5__Base__
#include <iostream>
class Base
{
public:
virtual void speak();
};
#endif /* defined(__Concept5__Base__) */
//
// Derived.cpp
// Concept5
#include "Derived.h"
void Derived::speak()
{
std::cout << "Derived speaks" << std::endl;
}
//
// Derived.h
// Concept5
//
#ifndef __Concept5__Derived__
#define __Concept5__Derived__
#include <iostream>
#include "Base.h"
class Derived : public Base
{
public:
void speak();
};
#endif /* defined(__Concept5__Derived__) */
我不是 Objective-C 专家,但 EXC_BAD_ACCESS 意思是您正在尝试访问带有错误指针的内容,可能是 nil 指针。
由于您的计时器在 Monitor 实例上调用 INSTANCE 方法而不是 CLASS 方法,因此当您的计时器触发时,您 更好 有一个监视器实例。我 猜测 是你不知道。如果我更像是一个 Objective-C 人,我可能会看看你的代码并看到这个,但实际上我必须 运行 你的代码才能告诉你。但我敢打赌这就是问题所在。
综上所述,使用实例方法调用计时器是一个冒险的想法,除非您绝对确定该实例仍然存在并且您知道自己在做什么。在计时器上只调用 class 方法更安全。
我从未使用过 Objective-C,但以下内容看起来像是一个问题:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
Derived derived;
monitor->init(derived);
//....
}
由于Derived
是局部变量,作用域不会超出applicationDidFinishLaunching
函数。因此调用 init()
(它接受一个指针),当上面的函数 returns.
如果这是 C++,解决方案是确保对象的生命周期足够长。通常的解决方案是:
1) 使对象成为全局对象,或者
2) 使用new
或
3) 创建一个智能指针(可能 std::shared_ptr
)并使用它代替原始指针。