I'm suddenly beset by Core Data problems in the form of managedObjectContexts that are nil two-thirds of the time: the onset more or less coincides with upgrading to Xcode 8. The new NSPersistentContainer class seemed to offer an opportunity to solve my problems and get rid of some ugly code. Unfortunately, I cannot make it work.
In AppDelegate.h
#property (readonly, strong, nonatomic) NSPersistentContainer *persistentContainer;
In AppDelegate.m:
#synthesize persistentContainer = _persistentContainer;
- (NSPersistentContainer *)persistentContainer
{
if (!_persistentContainer) {
_persistentContainer = [NSPersistentContainer persistentContainerWithName:#"I_WILL_PERSIST"];
__block BOOL storesWereLoaded = NO;
[_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *psd, NSError *error) {
if (error) {
NSLog(#"loadPersistentStoresWithCompletionHandler: persistent container could not load store %#. Error: %#",
psd, error.debugDescription);
} else {
storesWereLoaded = YES;
}
}];
if (storesWereLoaded) {
NSLog(#"Stores were loaded");
} else {
NSLog(#"Stores were not loaded");
}
}
return _persistentContainer;
}
The app is a little test app, with an arrayController bound (in IB) to App Delegate.persistentContainer.viewContext. App Delegate is connected and not nil. The persistentContainer getter is called repeatedly but the NSLog's inside the block never fire and the console shows:
Cannot perform operation without a managed object context 2016-09-24
19:34:39.207 I_WILL_PERSIST[5588:180829] ( 0 CoreFoundation
0x00007fff8da994f2 __exceptionPreprocess + 178 1 libobjc.A.dylib
0x00007fff8ed6173c objc_exception_throw + 48 2 CoreFoundation
0x00007fff8db004bd +[NSException raise:format:] + 205 3 AppKit
0x00007fff85d411c4 -[_NSManagedProxy _managedObjectContext] + 66
Does the problem lie in my shaky block-programming skills? Is it a signing / permissions issue (the app is not Sandboxed, code signing automatic)? What's with Core Data all of a sudden?
====EDIT====
After upgrading to Mac OS 10.12 (Sierra), NSPersistentContainer fails with error:
2016-09-28 20:55:53.256588 osPersist[1936:41151] [error] error:
-addPersistentStoreWithType:SQLite configuration:(null) URL:file:///Users/user/Library/Application%20Support/osPersist/osPersist.sqlite options:{
NSInferMappingModelAutomaticallyOption = 1;
NSMigratePersistentStoresAutomaticallyOption = 1; } ... returned error Error Domain=NSCocoaErrorDomain Code=512 "The file couldn’t be saved." UserInfo={reason=Failed to create file; code = 2} with userInfo dictionary {
reason = "Failed to create file; code = 2"; } 2016-09-28 20:55:53.256747 osPersist[1936:41151] Unresolved error Error Domain=NSCocoaErrorDomain Code=512 "The file couldn’t be saved." UserInfo={reason=Failed to create file; code = 2}, {
reason = "Failed to create file; code = 2"; }
Why the database creation fails is not clear: it happens both with and without code-signing. I've made a bug report and I've opened a support request.
As soon as I upgraded to Sierra (MacOS 10.12) NSPersistentContainer started failing with errors. So, you can implement NSPersistentContainer in Xcode 8 running on MacOS 10.11 and your project will compile and run, but NSPersistentContainer won't do squat. I've filed a bug report and I hope that Apple will add preprocessor directives to the class, but they don't seem very interested.
Related
I have a simple free iOS arcade game not functioning correctly, after installation from the App Store, for owners of an iPhone with iOS 7.1 - 7.1.2. The game is build with Sprite Kit & Objective-C (no Swift what-so-ever) but is very simple in nature & doesn't have any fancy code or complexity to it. It also works wonderfully for anyone with iOS 8.x.x installed. After downloading iOS 7.1 Simulator for Xcode 6, I was able to reproduce the problem: iPhone's 4S, 5 or 5S running iOS version 7.1 - 7.1.2 all crash - So the launch image appears, but when it needs to load up the game from SKScene class called MyScene, it just doesn't open. In crash logs it says the following:
+[SKLabelNode labelNodeWithText:]: unrecognized selector sent to class 0x1022503a0
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[SKLabelNode labelNodeWithText:]: unrecognized selector sent to class 0x1022503a0'
*** First throw call stack:
(
0 CoreFoundation 0x00000001029a6495 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x000000010270199e objc_exception_throw + 43
2 CoreFoundation 0x0000000102a3755d +[NSObject(NSObject) doesNotRecognizeSelector:] + 205
Upon crashing, Xcode brings me to some Apple code page about "dispatch_once" & highlights line 68:
dispatch_once(predicate, block); Thread 1: signal SIGABRT
Basically, inside MyScene, there's -(id)initWithSize:(CGSize)size method. Inside it, I created
static dispatch_once_t onceMS;
dispatch_once(&onceMS, ^{
Inside dispatch_once, I have 4 things: 1. An instance of audioController is created (a class responsible for playing looped background music). 2. SKSpriteNode spriteNodeWithImageNamed: 3. SKLabelNode labelNodeWithText: 4. SKLabelNode labelNodeWithText:
All of these 4 things are meant to show up once, in the beginning of game startup: they are visual instructions for how to play. The background music is self explanatory.
I tried commenting all of this out but it still displayed the same crash logs as before. I proceeded commenting out the entire static dispatch_once & still the game crash. Can someone please give out some wisdom? I don't know what to do due to my lack of experience.
According to the documentation +[SKLabelNode labelNodeWithText:] is simply not available on iOS7
I have literally no experience with SpriteKit, but you should be able to replace all instances of
SKLabelNode *node = [SKLabelNode labelNodeWithText:#"your text"];
with:
SKLabelNode *node = [SKLabelNode labelNodeWithFontNamed:#"HelveticaNeue-UltraLight"];
node.fontSize = 32;
node.text = #"your text";
You can create your own category on SKLabelNode as well:
#interface SKLabelNode (iOS7Compatibility)
+ (instancetype)mba_labelNodeWithText:(NSString *)text;
#end
#implementation SKLabelNode (iOS7Compatibility)
+ (instancetype)mba_labelNodeWithText:(NSString *)text {
SKLabelNode *node = [self labelNodeWithFontNamed:#"HelveticaNeue-UltraLight"];
node.fontSize = 32;
node.text = text;
return node;
}
#end
which allows you to use:
SKLabelNode *node1 = [SKLabelNode mba_labelNodeWithText:#"your text"];
You must not name the category method labelNodeWithText:, because you don't want to overwrite methods in categories.
I have an app for Mac and iOS that uses .plist files to sync data between devices using iCloud. Every once in a while I get an email from someone that's getting repeated crashes on a specific device. (Other devices are fine.) In every case the app crashed while trying to read in a file from iCloud, using NSPropertyListSerialization to convert the data to a dictionary. In every case the problem is solved by having the user delete the iCloud data for the app. The same files get synced back in, and everything works fine again.
The specific example I'll use here is from the Mac version, but I've had almost identical crashes on iOS. From the crash report:
Exception Type: EXC_BAD_ACCESS (SIGBUS)
Exception Codes: 0x000000000000000a, 0x0000000101ee2000
VM Regions Near 0x101ee2000:
VM_ALLOCATE 0000000101ee1000-0000000101ee2000 [ 4K] rw-/rwx SM=PRV
--> mapped file 0000000101ee2000-0000000101ee3000 [ 4K] r--/rwx SM=COW /Users/USER/Library/Mobile Documents/PB4R74AA4J~com~junecloud~Notefile/*/*.notefile
shared memory 0000000101ee3000-0000000101ee4000 [ 4K] rw-/rw- SM=SHM
And then:
Thread 7 Crashed:
0 libsystem_c.dylib 0x0000000105157013 bcmp + 19
1 com.apple.CoreFoundation 0x0000000101bbf4b0 __CFBinaryPlistGetTopLevelInfo + 80
2 com.apple.CoreFoundation 0x0000000101bbf36d __CFTryParseBinaryPlist + 93
3 com.apple.CoreFoundation 0x0000000101bbede2 _CFPropertyListCreateWithData + 146
4 com.apple.CoreFoundation 0x0000000101bcbdb0 CFPropertyListCreateWithData + 112
5 com.apple.Foundation 0x0000000101568b89 +[NSPropertyListSerialization propertyListWithData:options:format:error:] + 94
6 com.junecloud.Notefile-Helper 0x000000010107ad06 -[JUNNoteDocument readFromData:ofType:error:] + 64
7 com.apple.AppKit 0x000000010268d507 -[NSDocument readFromURL:ofType:error:] + 546
8 com.apple.AppKit 0x000000010228e3c8 -[NSDocument _initWithContentsOfURL:ofType:error:] + 135
9 com.apple.AppKit 0x000000010228e074 -[NSDocument initWithContentsOfURL:ofType:error:] + 262
10 com.junecloud.Notefile-Helper 0x000000010107cad8 -[JUNSyncDocument initWithFileURL:] + 213
11 com.junecloud.Notefile-Helper 0x0000000101079ec7 -[NotefileAppDelegate documentForURL:] + 68
12 com.junecloud.Notefile-Helper 0x00000001010825cb -[JUNSyncManager documentForURL:] + 76
13 com.junecloud.Notefile-Helper 0x000000010107d43c -[JUNSyncInOperation main] + 1340
14 com.apple.Foundation 0x0000000101563cd2 __NSThread__main__ + 1345
15 libsystem_c.dylib 0x00000001051697a2 _pthread_start + 327
16 libsystem_c.dylib 0x00000001051561e1 thread_start + 13
Thread 7 crashed with X86 Thread State (64-bit):
rax: 0x0000000000000062 rbx: 0x000000000000007b rcx: 0x000000010c2be868 rdx: 0x0000000000000007
rdi: 0x0000000101d1e151 rsi: 0x0000000101ee2000 rbp: 0x000000010c2be810 rsp: 0x000000010c2be7b8
r8: 0x000000010c2be870 r9: 0x0000000000000000 r10: 0x00007ff841c28900 r11: 0x00007ff841c186d8
r12: 0x000000010c2be870 r13: 0x0000000101ee2000 r14: 0x000000010c2beb00 r15: 0x000000010c2be980
rip: 0x0000000105157013 rfl: 0x0000000000010202 cr2: 0x0000000101ee2000
Logical CPU: 2
Here's the relevant bit of code where it's crashing:
- (BOOL)readFromData:(NSData *)data ofType:(NSString *)typeName error:(NSError **)outError {
BOOL success = NO;
NSDictionary *dictionary = nil;
NSError *error = nil;
id plist = [NSPropertyListSerialization propertyListWithData:data
options:NSPropertyListImmutable format:NULL error:&error];
if (plist && [plist isKindOfClass:[NSDictionary class]]) {
dictionary = plist;
} else {
NSLog(#"Error opening document: %# %#",error,[error userInfo]);
if (outError != NULL) *outError = error;
}
// Then it does some things with the dictionary if it's not nil
return success;
}
Am I correct in thinking that NSPropertyListSerialization is just choking on some corrupt data, or is the problem more likely in my own code? If the problem is with NSPropertyListSerialization, is there anything I can do to prevent the app from crashing, and deal with the problem more appropriately?
If the problem is likely to be in my own code, what could I do to track down the cause? This would be much easier if I could duplicate the problem myself, but I've never seen this crash on my own devices, and obviously I can't expect a user to give me access to their iCloud account.
Update As requested, here's a bit of JUNSyncDocument. On iOS this is a UIDocument subclass, on Mac it's an NSDocument subclass.
- (id)initWithFileURL:(NSURL *)url {
#if TARGET_OS_IPHONE
self = [super initWithFileURL:url];
return self;
#else
NSError *error = nil;
if ([[NSFileManager defaultManager] fileExistsAtPath:[url path]]) {
if ((self = [super initWithContentsOfURL:url ofType:[self documentType] error:&error])) {
self.fileURL = url;
self.hasUndoManager = NO;
} else NSLog(#"Error initializing existing document: %# %#",url,error);
} else {
if ((self = [super initWithType:[self documentType] error:&error])) {
self.fileURL = url;
self.hasUndoManager = NO;
} else NSLog(#"Error initializing new document: %#",error);
}
return self;
#endif
}
This seems messy, and I wouldn't be surprised if I'm doing something stupid here. It works fine in most cases though. That gets called from NotefileAppDelegate:
- (JUNSyncDocument *)documentForURL:(NSURL *)url {
JUNNoteDocument *document = [[JUNNoteDocument alloc] initWithFileURL:url];
return document;
}
Which in turn is called by JUNSyncManager:
- (JUNSyncDocument *)documentForURL:(NSURL *)url {
return [self.delegate documentForURL:url];
}
Which is called by JUNSyncInOperation:
JUNSyncDocument *document = [self.delegate documentForURL:self.url];
I just realized I can get rid of that ridiculous delegate chain by using NSClassFromString, but I don't know if that will affect the problem or not.
Looking at the source of __CFTryParseBinaryPlist and __CFBinaryPlistGetTopLevelInfo, which are open source.
It looks like the memcmp (bcmp) that is crashing is at the very beginning where it checks first few bytes of the data for the binary plist header. It wouldn't get that far if CFDataGetLength was <= 8 bytes, so it's not a buffer underflow. It's possible CFDataGetBytePtr returned nil, but I don't see how that could happen if the length was > 8. Most likely, the data pointer has gone invalid.
I could tell more you posted the register contents from the crash report. Also, post the code of how it's creating the data (-[JUNSyncDocument initWithFileURL:] and -[NotefileAppDelegate documentForURL:].)
I have the exact same problem, (UIDocument & NSDocument subclasses, crash when accessing the plist data), although I'm using NSFileWrapper instead.
The mapped file path looks suspicious in your report (unless it's been anonymized by the OS), doesn't appear to be an actual file, but the query string. Isn't it that the NSMetadataQuery is returning incorrect results?
I have no solution so far, still searching.
update
I could debug this problem with a customer, generating custom builds with logging information. Here are my observations:
the crashes happen with different APIs, like NSPropertyListSerialization, CGImageSourceCreateWithURL, and possibly many other.
the accessed file is stored in the iCloud container
It has the following status:
fileExists = YES;
isUbiquitous = YES;
hasNonZeroSize = YES;
isDownloaded = NO;
So it appears as a regular file to most APIs, yet it is not available. When accessed, it makes the app crash.
- the accessed file can be within a file package that has the isDownloaded = YES, although the accessed file itself (within the file package) has isDownloaded = NO.
Work around: check the isDownloaded property for the file prior to accessing its contents. This property is checked using:
-[NSURL getResourceValue:&val forKey:NSURLUbiquitousItemIsDownloadedKey error:&error]
If like me you're using NSFileWrapper to read the UIDocument contents, then you need to have this check in:
-[UIDocument readFromURL:(NSURL *)url error:(NSError *__autoreleasing *)outError]
because the NSFileWrapper won't give you access to the file package NSURL that's needed.
I suspect a problem with the atomicity of iCloud when the document is created. It looks like the file package and its contents are not in sync for their downloaded status, just like if the document directory is made first, and its contents copied to it as 2 distinct operations.
Problem
This question may seem a bit long, but I try to give as much information as possible, since I am really staggered by this.
I am currently working an a library which should automate XML document parsing. But I am running into a problem now testing the library for the first time.
I have a library class called CSXDocumentLayout which represents the layout of a document. This class contains the private method - (NSError *)readLayoutDocument:(NSString *)fpath called from an init method.
/* MARK: Reading in Layouts */
- (NSError *)readLayoutDocument:(NSString *)fpath {
CSXDocumentLayout *layout;
CSXXMLParser *parser;
BOOL state;
layout = [CSXDocumentLayout layoutDocumentLayout];
parser = [[CSXXMLParser alloc] initWithDocumentLayouts:
[NSArray arrayWithObject:layout]];
parser.file = fpath;
state = [parser parse];
if(state == NO || parser.error != nil) {
return parser.error;
}
return nil;
}
This method will read in an XML document representing the layout of an other XML document. It is parsed by the class CSXXMLParser, which I want to test.
I create an object representing a layout document with +[CSXDocumentLayout layoutDocumentLayout]. This method is implemented in the category CSXDocumentLayout (CSXLayoutObject).
Below is my test file:
#import <Foundation/Foundation.h>
#import <CeasyXML.h>
int main(int argc, const char **argv) {
NSAutoreleasePool *pool = [NSAutoreleasePool new];
NSString *file;
file = [NSString stringWithUTF8String:__FILE__];
file = [file stringByDeletingLastPathComponent];
file = [file stringByAppendingPathComponent:#"Layout.xml"];
CSXDocumentLayout *layout;
NSError *error;
layout = [[CSXDocumentLayout alloc] initWithLayoutDocument:file
error:&error];
if(layout == nil) {
NSLog(#"Could not create layout: %#", error);
exit(0);
}
NSLog(#"Layout:\n%#", layout);
[pool release];
return 0;
}
This file compiles to a separate executable linked to my static library libceasyxml.a. Everything compiles just fine without any warnings.
But when I run it I get a unrecognized selector sent to class exception:
2012-05-02 16:59:47.620 TestApp[1887:a0f] +[CSXDocumentLayout layoutDocumentLayout]: unrecognized selector sent to class 0x1000064c8
2012-05-02 16:59:47.791 TestApp[1887:a0f] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[CSXDocumentLayout layoutDocumentLayout]: unrecognized selector sent to class 0x1000064c8'
*** Call stack at first throw:
(
0 CoreFoundation 0x00007fff83e47784 __exceptionPreprocess + 180
1 libobjc.A.dylib 0x00007fff84604f03 objc_exception_throw + 45
2 CoreFoundation 0x00007fff83ea11a0 __CFFullMethodName + 0
3 CoreFoundation 0x00007fff83e198ef ___forwarding___ + 751
4 CoreFoundation 0x00007fff83e15a38 _CF_forwarding_prep_0 + 232
5 TestApp 0x0000000100001512 -[CSXDocumentLayout(Private) readLayoutDocument:] + 49
6 TestApp 0x00000001000010d4 -[CSXDocumentLayout initWithLayoutDocument:error:] + 96
7 TestApp 0x0000000100001017 main + 179
8 TestApp 0x0000000100000f5c start + 52
9 ??? 0x0000000000000001 0x0 + 1
)
I find it very disturbing that I cannot call the class method +[CSXDocumentLayout(CSXLayoutObject) layoutDocumentLayout], though I can call both -[CSXDocumentLayout initWithLayoutDocument:error:], and -[CSXDocumentLayout(Private) readLayoutDocument:].
Research
I checked if the method is defined in the output files by running nm file and it is, well partly:
In libceasyxml.a, it is defined (nm libceasyxml.a)
...
libceasyxml.a(CSXDocumentLayout+CSXLayoutObject.o):
0000000000000100 t +[CSXDocumentLayout(CSXLayoutObject) classAttributeLayout]
00000000000020e0 s +[CSXDocumentLayout(CSXLayoutObject) classAttributeLayout].eh
000000000000056b t +[CSXDocumentLayout(CSXLayoutObject) documentElementLayout]
0000000000002180 s +[CSXDocumentLayout(CSXLayoutObject) documentElementLayout].eh
0000000000000402 t +[CSXDocumentLayout(CSXLayoutObject) layoutDocumentLayout]
0000000000002148 s +[CSXDocumentLayout(CSXLayoutObject) layoutDocumentLayout].eh
0000000000000200 t +[CSXDocumentLayout(CSXLayoutObject) layoutElementLayout]
0000000000002110 s +[CSXDocumentLayout(CSXLayoutObject) layoutElementLayout].eh
0000000000000000 t +[CSXDocumentLayout(CSXLayoutObject) nameAttributeLayout]
00000000000020b0 s +[CSXDocumentLayout(CSXLayoutObject) nameAttributeLayout].eh
0000000000002098 s EH_frame1
0000000000001c49 s LC0
...
In TestApp, it is NOT defined (nm TestApp), actually I can't find any method with the category name CSXLayoutObject.
...
0000000100001271 t -[CSXDocumentLayout setDocumentClassString:]
00000001000013a8 t -[CSXDocumentLayout setElements:]
0000000100001490 t -[CSXDocumentLayout setName:]
00000001000014db t -[CSXDocumentLayout(Private) readLayoutDocument:]
0000000100004060 t -[CSXElementList dealloc]
00000001000040b0 t -[CSXElementList elements]
...
EDIT: Fixed broken link
I suspect you have run into a known problem of categories embedded in static libraries.
If I am right, try to compile with the linker flags -ObjC (and if that is not enough, also -all_load) and your problem should disappear.
Even though the answer is already selected, I wish the solution to my issue was here, as simple as it may be. Be sure to check that your class is properly checked in the Target Membership field under the File Inspector pane. If you fail to do so then it's only natural to receive the unrecognized selector sent to class error.
I use HessianKit to communicate with server. In the situation of network or server down Hessian will throw exception, so I put every Hessian call in a #try ... #catch block. Everything worked fine until I upgraded Xcode from 3.2.2 to 3.2.3. I wrote the some testing code and found under Xcode 3.2.3, catch exception would be failed if the exception was thrown from a proxy object.
MyProxy.h:
#interface MyProxy : NSProxy {
}
#end
MyProxy.m:
#implementation MyProxy
- (id)init {
return self;
}
- (void)forwardInvocation:(NSInvocation *)invocation {
NSLog(#"Call method %#", NSStringFromSelector([invocation selector]));
[NSException raise:#"MyException" format:#"this is an exception"];
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
.....
}
#end
Code using MyProxy:
#try {
MyProxy *p = [[MyProxy alloc] init];
[p doSomething];
[p release];
}
#catch (NSException * e) {
NSLog(#"%#", e);
}
When these code build under xcode 3.2.2, the exception can be catched correctly. But under xcode 3.2.3, the program terminated after output following on the console:
2010-09-08 21:09:29.877 BriefCase[34651:40b] Call method doSomgthing
2010-09-08 21:09:29.879 BriefCase[34651:40b] *** Terminating app due to uncaught exception 'MyException', reason: 'this is an exception'
2010-09-08 21:09:29.880 BriefCase[34651:40b] Stack: (
45955152,
47113004,
45692683,
45692522,
151932,
45426420,
45423090,
9352,
4417860,
4421967,
4447550,
4429047,
4461016,
53399932,
45234332,
45230248,
4420129,
4453234,
8812,
8666
)
terminate called after throwing an instance of 'NSException'
Program received signal: “SIGABRT”.
What can I do?
I filed a bug with Apple, and the reply is:
It has been determined that this is a known issue, which is currently being investigated by engineering. This issue has been filed in our bug database under the original Bug ID# 7995323.
Maybe your project/target/executable settings have been messed up?
Is the "Enable Objective-C Exceptions" box ticked for your configuration/target/etc?
If it is, maybe you should file a bug with Apple here.
Hy everybody,
I have a screensaver made with obj-c and cocoa. Everything works fine under OsX 10.6.2 except the following.
Within my screensaver I have a WebView with some application running. When I try to call my objective-c app (the screensaver) via javascript, I get an error and the screensaver and the system preferences panel crash.
System Preferences[86666]
*** Terminating app due to uncaught exception 'NSInvalidArgumentException'
reason: '-[NSCFArray drain]: unrecognized selector sent to instance 0x20049b1e0'
*** Call stack at first throw:(
0 CoreFoundation 0x00007fff8123a444 __exceptionPreprocess + 180
1 libobjc.A.dylib 0x00007fff81f130f3 objc_exception_throw + 45
2 CoreFoundation 0x00007fff812931c0 +[NSObject(NSObject) doesNotRecognizeSelector:] + 0
3 CoreFoundation 0x00007fff8120d08f forwarding + 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_10IdentifierERNS_12PropertySlotE + 486
)
I know this looks like some memory leak, but as you will see in the code, I really have nearly no objects allocated.
This only happens, when I start the screensaver with the "Test" button from the screensaver system prefs.
When I start the screensaver via terminal or if it starts automatically, the same action (calling obj-c from javascript) works fine.
Maybe someone has any idea, where the error could come from. Here is some code from the implementation:
#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
I hope that's enough code for you to see some problems / solutions.
I would really appreciaty any answers.
Somehow an NSCFArray (NSMutableArray) is being sent a "drain" message that's meant for an NSAutoreleasePool.
You might be able to get a bit more info on what the array is by implementing the drain method for NSMutableArray, so you can trap the now-recognized selector and print out the contents of the array object. Try adding this somewhere in your code:
#interface NSMutableArray (drain)
- (void) drain;
#end
#implementation NSMutableArray (drain)
- (void) drain
{
NSLog(#"drain message received by object: %#", self);
}
#end
If you don't see any messages show up in the Console, try changing the "NSMutableArray" in the above code to "NSObject".
One thing to be aware of is that when you start the screensaver via the "Test" button in System Prefs, you actually have 2 instances of your screensaver view running in the same process' address space on different threads. One (with isPreview==YES) is the little preview in the SysPrefs window (which continues running even when the full-screen version is started), and the other one is the full-screen version. They are both running in the SysPrefs.app process. So, you have to be careful to check all Notifications/etc. to see if they are coming from the view instance you expect.
I don't see any obvious problems from a quick glance at the code you posted, but it may be somewhere else. Do you use Notifications anywhere?
I put a similar webview-in-a-screensaver project on github at http://github.com/kelan/WikiWalker, where I initially had some similar problems (though I wasn't using any javascript stuff). It's not perfect code, but might help. I also did some tricks to forward notifications to the main thread (for drawing) in a . See the "Threaded Notification Support" parts of WWScreenSaverView.{h,m}.
Something to try:
Open up a terminal window and enter the following line to run System Preferences with NSZombieEnabled:
env NSZombieEnabled=YES "/Applications/System Preferences.app/Contents/MacOS/System Preferences"
Perform the steps that lead to the crash.
Run the Console app, set the filter in the upper right to "System Preferences", and look for NSZombie messages.
Hope this helps!
Just to troubleshoot, did you try not releasing the WebView?
Also, maybe set the WebView's delegates to nil before releasing it first?