I'm making a macOS app and I've got this code used to rotate an image:
didSet {
let degreesToRotate = oldValue - phoneXRotation
phoneImageView.rotate(byDegrees: CGFloat(degreesToRotate))
degreesLabel.isHidden = false
degreesLabel.stringValue = "\(phoneXRotation)"
if phoneXRotation > 70 {
statusLabel.stringValue = "Phone orientation: Right Tilt"
} else if phoneXRotation < -70 {
statusLabel.stringValue = "Phone orientation: Left Tilt"
} else {
statusLabel.stringValue = "Phone orientation: Flat"
}
}
The app will randomly crash in an lldb error. If I comment out the third line that rotate the phone, I have no problems. The conversion from Int to CGFloat shouldn't crash. Any ideas?
Here is the stack trace:
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
frame #0: 0x00007fff8989b44e AppKit`-[NSApplication _crashOnException:] + 109
frame #1: 0x00007fff8996ea32 AppKit`__37+[NSDisplayCycle currentDisplayCycle]_block_invoke.31 + 708
frame #2: 0x00007fff8ba62d37 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
frame #3: 0x00007fff8ba62ca7 CoreFoundation`__CFRunLoopDoObservers + 391
frame #4: 0x00007fff8ba436d9 CoreFoundation`__CFRunLoopRun + 873
frame #5: 0x00007fff8ba43114 CoreFoundation`CFRunLoopRunSpecific + 420
frame #6: 0x00007fff8afa3ebc HIToolbox`RunCurrentEventLoopInMode + 240
frame #7: 0x00007fff8afa3cf1 HIToolbox`ReceiveNextEventCommon + 432
frame #8: 0x00007fff8afa3b26 HIToolbox`_BlockUntilNextEventMatchingListInModeWithFilter + 71
frame #9: 0x00007fff8953ca54 AppKit`_DPSNextEvent + 1120
frame #10: 0x00007fff89cb87ee AppKit`-[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 2796
frame #11: 0x00007fff895313db AppKit`-[NSApplication run] + 926
frame #12: 0x00007fff894fbe0e AppKit`NSApplicationMain + 1237
* frame #13: 0x000000010000691d Dataspeed Mac Project`main at AppDelegate.swift:12
frame #14: 0x00007fffa11f1235 libdyld.dylib`start + 1
frame #15: 0x00007fffa11f1235 libdyld.dylib`start + 1
My code below creates a Texture from an image name from file lookups in a plist like (Duck1_1,Duck1_2,Duck1_3,etc) it loops through them then adds them to a mutable array. The mutable array is then used to animate with the textures stored and played with an SKAction. This works fine for the animations until 30-40 are played then it crashes and says too many files open and it can't open the files anymore. Any ideas on how to stop this from happening?
thanks
//loadPlistForAnimationWithNames function
NSMutableArray *animationToReturn = [NSMutableArray array];
for(NSString *frameNumber in animationFrameNumbers) {
NSString *frameName = [NSString stringWithFormat:#"%#%#.png",animationFramePrefix,frameNumber];
if(frameName!=nil)
[animationToReturn addObject:[SKTexture textureWithImageNamed:frameName]];
}
SKAction *action=nil;
action=[SKAction animateWithTextures:animationToReturn timePerFrame:animationDelay resize:NO restore:NO];
SKAction *repeatAction=nil;
repeatAction = [SKAction repeatAction:action count:1];
[animationToReturn removeAllObjects];
action=nil;
animationFrameNumbers=nil;
return repeatAction;
//Call to loadPlistForAnimationWithNames and run animation
SKAction *action=[animalObject loadPlistForAnimationWithNames:#"duckAnim1" andClassName:NSStringFromClass([self class])];
SKSpriteNode *sprite = [SKSpriteNode spriteNodeWithImageNamed:#"Duck1_1"];
sprite.position=CGPointMake(self.frame.size.width/2, self.frame.size.height/2);
sprite.size=self.frame.size;
[sprite setZPosition:3];
[self addChild:sprite];
[sprite runAction:action];
Here is the Xcode error I get when it crashes:
: ImageIO: CGImageReadCreateDataWithMappedFile 'open' failed '/private/var/mobile/Containers/Bundle/Application/782E98C3-0452-43EF-BF4D-401773D5FDCD/WildNoizesLite.app/Duck1_1.png'
error = 24 (Too many open files)
Backtrace:
* thread #1: tid = 0x301c4, 0x00000001944ab270 libsystem_kernel.dylib__pthread_kill + 8, queue = 'com.apple.main-thread', stop reason = signal SIGABRT
frame #0: 0x00000001944ab270 libsystem_kernel.dylib__pthread_kill + 8
frame #1: 0x0000000194549170 libsystem_pthread.dylibpthread_kill + 112
frame #2: 0x0000000194422b18 libsystem_c.dylibabort + 112
frame #3: 0x00000001934b5418 libc++abi.dylibabort_message + 116
frame #4: 0x00000001934d4b8c libc++abi.dylibdefault_terminate_handler() + 304
frame #5: 0x0000000193ce83c0 libobjc.A.dylib_objc_terminate() + 128
frame #6: 0x00000001934d1bb4 libc++abi.dylibstd::__terminate(void (*)()) + 16
frame #7: 0x00000001934d173c libc++abi.dylib__cxa_rethrow + 144
frame #8: 0x0000000193ce8294 libobjc.A.dylibobjc_exception_rethrow + 44
frame #9: 0x0000000181ef5384 CoreFoundationCFRunLoopRunSpecific + 572
frame #10: 0x000000018b94b6fc GraphicsServicesGSEventRunModal + 168
frame #11: 0x0000000186af2f40 UIKitUIApplicationMain + 1488
* frame #12: 0x0000000100174fa0 Wild Noizesmain(argc=1, argv=0x000000016fd6f9d8) + 124 at main.m:16
frame #13: 0x0000000194392a08 libdyld.dylib`start + 4
The score component of the game was operating normally, but recently I've implemented GameKit and it is adding more to the score than what is in the code.
else if key == kCollectableStarKey {
sprite = Collectable(texture: atlas.textureNamed("StarGold"))
(sprite as! Collectable).collectionSound = Sound(named: "Collect.caf")
(sprite as! Collectable).pointValue = 3
(sprite as! Collectable).delegate = self.delegate
sprite.physicsBody = SKPhysicsBody(circleOfRadius: sprite.size.width * 0.3)
sprite.physicsBody?.categoryBitMask = kCollectableCategory
sprite.physicsBody?.dynamic = false
self.addChild(sprite)
}
else if key == kBoneKey {
sprite = Collectable(texture: atlas.textureNamed("FishBone"))
(sprite as! Collectable).collectionSound = Sound(named: "fail.caf")
(sprite as! Collectable).pointValue = -2
(sprite as! Collectable).delegate = self.delegate
sprite.physicsBody = SKPhysicsBody(circleOfRadius: sprite.size.width * 0.3)
sprite.physicsBody?.categoryBitMask = kCollectableCategory
sprite.physicsBody?.dynamic = false
self.addChild(sprite)
}
Here is the Collectable protocol
protocol CollectableDelegate {
func wasCollected(collectable: Collectable)
}
class Collectable: SKSpriteNode {
var delegate: CollectableDelegate!
var collectionSound: Sound!
var pointValue: Int = 0
func collect() {
self.collectionSound.play()
self.runAction(SKAction.removeFromParent())
if let delegate = self.delegate {
self.delegate.wasCollected(self)
}
}
}
and the Bone Protocol:
protocol BoneDelegate {
func wasGathered(collectable: boneCollectable)
}
class boneCollectable: SKSpriteNode {
var delegate: BoneDelegate!
var gatherSound: Sound!
var boneValue: Int = 0
func gather() {
self.gatherSound.play()
self.runAction(SKAction.removeFromParent())
if let delegate = self.delegate {
self.delegate.wasGathered(self)
}
}
}
I've uploaded a video of the problem as well:
Video here
So it appears that the problem was with the physics body for my main sprite.
// Setup physics body with path.
let offsetX = self.frame.size.width * self.anchorPoint.x;
let offsetY = self.frame.size.height * self.anchorPoint.y;
var planeBodyPath = CGPathCreateMutable();
CGPathMoveToPoint(planeBodyPath, nil, 19 - offsetX, 0 - offsetY);
CGPathAddLineToPoint(planeBodyPath, nil, 40 - offsetX, 50 - offsetY);
CGPathAddLineToPoint(planeBodyPath, nil, 14 - offsetX, 40 - offsetY);
CGPathAddLineToPoint(planeBodyPath, nil, 38 - offsetX, 11 - offsetY);
CGPathAddLineToPoint(planeBodyPath, nil, 11 - offsetX, 20 - offsetY);
CGPathAddLineToPoint(planeBodyPath, nil, 5 - offsetX, 20 - offsetY);
CGPathAddLineToPoint(planeBodyPath, nil, 36 - offsetX, 28 - offsetY);
CGPathAddLineToPoint(planeBodyPath, nil, 20 - offsetX, 27 - offsetY);
CGPathAddLineToPoint(planeBodyPath, nil, 20 - offsetX, 7 - offsetY);
CGPathAddLineToPoint(planeBodyPath, nil, 54 - offsetX, 13 - offsetY);
CGPathAddLineToPoint(planeBodyPath, nil, 70 - offsetX, 31 - offsetY);
CGPathAddLineToPoint(planeBodyPath, nil, 70 - offsetX, 40 - offsetY);
CGPathAddLineToPoint(planeBodyPath, nil, 69 - offsetX, 55 - offsetY);
CGPathCloseSubpath(planeBodyPath);
self.physicsBody = SKPhysicsBody(polygonFromPath: planeBodyPath)
After deleting this and adding this:
// Setup physics body with path.
let offsetX = self.frame.size.width * self.anchorPoint.x;
let offsetY = self.frame.size.height * self.anchorPoint.y;
var planeBodyPath = CGPathCreateMutable();
CGPathMoveToPoint(planeBodyPath, nil, 64 - offsetX, 11 - offsetY);
CGPathAddLineToPoint(planeBodyPath, nil, 77 - offsetX, 42 - offsetY);
CGPathAddLineToPoint(planeBodyPath, nil, 75 - offsetX, 10 - offsetY);
CGPathAddLineToPoint(planeBodyPath, nil, 38 - offsetX, 30 - offsetY);
CGPathAddLineToPoint(planeBodyPath, nil, 11 - offsetX, 54 - offsetY);
CGPathAddLineToPoint(planeBodyPath, nil, 5 - offsetX, 57 - offsetY);
CGPathAddLineToPoint(planeBodyPath, nil, 36 - offsetX, 61 - offsetY);
CGPathAddLineToPoint(planeBodyPath, nil, 76 - offsetX, 27 - offsetY);
CGPathAddLineToPoint(planeBodyPath, nil, 74 - offsetX, 7 - offsetY);
CGPathAddLineToPoint(planeBodyPath, nil, 54 - offsetX, 13 - offsetY);
CGPathAddLineToPoint(planeBodyPath, nil, 14 - offsetX, 31 - offsetY);
CGPathAddLineToPoint(planeBodyPath, nil, 27 - offsetX, 62 - offsetY);
CGPathAddLineToPoint(planeBodyPath, nil, 69 - offsetX, 55 - offsetY);
CGPathCloseSubpath(planeBodyPath);
self.physicsBody = SKPhysicsBody(polygonFromPath: planeBodyPath)
All worked normally with the scoring system. I have no clue as to why it causes the error however.
I maintain a legacy OSX application that instead of calling NSApplicationMain() to process events, runs an event loop on the main thread that looks like this:
...
do {
event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:distantPast
inMode: NSDefaultRunLoopMode dequeue:YES];
[self handleEvent:event];
}
} while(event != nil);
...
Everything works until I activate the application's menu. Once the menu is active, nextEventMatchingMask blocks forever. I can see in lldb that osx starts another modal event loop (carbon?) which causes the cococa's one to block:
frame #2: 0x00007fff92748eb4 CoreFoundation`__CFRunLoopServiceMachPort + 212
frame #3: 0x00007fff9274837b CoreFoundation`__CFRunLoopRun + 1371
frame #4: 0x00007fff92747bd8 CoreFoundation`CFRunLoopRunSpecific + 296
frame #5: 0x00007fff8c11c56f HIToolbox`RunCurrentEventLoopInMode + 235
frame #6: 0x00007fff8c11c2ea HIToolbox`ReceiveNextEventCommon + 431
frame #7: 0x00007fff8c17568a HIToolbox`AcquireNextEventInMode + 54
frame #8: 0x00007fff8c172e2b HIToolbox`IsUserStillTracking(MenuSelectData*, unsigned char*) + 173
frame #9: 0x00007fff8c172a41 HIToolbox`TrackMenuCommon(MenuSelectData&, unsigned char*) + 1661
frame #10: 0x00007fff8c1803c1 HIToolbox`MenuSelectCore(MenuData*, Point, double, unsigned int, OpaqueMenuRef**, unsigned short*) + 510
frame #11: 0x00007fff8c1800fe HIToolbox`_HandleMenuSelection2 + 446
frame #12: 0x00007fff8a9a8de0 AppKit`_NSHandleCarbonMenuEvent + 277
frame #13: 0x00007fff8a8dfd0d AppKit`_DPSNextEvent + 1828
frame #14: 0x00007fff8a8def68 AppKit`-[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 346
Is there anything I can do to prevent this behaviour ?
Unfortunately I cannot rewrite the application so I need a quick and dirty solution to run the main thread while the menu is active.
I have overridden the adjustScroll: method within the documentView of my NSScrollView in order to investigate how to use it to constrain large scroll movements.
What I am seeing is that for each scroll "event" prior to calling the normal scrolling notifications (which I am listening to elsewhere) it calls the adjustScroll method twice(!) and the first time it always seems to call it with a rectangle of size (1,1) - strange?
My method is as follows:
override func adjustScroll(newVisible: NSRect) -> NSRect {
println("Document: adjustScroll: \(newVisible)")
return super.adjustScroll(newVisible)
}
With the results of the println being as follows:
Document: adjustScroll: (1.0, 0.0, 1.0, 1.0)
Document: adjustScroll: (1.0, 0.0, 1436.0, 855.0)
I only have one "Document" object in my view hierarchy and there is only one scrollView...perplexed.
EDIT
I have printed out the stack within the adjustScroll call. The relevant parts are as follows for each of the two calls:
(1.0,1.0)
[0 Grid 0x000000010007d697 _TToFC4Grid8Document12adjustScrollfS0_FVSC6CGRectS1_ + 87,
1 AppKit 0x00007fff84368070 -[_NSScrollingConcurrentMainThreadSynchronizer _scrollToCononicalOrigin] + 655,
2 AppKit 0x00007fff84367a51 -[_NSScrollingConcurrentMainThreadSynchronizer _synchronize:completionHandler:] + 167,
3 AppKit 0x00007fff84367963 __80-[_NSScrollingConcurrentMainThreadSynchronizer initWithSharedData:constantData:]_block_invoke + 144,
4 libdispatch.dylib 0x000000010057ed43 _dispatch_client_callout + 8,
...
(1436.0, 855.0)
[0 Grid 0x000000010007d697 _TToFC4Grid8Document12adjustScrollfS0_FVSC6CGRectS1_ + 87,
1 AppKit 0x00007fff84206f8d -[NSClipView _scrollTo:animateScroll:flashScrollerKnobs:] + 1302,
2 AppKit 0x00007fff84368209 -[_NSScrollingConcurrentMainThreadSynchronizer _scrollToCononicalOrigin] + 1064,
3 AppKit 0x00007fff84367a51 -[_NSScrollingConcurrentMainThreadSynchronizer _synchronize:completionHandler:] + 167,
4 AppKit 0x00007fff84367963 __80-[_NSScrollingConcurrentMainThreadSynchronizer initWithSharedData:constantData:]_block_invoke + 144,
5 libdispatch.dylib 0x000000010057ed43 _dispatch_client_callout + 8,
...