Continuing to try to understand blocks in Objective-C. I have the following function:
typedef void(^TAnimation)(void);
TAnimation makeAnim(UIView *aView, CGFloat angle, CGFloat x, CGFloat y,
CGFloat width, CGFloat height, UIInterfaceOrientation uiio) {
return Block_copy(^{
aView.transform = CGAffineTransformMakeRotation(angle);
aView.frame = CGRectMake(x, y, width, height);
[UIApplication sharedApplication].statusBarOrientation = uiio;
});
}
When I try to do the following:
TAnimation f = makeAnim( ... );
f();
I get an EXC_BAD_ACCESS. However, if I do the following instead:
TAnimation f = makeAnim( ... );
[UIView animateWithDuration:0 delay:0 options:0 animations:f completion:NULL];
it works fine. What is the problem in the first scenario?
Try using NSZombieEnabled. When you deallocate an object it turns into a NSZombie, so when you call it, it throws an exception. To activate NSZombieEnabled, open the info window for the executable, go under Arguments and enter NSZombieEnable with a value of yes under "Variables to be set in the Environment:".
A very simple block-based example like this:
#import <Foundation/Foundation.h>
typedef void(^printerBlock)(void);
printerBlock createPrinter(NSString *thingToPrint) {
return Block_copy(^{
NSLog(#"Printing: %#", thingToPrint);
});
}
int main (int argc, char const* argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
printerBlock pb = createPrinter(#"Testing string.");
pb();
[pool drain];
return 0;
}
prints this out:
2011-10-22 21:28:14.316 blocker[12834:707] Printing: Testing string.
when I compile the program as "blocker", so there must be some other reason the direct block invocation is failing. Some reasons might be because the view you're passing in is being over-released, in which case the NSZombieEnabled advice will help you out.
If it's not the case that the view is being over-released, then you'll want to run this in the debugger and figure out exactly where things are falling over.
We'll probably have to see more of your code in order to figure out what's actually breaking.
Related
I'm stumped trying to debug an issue on iOS that seems to only occur with Release builds which seems to implicate that the optimizer is doing something that isn't playing nicely with my code. The code that crashes is some code that is serializing some binary data into a NSMutableData instance as follows.
[_data increaseLengthBy:sizeof(CFSwappedFloat64)];
*((CFSwappedFloat64 *)[self pointerAtOffset]) = CFConvertFloat64HostToSwapped(value);
_offset += sizeof(CFSwappedFloat64);
_data is a NSMutableData instance. pointerAtOffset and the init method for this class is defined as follows.
- (unsigned char *)pointerAtOffset {
return ((unsigned char *)_data.mutableBytes) + _offset;
}
- (id)init {
if( self = [super init] ) {
_data = [[NSMutableData alloc] initWithCapacity:1028];
_offset = 0;
}
return self;
}
Now the strange thing is that if I add a NSLog print statement, it fixes the bug.
[_data increaseLengthBy:sizeof(CFSwappedFloat64)];
NSLog(#"%d - %d", (int)_data.mutableBytes, _offset);
*((CFSwappedFloat64 *)[self pointerAtOffset]) = CFConvertFloat64HostToSwapped(value);
_offset += sizeof(CFSwappedFloat64);
Any ideas what might be causing this? It's kind of unnerving to deploy code that works because of a NSLog statement.
This reminds me of the armv6 Thumb instruction problems. If you change your debug build settings to optimize to Fastest,Smallest and it crashes, then that is your problem.
I have a flood fill function:
-(void) fillArea :(int) fillNum x:(int) xSpot y:(int) ySpot
{
int gridValue = 1;
int gridCount = [theGrid count];
[[theGrid objectAtIndex:(xSpot+ySpot*120)] getValue:&gridValue];
if (gridValue != 0) {
return;
}
[theGrid replaceObjectAtIndex:(xSpot + ySpot*120) withObject:[NSNumber numberWithInt:fillNum]];
[self fillArea:fillNum x:(xSpot+1) y:(ySpot)];
[self fillArea:fillNum x:(xSpot+1) y:(ySpot-1)];
[self fillArea:fillNum x:(xSpot) y:(ySpot-1)];
[self fillArea:fillNum x:(xSpot-1) y:(ySpot-1)];
[self fillArea:fillNum x:(xSpot-1) y:(ySpot)];
[self fillArea:fillNum x:(xSpot-1) y:(ySpot+1)];
[self fillArea:fillNum x:(xSpot) y:(ySpot+1)];
[self fillArea:fillNum x:(xSpot+1) y:(ySpot+1)];
return;
}
theGrid is an NSMutableArray of ints (either a 0 or a 1). It is just a 1D array that simulates a 2D array by multiplying the ySpot by 120 (the width of my grid). I checked the gridCount and it is equal to 9600.
However, I get an exc_bad_access at [[theGrid objectAtIndex:(xSpot+ySpot*120)] getValue:&gridValue]. I check my xSpot and ySpot when this happens and I know that (xSpot+ySpot*120) < 9600 every time. So I know it's not that I'm trying to access an object who's index is outside my array.
Futhermore, in my tick function I ran the code:
int gVal = 1;
int gIndex = 0;
while (gIndex < [theGrid count]) {
[[theGrid objectAtIndex:gIndex] getValue:&gVal];
gIndex += 1;
}
I did not get an exc_bad_access error. Please help me figure out why I'm getting an exc_bad_access error.
EDIT:
I split [[theGrid objectAtIndex:(xSpot+ySpot*120)] getValue:&gridValue]; into:
id object = [theGrid objectAtIndex:(xSpot+ySpot*widthInGridSize)];
gridValue = [object intValue];
I still get exc_bad_access and it says it is on the line:
gridValue = [object intValue];
So I assume this means object has already been released? I don't understand how that's possible. I thought ints didn't need to be retained in any way since they're just ints. Also I thought adding an object to an array automatically retained it so why would my int get released.
In the debug section the value of object is said equal: (_NSCFNumber *) 0x005aec80 (int) 0
As per comments - this isn't actually an out of bounds issue, but rather the object you're pulling out of 'theGrid' is bogus (already released). Break that into multiple lines to confirm; and turn on "zombies" in your debug settings. Cheers!
fresh to objC and cocos2d :)
i'm following "learn cocos2d game development with iOS5", in chapter4, there is a "DoodleDrop" game.
define some variable in GameScene.h like this
#interface GameScene : CCLayer
{
CCSprite *player;
CGPoint playerVelocity;
CCArray *spiders;
CGSize screenSize;
int dropedSpidersCount;
float duration;
}
+ (CCScene *)scene;
#end
in GameScene.m the init method looks like this
- (id)init
{
if (self = [super init]) {
duration = 4.0;
[self createPlayer];
[self createSpiders]; // spiders were inited here.
[self resetSpiders];
[self schedule:#selector(chooseSpider:) interval:0.7];
}
return self;
}
while in chooseSpider, i cannot access spiders, xcode broke
in other methods, spiders or duration just behave normally, why does this happens?
gist code added
https://gist.github.com/2940466
After inspecting your code, I suggest you to try this fix:
- (void)createSpiders
{
CCSprite *tempSpider = [CCSprite spriteWithFile:#"spider.png"];
CGSize spiderSize = [tempSpider texture].contentSize;
int spiderCount = screenSize.width / spiderSize.width;
spiders = [[CCArray arrayWithCapacity:spiderCount] retain];
for (int i = 0; i < spiderCount; i++) {
CCSprite *spider = [CCSprite spriteWithFile:#"spider.png"];
[self addChild:spider];
[spiders addObject:spider];
}
}
where the only difference is in the line:
spiders = [[CCArray arrayWithCapacity:spiderCount] retain];
Indeed, if you do not retain you spiders object, it will be autoreleased at the next run loop iteration.
OLD ANSWER:
Without seeing more code it is not possible to say exactly what is happening, but it seems that in the interval between creating the spiders and the actual execution of chooseSpiders, your spiders array gets deallocated.
As a quick try, I would suggest adding:
[spiders retain];
before calling
[self schedule:#selector(chooseSpider:) interval:0.7];
and see wether the crash keeps happening.
if you provide more code, it could be possible to help you further.
I've just began to learn iOS development and now I have a sigabrt on my main function. The error is triggered by calling:
int retVal = UIApplicationMain(argc, argv, nil, nil);
As I am very new to iOS programming I have no idea on what could by causing this error. One thing that I have found on my callstack is the following exception being raised: dyld_stub_objc_exception_throw
What could be causing this error?
I was having this problem in X-Code 4.2 and the issue was it couldn't find my Storyboard. The frustrating part was that there was no indication of what the actual exception was. I was able to get the exception in the log by adding a try / catch to my main function. (Note I'm using ARC, so if you aren't using ARC your main will look a little different with try catch)
int main(int argc, char *argv[])
{
int retVal = 0;
#autoreleasepool {
NSString *classString = NSStringFromClass([sortaAppDelegate class]);
#try {
retVal = UIApplicationMain(argc, argv, nil, classString);
}
#catch (NSException *exception) {
NSLog(#"Exception - %#",[exception description]);
exit(EXIT_FAILURE);
}
}
return retVal;
}
UIApplicationMain basically kicks off the rest of your application, so the actual cause of the crash could be anywhere in your application. You may need to look further down the call stack.
However, I note that you're passing nil as the final two parameters. The first nil is the principalClassName argument, which can legally be nil if you want UIApplication to be the principal class. The second nil is the application delegate name; you should pass nil if you load the delegate from the main nib. Do you? If you don't, that might be the problem (I can't say I've ever called this function with both of those arguments nil).
It was just a typical error of someone learning a new language/API. I forgot to properly set up the view.
UIView *controllersView = [myViewController view];
[window addSubview:controllersView];
Header :
#interface CodeTest : NSObject {
BOOL cancelThread;
}
-(void) testCode;
-(void) stopRunning;
-(void) startRunning;
#property (assign) BOOL cancelThread;
#end
Implementation :
-(void)stopRunning{
self.cancelThread = YES;
}
-(void)startRunning{
self.cancelThread = NO;
[NSThread detachNewThreadSelector:#selector(testCode) toTarget:self withObject:nil];
}
-(void)testCode{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSLog(#"STARTED");
/* Std C99 code */
while( conditions ){
if(self.cancelThread){
conditions = NO;
}
...
...
}
/* end of C code */
[pool release];
}
As you can see, it tires to execute testCode on a separate thread and using the cancelThread BOOL as a stop execution flag in the separate thread.
I have the following issue :
The compiler signals that self.cancelThread in the middle of the std c code is not valid (self is not defined). I think, it tries to interpret that statement as c code but this is obj-c.
There is something missing ?
UPDATE : It's not related to missing {}'s as one of you suggested... The code works perfectly without the if(self.cancelThread){ conditions = NO; }.
-[CodeTest setCancelThread:]: unrecognized selector.
Means that you don't have a setter defined for the cancelThread property. You're missing
#synthesize cancelThread;
(in your #implementation section)
What do you mean by " /* Std C99 code */"?
If that code is really being compiled as C99 code, then self.cancelThread is problematic because it is an Objective-C expression. First, it is the equivalent of [self cancelThread], a method call and, secondly, it requiresself` which wouldn't be present in the body of a C99 function.
However, given that the code you showed has it in a method, the comment doesn't make sense.