大家好
我有一个用 obj-c 和 cocoa 制作的屏幕保护程序。在 OsX 10.6.2 下一切正常,除了以下内容。在我的屏幕保护程序中,我有一个正在运行一些应用程序的 WebView。当我尝试通过 javascript 调用我的 Objective-c 应用程序(屏幕保护程序)时,我收到一个错误并且屏幕保护程序和系统首选项面板崩溃。
系统偏好设置[86666] *** 由于未捕获的异常“NSInvalidArgumentException”而终止应用程序
原因:'-[NSCFArray drain]:无法识别的选择器发送到实例 0x20049b1e0'
在第一掷:( ***调用堆栈
0的CoreFoundation 0x00007fff8123a444 __exceptionPreprocess + 180
1 libobjc.A.dylib 0x00007fff81f130f3 objc_exception_throw + 45
+ 0:2的CoreFoundation 0x00007fff812931c0 + [NSObject的(NSObject的)doesNotRecognizeSelector]
3的CoreFoundation 0x00007fff8120d08f转发+ 751
4的CoreFoundation 0x00007fff812091d8 _CF_forwarding_prep_0 + 232 5 WebCore 0x00007fff847adee0 _ZN3JSC8Bindings12ObjcInstance10virtualEndEv + 48
6 WebCore 0x00007fff8470d71d _ZN3JSC16RuntimeObjectImp18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE + 397
7 JavaScriptCore 0x00007fff80862b66 NK3JSC7JSValue3getEPNS_9ExecStateERKNS_10IdentifierSer4_1
)Proty_10IdentifierS_4_1) ProtySlotE + 397
我知道这看起来像是一些内存泄漏,但正如您将在代码中看到的那样,我实际上几乎没有分配任何对象。
这只发生在我使用屏幕保护程序系统首选项中的“测试”按钮启动屏幕保护程序时。当我通过终端启动屏幕保护程序或者如果它自动启动时,相同的操作(从 javascript 调用 obj-c)可以正常工作。
也许有人有任何想法,错误可能来自哪里。这是实现中的一些代码:
@implementation ScreensaverView
- (id)initWithFrame:(NSRect)frame isPreview:(BOOL)isPreview {
self = [super initWithFrame:frame isPreview:isPreview];
if (self) {
[self setAnimationTimeInterval:-1];
[self setAutoresizesSubviews:YES];
// ::::::::::::::::::::::: Init stuff ::::::::::::::::::
// init
quitFlag = false;
previewMode = isPreview;
// find out the path the screensaver bundle
pMainBundle = [NSBundle bundleForClass:[self class]];
pBundlePath = [pMainBundle bundlePath];
// read Info.plist
infoDict = [pMainBundle infoDictionary];
}
return self;
}
- (void)startAnimation
{
[super startAnimation];
// combine: bundle path + filename for screensaver file
NSString *pathToScreensaver = [NSString stringWithString:pBundlePath];
NSString *valueScreensaverFile;
if(!previewMode)
{
valueScreensaverFile = [infoDict objectForKey:@"ScreensaverFile"];
}
else
{
valueScreensaverFile = [infoDict objectForKey:@"PreviewFile"];
}
// add filename to bundle path
pathToScreensaver = [pathToScreensaver stringByAppendingString:valueScreensaverFile];
// complete NSURL to the screensaver file
NSURL *screensaverUrl = [NSURL fileURLWithPath: pathToScreensaver];
webView = [WebView alloc];
[webView initWithFrame:[self frame]];
[webView setDrawsBackground:NO];
// delegation policy for interactive mode
[webView setPolicyDelegate: self];
[webView setUIDelegate:self];
// load screensaver
[[webView mainFrame] loadRequest:[NSURLRequest requestWithURL:screensaverUrl]];
scriptObject = [webView windowScriptObject];
[scriptObject setValue:self forKey:@"screensaver"];
[self addSubview:webView];
}
- (void)stopAnimation
{
[[webView mainFrame] stopLoading];
[webView removeFromSuperview];
[webView release];
[super stopAnimation];
}
+ (BOOL)isSelectorExcludedFromWebScript:(SEL)selector
{
if (selector == @selector(quitScreenSaver)) {
return NO;
}
if(selector == @selector(gotoUrl:) ){
return NO;
}
return YES;
}
+(NSString *)webScriptNameForSelector:(SEL)selector
{
if(selector == @selector(quitScreenSaver))
{
return @"quitNoOpen";
}
if(selector == @selector(gotoUrl:))
{
return @"openAndQuit";
}
return nil;
}
- (void) quitScreenSaver
{
quitFlag = true;
[super stopAnimation];
}
- (void) gotoUrl:(NSString *) destinationURL
{
if(destinationURL == NULL)
{
return;
}
NSString * path = destinationURL;
NSURL * fileURL = [NSURL URLWithString:path];
[[ NSWorkspace sharedWorkspace ] openURL:fileURL];
[self quitScreenSaver];
}
@end
我希望这些代码足以让您看到一些问题/解决方案。我真的很感激任何答案。