Screensaver, initWithFrame:isPreview: is being called on the wrong class

"Unrecognized selector -[MazieSaver.Maze initWithFrame:isPreview:]"


Trying to run a screensaver app ( OS X 10.10, XCode 7.01, Swift 2 ) and am getting the above crash, unsurprising as the indicated class does not have that selector.


This is wrong class entirely, the screensaver should be calling the selector on my MazieSaver.MazieSaverView class, which is the class I have listed in the plist file as the "Principal Class" (as set by the template when I created the project).


I've done some searching but drawn a blank so far, can anyone help?

Answered by JiggyWig in 70326022

I did not get to the bottom of this, but I got it to work by rebuilding the project from scratch. I didn't change any code, just created a blank screensaver and added my code back in piece by piece, stubbing as necessary and verifying it still worked as a screensaver step by step until I had everything back in. Then I rebuilt the test harness target, and that was fine too. Comparing the old & new projects did not show any obvious discrepancies. I have no idea what went wrong, and perhaps never will...

Could I trouble you to post the call stack at the moment of the crash?

Yes of course:


Process: System Preferences [6051]

Path: /Applications/System Preferences.app/Contents/MacOS/System Preferences

Identifier: com.apple.systempreferences

Version: 14.0 (14.0)

Build Info: SystemPrefsApp-281000000000000~3

Code Type: X86-64 (Native)

Parent Process: ??? [1]

Responsible: System Preferences [6051]

User ID: 501



PlugIn Path: /Users/USER/Library/Screen Savers/MazieSaver.saver/Contents/Frameworks/libswiftCore.dylib

PlugIn Identifier: libswiftCore.dylib

PlugIn Version: 2.0 (700.0.59)



Date/Time: 2015-09-30 02:32:51.911 +0100

OS Version: Mac OS X 10.10.5 (14F27)

Report Version: 11


Time Awake Since Boot: 79000 seconds

Time Since Wake: 20000 seconds



Crashed Thread: 0 Dispatch queue: com.apple.main-thread



Exception Type: EXC_CRASH (SIGABRT)

Exception Codes: 0x0000000000000000, 0x0000000000000000



Application Specific Information:

com.apple.preference.desktopscreeneffect v.5.1 (Desktop & Screen Saver)

objc[6051]: GC: forcing GC OFF because OBJC_DISABLE_GC is set

abort() called

Unrecognized selector -[MazieSaver.Maze initWithFrame:isPreview:]




Application Specific Signatures:

MazieSaver



Thread 0 Crashed:: Dispatch queue: com.apple.main-thread

0 libsystem_kernel.dylib 0x00007fff9bb87286 __pthread_kill + 10

1 libsystem_c.dylib 0x00007fff9aa439b3 abort + 129

2 libswiftCore.dylib 0x0000000115f18544 swift::fatalError(char const*, ...) + 212

3 libswiftCore.dylib 0x0000000115f19726 -[SwiftObject doesNotRecognizeSelector:] + 86

4 com.apple.CoreFoundation 0x00007fff92bcae24 ___forwarding___ + 1028

5 com.apple.CoreFoundation 0x00007fff92bca998 _CF_forwarding_prep_0 + 120

6 com.apple.ScreenSaver 0x00007fff929b6367 -[ScreenSaverModules loadModule:frame:isPreview:] + 974

7 com.apple.preference.desktopscreeneffect.screeneffects 0x000000010ec13315 0x10ec0a000 + 37653

8 com.apple.preference.desktopscreeneffect.screeneffects 0x000000010ec1377c 0x10ec0a000 + 38780

9 com.apple.preference.desktopscreeneffect.screeneffects 0x000000010ec14b7c 0x10ec0a000 + 43900

10 com.apple.preference.desktopscreeneffect.screeneffects 0x000000010ec14fe5 0x10ec0a000 + 45029

11 com.apple.AppKit 0x00007fff9492b0c5 -[NSCollectionViewItem _setSelectedWithoutNotification:] + 35

12 com.apple.CoreFoundation 0x00007fff92ba1705 __53-[__NSArrayM enumerateObjectsWithOptions:usingBlock:]_block_invoke + 133

13 com.apple.CoreFoundation 0x00007fff92ba0e09 -[__NSArrayM enumerateObjectsWithOptions:usingBlock:] + 313

14 com.apple.AppKit 0x00007fff9492b9e7 -[NSCollectionView _applySelectionIndexes:toItems:] + 91

15 com.apple.AppKit 0x00007fff9492b75e -[NSCollectionView _selectObjectsAtIndexes:avoidsEmptySelection:] + 443

16 com.apple.AppKit 0x00007fff94dac0bc -[NSCollectionView mouseDown:] + 649

17 com.apple.AppKit 0x00007fff94691cfb forwardMethod + 126

18 com.apple.AppKit 0x00007fff94691cfb forwardMethod + 126

19 com.apple.AppKit 0x00007fff94d0a2dc -[NSWindow _reallySendEvent:isDelayedEvent:] + 14125

20 com.apple.AppKit 0x00007fff94699c86 -[NSWindow sendEvent:] + 470

21 com.apple.systempreferences 0x0000000107f6cb12 0x107f65000 + 31506

22 com.apple.AppKit 0x00007fff94696212 -[NSApplication sendEvent:] + 2504

23 com.apple.systempreferences 0x0000000107f6bf7b 0x107f65000 + 28539

24 com.apple.AppKit 0x00007fff945bfb68 -[NSApplication run] + 711

25 com.apple.AppKit 0x00007fff9453c244 NSApplicationMain + 1832

26 libdyld.dylib 0x00007fff97c665c9 start + 1

Additional: I'm missing something important. I rejigged the code to make the Maze class a nested class inside the MazieSaverView class (yeuch!), and the ScreenSaver app is STILL calling the selector on it.



Process: System Preferences [6909]

Path: /Applications/System Preferences.app/Contents/MacOS/System Preferences

Identifier: com.apple.systempreferences

Version: 14.0 (14.0)

Build Info: SystemPrefsApp-281000000000000~3

Code Type: X86-64 (Native)

Parent Process: ??? [1]

Responsible: System Preferences [6909]

User ID: 501



PlugIn Path: /Users/USER/Library/Screen Savers/MazieSaver.saver/Contents/Frameworks/libswiftCore.dylib

PlugIn Identifier: libswiftCore.dylib

PlugIn Version: 2.0 (700.0.59)



Date/Time: 2015-09-30 08:49:07.820 +0100

OS Version: Mac OS X 10.10.5 (14F27)

Report Version: 11

Time Awake Since Boot: 100000 seconds

Time Since Wake: 42000 seconds



Crashed Thread: 0 Dispatch queue: com.apple.main-thread



Exception Type: EXC_CRASH (SIGABRT)

Exception Codes: 0x0000000000000000, 0x0000000000000000



Application Specific Information:

com.apple.preference.desktopscreeneffect v.5.1 (Desktop & Screen Saver)

objc[6909]: GC: forcing GC OFF because OBJC_DISABLE_GC is set

abort() called

Unrecognized selector -[_TtCC10MazieSaver14MazieSaverView4Maze initWithFrame:isPreview:]




Application Specific Signatures:

MazieSaver



Thread 0 Crashed:: Dispatch queue: com.apple.main-thread

0 libsystem_kernel.dylib 0x00007fff9bb87286 __pthread_kill + 10

1 libsystem_c.dylib 0x00007fff9aa439b3 abort + 129

2 libswiftCore.dylib 0x000000010fa57544 swift::fatalError(char const*, ...) + 212

3 libswiftCore.dylib 0x000000010fa58726 -[SwiftObject doesNotRecognizeSelector:] + 86

4 com.apple.CoreFoundation 0x00007fff92bcae24 ___forwarding___ + 1028

5 com.apple.CoreFoundation 0x00007fff92bca998 _CF_forwarding_prep_0 + 120

6 com.apple.ScreenSaver 0x00007fff929b6367 -[ScreenSaverModules loadModule:frame:isPreview:] + 974

7 com.apple.preference.desktopscreeneffect.screeneffects 0x0000000109543315 0x10953a000 + 37653

8 com.apple.preference.desktopscreeneffect.screeneffects 0x000000010954377c 0x10953a000 + 38780

9 com.apple.preference.desktopscreeneffect.screeneffects 0x0000000109544b7c 0x10953a000 + 43900

10 com.apple.preference.desktopscreeneffect.screeneffects 0x0000000109544fe5 0x10953a000 + 45029

11 com.apple.AppKit 0x00007fff9492b0c5 -[NSCollectionViewItem _setSelectedWithoutNotification:] + 35

12 com.apple.CoreFoundation 0x00007fff92ba1705 __53-[__NSArrayM enumerateObjectsWithOptions:usingBlock:]_block_invoke + 133

13 com.apple.CoreFoundation 0x00007fff92ba0e09 -[__NSArrayM enumerateObjectsWithOptions:usingBlock:] + 313

14 com.apple.AppKit 0x00007fff9492b9e7 -[NSCollectionView _applySelectionIndexes:toItems:] + 91

15 com.apple.AppKit 0x00007fff9492b75e -[NSCollectionView _selectObjectsAtIndexes:avoidsEmptySelection:] + 443

16 com.apple.AppKit 0x00007fff94dac0bc -[NSCollectionView mouseDown:] + 649

17 com.apple.AppKit 0x00007fff94691cfb forwardMethod + 126

18 com.apple.AppKit 0x00007fff94691cfb forwardMethod + 126

19 com.apple.AppKit 0x00007fff94d0a2dc -[NSWindow _reallySendEvent:isDelayedEvent:] + 14125

20 com.apple.AppKit 0x00007fff94699c86 -[NSWindow sendEvent:] + 470

21 com.apple.systempreferences 0x000000010310db12 0x103106000 + 31506

22 com.apple.AppKit 0x00007fff94696212 -[NSApplication sendEvent:] + 2504

23 com.apple.systempreferences 0x000000010310cf7b 0x103106000 + 28539

24 com.apple.AppKit 0x00007fff945bfb68 -[NSApplication run] + 711

25 com.apple.AppKit 0x00007fff9453c244 NSApplicationMain + 1832

26 libdyld.dylib 0x00007fff97c665c9 start + 1

Both crashes are identical, so maybe you should go back to the simpler class arrangement.


A few thoughts:

• Did you make sure that all the classes in your nib are correct?

• Maybe implement initWithFrame(isPreview:) in your Maze class to see in the Debug Navigator what code is calling it.

A couple quick things to check:


  1. Are you exporting the class you've set as the principal class using @objc (YourClassNameHere)
  2. Are you building the project with the "Embedded Content Contains Swift Code" set to YES in the bundle's build settings?


I haven't actually built a functional screen saver yet, but doing those two things at least let me get to the point where the bundle appeared to be loaded. Just tossing out some ideas and things to check...

FYI, I haven't ever tried to make a screen saver either…

I had some time to look at this a bit more. I was able to get this working. Ignore my #1 in my other post, I think that's a red herring. I had typed the wrong principalClass name (at first I didn't have the module name, and then I puth the wrong module name in). #2 does appear to be required. With that set, the correct fully qualified module name, and then the appropriate inheritance from ScreenSaverView, then I was able to do a simple screen saver based off of the template code that just filled the screen with a solid color in the drawRect method.

I have been experimenting with this some more. Here is the wholly bizarre state of affairs


1. If I have a single class in the project, and it's inheriting from ScreenSaverView (and I set Embedded Swift Code, Code Signing and Principal class correctly), it works I can do some simple drawing.

2. If I add in any additional swift classes the View class gets ignored and the ScreenSaver App tries to call the selector on one of them.

3. If I derive these classes from NSObject, I don't get a crash (probably just happily swallowing a null selector now), but it still fails to init the View Class and I get the message about the plugin being incompatible.

4. I also tried making my classes structs, but I couldn't do them all because I have some some actual polymorphism I need to retain, so I don't know..


So then I tried a Screensaver someone else wrote called Timesaver I think. It was a single View class so I refactored it a bit so it has a couple of switft classes. This project works fine, in all the arrangements I tried.


I have pored over the project files and cannot see any configuration differences.


I am somewhat lost. This is annoying, because I was really enjoying using swift and this is a big spanner in the works.


What am I missing?....

For a case like this it might be best to file a Developer Technical Support request and the folks there can work one on one with you specifically to get this to work. http://developer.apple.com/support/technical.

That's not a bad idea, I've never used any of my free incidents, maybe now is the time. I'm going to try over on Stack Overflow first though. :-)

Accepted Answer

I did not get to the bottom of this, but I got it to work by rebuilding the project from scratch. I didn't change any code, just created a blank screensaver and added my code back in piece by piece, stubbing as necessary and verifying it still worked as a screensaver step by step until I had everything back in. Then I rebuilt the test harness target, and that was fine too. Comparing the old & new projects did not show any obvious discrepancies. I have no idea what went wrong, and perhaps never will...

Unfortnuatly, the suggested fix to rebuild the project from scratch didn't work for me. What did end up working was adding the switft module to the principal class. For example, instead of the principal class being "MazieSaverView", it should be the full "MazieSaver.MazieSaverView". Everything worked for me after this.

My project stopped working after I added some existing .swift files to it.


I was able to fix it by dragging my ScreenSaverView subclass (the principle class) up in Target - Build Phases - Compile Sources so it gets compiled first.

Seems the engine would always try to send the initWithFrame:isPreview: message to the class on top of the compile sources list regardless of the principal class setting (Swift 3 / XCode 8.3.3).

My experience is, that you cannot switch between two savers that are written in Swift. That got me confused in the beginning of developing https://EmojiSaver.eu, because I had multiple versions of the same saver deployed to "~/Library/Screen Savers/".


It is always a good idea to keep "~/Library/Screen Savers/" clean and to restart the System Preferences App before expecting any changes to get recognized.


Currently there is another problem when using High Sierra and Swift screen savers. I dig into it here: https://github.com/klaas/QlaasSwiftScreenSaver and the Aerial saver has the same issue as well: https://github.com/JohnCoates/Aerial/pull/420

I encountered the same error. I fixed it by moving the screensaver view file to the top of the Compile Sources list.


Go to your screensaver target, Build Phases, and in Compile Sources drag the view file to the top of the list. My screen saver worked fine after that.

Screensaver, initWithFrame:isPreview: is being called on the wrong class
 
 
Q