I have a crash with some optimisation code. What I'm trying to do is to remove some points from the input array when the previous and the next point are close enough. The method works well in almost all case but crash with some specific data.
An example of input data that crash:
Value of coords : (51.55188, -0.17591), (51.55208, -0.17516), (51.55231, -0.17444)
Value of altitudes : 10000, 10000, 10000
Value of count : 3
If I skip the optimisation code and use directly the input value, then everything works correctly. It also works correctly if I simply memcpy the input values in the temp arrays.
I got a EXC_BAD_ACCESS EXC_I386_GPFLT after using this method with the input data posted. The crash doesn't happen directly in this method but after when I use the object created at the end of the method. I've already tried NSZombie and Profiling for zombies. Everything works correctly with almost all the data but crash 100% with this specific input data (At least it is easier for me to debug!).
The code of my method:
+ (instancetype) optimizedPolylineWithCoordinates:(CLLocationCoordinate2D*) coords altitudes:(RLMKAltitude*) altitudes count:(NSUInteger) count
{
CGFloat minimumDistanceBetweenPoints = [self minimumOptimizedDistanceBetweenPoints];
CLLocationCoordinate2D* tempCoords = malloc(sizeof(CLLocationCoordinate2D) * count);
RLMKAltitude* tempAltitudes = malloc(sizeof(RLMKAltitude) * count);
NSUInteger tempCoordsCount = 0;
// Always keep first point
tempCoords[0] = coords[0];
tempAltitudes[0] = altitudes[0];
++tempCoordsCount;
for (NSUInteger i = 1; i < (count - 1); i++)
{
MKMapPoint prevPoint = MKMapPointForCoordinate(coords[i - 1]);
MKMapPoint nextPoint = MKMapPointForCoordinate(coords[i + 1]);
// Get the distance between the next point and the previous point.
CLLocationDistance distance = MKMetersBetweenMapPoints(nextPoint, prevPoint);
// Keep the current point if the distance is greater than the minimum
if (distance > minimumDistanceBetweenPoints)
{
tempCoords[tempCoordsCount] = coords[i];
tempAltitudes[tempCoordsCount] = altitudes[i];
++tempCoordsCount;
}
}
// Always keep last point
tempCoords[tempCoordsCount] = coords[(count - 1)];
tempAltitudes[tempCoordsCount] = altitudes[(count - 1)];
++tempCoordsCount;
RLMKMapWay* object = [self polylineWithCoordinates:tempCoords altitudes:tempAltitudes count:tempCoordsCount];
free(tempCoords);
free(tempAltitudes);
return object;
}
Note that the polylineWithCoordinates method called with the temp data take care of making copy of all the data so the problem is likely not related with the free located after the call (I've already tried to comment both lines and the crash still happen)
When count == 1, you are writing outside the allocated memory.
Related
I am developing an app in XCode and have to write a bit of C for an algorithm. Here is a part of the C code:
double dataTag[M][N];
// dataTag initialized to values.....
double w[N]; // This is outside for loop at the top level of the method
for (int i = 0; i < N; i++) {
w[i] = pow(10.0, dataTag[2][i] / 10.0 / b);
}
//This is inside for loop.....
double disErr[N];
// disErr set and values confirmed with printArray...
double transedEstSetDrv[N][M];
// transedEstSetDrv set and values confirmed with printArray...
double stepGrad[M] = {0, 0, 0};
for (int j = 0; j < M; j++) {
double dotProductResult[M];
dotProductOfArrays(w, disErr, dotProductResult, N);
stepGrad[j] = sumOfArrayMultiplication(transedEstSetDrv[j], dotProductResult, M);
}
// Print array to console to confirm values
NSLog(#"%f %f %f", stepGrad[0], stepGrad[1], stepGrad[2]); <-- if this is present algorithm gives different results.
//Continue calculations......
So this is a part of algorithm in C which is inside for loop. The weird part is the NSLog that prints stepGrad array. Depending if i comment the call to the NSLog or not - the algorithm as a whole gives different results.
It would be great if someone gave some debugging suggestions.
Thanks!
UPDATE 1:
Simplified example which has the same issue and gave more code to support the issue.
UPDATE 2:
Removed the length_of_array function and just replaced it with a known number for simplicity.
So i will answer my own question.
Thanks to the comment from #Klas Lindbäck, i fixed the issue which was related to not initializing a C static array in for loop. So i went over all arrays before and after the code that had issue and did a
memset(a_c_array, 0, sizeof(a_c_array));
after declaration of each array. That is now working fine. Thank you for all your help!
I am using this Accelerometer graph from Apple and trying to convert their G-force code to calculate +/- 128.
The following image shows that the x, y, z values in the labels do not match the output on the graph: (Note that addX:y:z values are what is shown in the labels above the graph)
ViewController
The x, y, z values are received from a bluetooth peripheral, then converted using:
// Updates LABELS
- (void)didReceiveRawAcceleromaterDataWithX:(NSInteger)x Y:(NSInteger)y Z:(NSInteger)z
{
dispatch_async(dispatch_get_main_queue(), ^{
_labelAccel.text = [NSString stringWithFormat:#"x:%li y:%li z:%li", (long)x, (long)y, (long)z];
});
}
// Updates GRAPHS
- (void)didReceiveAcceleromaterDataWithX:(NSInteger)x Y:(NSInteger)y Z:(NSInteger)z
{
dispatch_async(dispatch_get_main_queue(), ^{
float xx = ((float)x) / 8192;
float yy = ((float)y) / 8192;
float zz = ((float)z) / 8192;
[_xGraph addX:xx y:0 z:0];
[_yGraph addX:0 y:yy z:0];
[_zGraph addX:0 y:0 z:zz];
});
}
GraphView
- (BOOL)addX:(UIAccelerationValue)x y:(UIAccelerationValue)y z:(UIAccelerationValue)z
{
// If this segment is not full, then we add a new acceleration value to the history.
if (index > 0)
{
// First decrement, both to get to a zero-based index and to flag one fewer position left
--index;
xhistory[index] = x;
yhistory[index] = y;
zhistory[index] = z;
// And inform Core Animation to redraw the layer.
[layer setNeedsDisplay];
}
// And return if we are now full or not (really just avoids needing to call isFull after adding a value).
return index == 0;
}
- (void)drawLayer:(CALayer*)l inContext:(CGContextRef)context
{
// Fill in the background
CGContextSetFillColorWithColor(context, kUIColorLightGray(1.f).CGColor);
CGContextFillRect(context, layer.bounds);
// Draw the grid lines
DrawGridlines(context, 0.0, 32.0);
// Draw the graph
CGPoint lines[64];
int i;
float _granularity = 16.f; // 16
NSInteger _granualCount = 32; // 32
// X
for (i = 0; i < _granualCount; ++i)
{
lines[i*2].x = i;
lines[i*2+1].x = i + 1;
lines[i*2].y = xhistory[i] * _granularity;
lines[i*2+1].y = xhistory[i+1] * _granularity;
}
CGContextSetStrokeColorWithColor(context, _xColor.CGColor);
CGContextStrokeLineSegments(context, lines, 64);
// Y
for (i = 0; i < _granualCount; ++i)
{
lines[i*2].y = yhistory[i] * _granularity;
lines[i*2+1].y = yhistory[i+1] * _granularity;
}
CGContextSetStrokeColorWithColor(context, _yColor.CGColor);
CGContextStrokeLineSegments(context, lines, 64);
// Z
for (i = 0; i < _granualCount; ++i)
{
lines[i*2].y = zhistory[i] * _granularity;
lines[i*2+1].y = zhistory[i+1] * _granularity;
}
CGContextSetStrokeColorWithColor(context, _zColor.CGColor);
CGContextStrokeLineSegments(context, lines, 64);
}
How can I calculate the above code to show the correct accelerometer values on the graph with precision?
I post this as an aswer not a comment, because I have not enough reputation, but what I'll write might be enough to send you in the right direction, that it even may count as an answer...
Your question still doesn't include what is really important. I assume the calculation of the xx/yy/zz is no problem. Although I have no idea what the 8192 is supposed to mean.
I guess the preblem is in the part where you map your values to pixel coordinates...
the lines[] contains your values in a range of 1/8192th of the values in the label. so your x value of -2 should be at a pixel position of -0.0000something, so slightly(far less than 1 Pixel) above the view... Because you see the line a lot further down there must be some translation in place (not shown in your code)
The second part that is important but not shown is DrawGridlines. Probably in there is a different approach to map the values to pixel-coordinates...
Use the debugger to check what pixel-coordinates you get when draw your +127-line and what you get if you insert the value of +127 in your history-array
And some Ideas for improvements when reading your code:
1.)Put the graph in it's own class that draws one graph(and has only one history. Somehow you seem to have that partially already (otherwise I cannot figure out your _xGraph/_yGraph/_zGraph) But on the other hand you draw all 3 values in one drawLayer??? Currently you seem to have 3*3 history buffers of which 3*2 are filled with zeros...
2.) use one place where you do the calculation of Y that you use both for drawing the grid and drawing the lines...
3.) use CGContextMoveToPoint(); + CGContextAddLineToPoint(); instead of copying into lines[] with these ugly 2*i+1 indecies...
I'm working on a Spritekit Tower Defence game. ARC is enabled. (And I intend to run this code in the background, though presently it's just running on the main thread.)
In my update loop (which is running up to 60 times a second) I call a method called getTargetsForTowers. After profiling this method, I've found two items in the list that are chewing up my CPU time: objc_object::sidetable_retain/release, and I'm trying to find out what they are.
I'd like to understand more about what this is and if I can improve performance by reducing them or getting rid of them altogether.
There are 300 enemies and 446 towers in my test scenario. The majority of the CPU time is reported in the tower loop.
- (void)getTargetsForTowers {
NSArray *enemiesCopy = [enemiesOnMap copy];
for (CCUnit *enemy in enemiesCopy) {
float edte = enemy.distanceToEnd;
CGPoint enemyPos = enemy.position;
[self calculateTravelDistanceForEnemy:enemy];
if (enemy.actualHealth > 0) {
NSArray *tiles = [self getTilesForEnemy:enemy];
for (CCTileInfo *tile in tiles) {
NSArray *tileTowers = tile.towers;
for (CCSKTower *tower in tileTowers) {
BOOL hasTarget = tower.hasTarget;
BOOL passes = !hasTarget;
if (!passes) {
CCUnit *tg = tower.target;
float tdte = tg.distanceToEnd;
passes = edte < tdte;
}
if (passes) {
BOOL inRange = [self circle:tower.position withRadius:tower.attackRange collisionWithCircle:enemyPos collisionCircleRadius:1];
if (inRange) {
tower.hasTarget = YES;
tower.target = enemy;
}
}
}
}
}
}
}
Screenshots from Time Profile (after 60 seconds of running):
image one http://imageshack.com/a/img22/2258/y18v.png
image two http://imageshack.com/a/img833/7969/7fy3.png
(I've been reading about blocks, arc, strong/weak references, etc., so I tried making the variables (such as CCSKTower *tower) __weak, which did get rid of those two items, but that added a whole bunch of new items related to retaining/creating/destroying the weak variables, and I think they consumed more CPU time than before.)
I'd appreciate any input on this. Thanks.
EDIT:
There's another method that I would like to improve as well which is:
- (NSArray *)getTilesForEnemy:(CCUnit *)enemy {
NSMutableArray *tiles = [[NSMutableArray alloc] init];
float enemyWidthHalf = enemy.size.width/2;
float enemyHeightHalf = enemy.size.height/2;
float enemyX = enemy.position.x;
float enemyY = enemy.position.y;
CGVector topLeft = [self getVectorForPoint:CGPointMake(enemyX-enemyWidthHalf, enemyY+enemyHeightHalf)];
CGVector topRight = [self getVectorForPoint:CGPointMake(enemyX+enemyWidthHalf, enemyY+enemyHeightHalf)];
CGVector bottomLeft = [self getVectorForPoint:CGPointMake(enemyX-enemyWidthHalf, enemyY-enemyHeightHalf)];
CGVector bottomRight = [self getVectorForPoint:CGPointMake(enemyX+enemyWidthHalf, enemyY-enemyHeightHalf)];
CCTileInfo *tile = nil;
for (float x = topLeft.dx; x < bottomRight.dx+1; x++) {
for (float y = bottomLeft.dy; y < topRight.dy+1; y++) {
if (x > -(gameHalfCols+1) && x < gameHalfCols) {
if (y < gameHalfRows && y > -(gameHalfRows+1)) {
int xIndex = (int)(x+gameHalfCols);
int yIndex = (int)(y+gameHalfRows);
tile = tileGrid[xIndex][yIndex];
if (tile != nil) {
[tiles addObject:tile];
}
}
}
}
}
return tiles;
}
I've looked over it repeatedly and there's nothing I really can see. Perhaps there's nothing more that can be done.
Screenshots:
One issue is that you create a new reference to tower.target, but only use that reference once. So simply rewriting that section should improve your performance, e.g.
if (!passes) {
float tdte = tower.target.distanceToEnd;
passes = edte < tdte;
}
Based on your comment, it seems that there's no way to avoid a retain/release if you access a property on tower.target. So let's try radical surgery. Specifically, try adding a distanceToEnd property to the tower, to keep track of the distanceToEnd for the tower's current target. The resulting code would look like this.
- (void)getTargetsForTowers {
// initialization to copy 'distanceToEnd' value to each tower that has a target
for ( CCSKTower *tower in towersOnMap )
if ( tower.hasTarget )
tower.distanceToEnd = tower.target.distanceToEnd;
NSArray *enemiesCopy = [enemiesOnMap copy];
for (CCUnit *enemy in enemiesCopy) {
float edte = enemy.distanceToEnd;
CGPoint enemyPos = enemy.position;
[self calculateTravelDistanceForEnemy:enemy];
if (enemy.actualHealth > 0) {
NSArray *tiles = [self getTilesForEnemy:enemy];
for (CCTileInfo *tile in tiles) {
NSArray *tileTowers = tile.towers;
for (CCSKTower *tower in tileTowers) {
if ( !tower.hasTarget || edte < tower.distanceToEnd ) {
BOOL inRange = [self circle:tower.position withRadius:tower.attackRange collisionWithCircle:enemyPos collisionCircleRadius:1];
if (inRange) {
tower.hasTarget = YES;
tower.target = enemy;
tower.distanceToEnd = edte; // update 'distanceToEnd' on the tower to match new target
}
}
}
}
}
}
}
My impression is that there's not much to be done about the getTilesForEnemy method. Looking at the Running Time image for getTilesForEnemy it's clear that the load is fairly evenly spread among the various components of the method, with only three items above 10%. The top item getVectorForPoint isn't even in the innermost loop. The second item insertObject is apparently the result of the addObject call in the inner loop, but there's nothing to be done for that call, it's required to generate the final result.
At the next level up (see the wvry.png image), you can see that getTilesForEnemy is now 15.3% of the total time spent in getTargetsForTowers. So even if it were possible to reduce getVectorForPoint from 17.3% to 7.3% there would not be a significant reduction in running time. The savings in getTilesForEnemy would be 10%, but because getTilesForEnemy is only 15.3% of the time in getTargetsForTowers, the overall savings would only be 1.53%.
Conclusion, because the components of getTilesForEnemy are balanced and below 20%, and because getTilesForEnemy is only 15.3% of the higher level method, no significant savings will be gained by trying to optimize getTilesForEnemy.
So once again the only option is radical surgery, and this time I mean a total rewrite of the algorithm. Such action should only be taken if the app still isn't performing up to spec. You've run into the limitations of ARC and NSArray's. Both of those technologies are extremely powerful and flexible, and are perfect for high-level development. However, they both have significant overhead which limits performance. So the question becomes, "How do you write the getTargetsForTowers without using ARC and NSArray's?". The answer is to use arrays of C structs to represent the objects. The resulting top level pseudo code would be something like this
copy the enemy information into an array of C structs
copy the tower information into an array of C structs
(note that the target for a tower is just an 'int', which is the index of an enemy in the enemy array)
for ( each enemy in the enemy array )
{
create an array of C structs for the tiles
for ( each tile )
for ( each tower in the tile )
update the tower target if needed
}
copy the updated tower information back into the NSArray of tower objects
For your second method, this part seems unclear and inefficient:
for (float x = topLeft.dx; x < bottomRight.dx+1; x++) {
for (float y = bottomLeft.dy; y < topRight.dy+1; y++) {
if (x > -(gameHalfCols+1) && x < gameHalfCols) {
if (y < gameHalfRows && y > -(gameHalfRows+1)) {
For instance, there's no point in spinning the y loop if your x is out of bounds. You could just do this:
for (float x = topLeft.dx; x < bottomRight.dx+1; x++) {
if (x > -(gameHalfCols+1) && x < gameHalfCols) {
for (float y = bottomLeft.dy; y < topRight.dy+1; y++) {
if (y < gameHalfRows && y > -(gameHalfRows+1)) {
More importantly, the point of the first for loop is to start x at some minimum and increment it to some maximum, and the if statement is there to make sure x is at least some minimum and less than some maximum, so there's no reason to have both a for() and an if(). I don't know what the values might look like for topLeft.dx and gameHalfCols, so I can't tell you the best way to do this.
But, for example, if topLeft.dx is always integral, you might say:
for (float x = MAX(topLeft.dx, ceil(-(gameHalfCols+1))); x < bottomRight.dx+1 && x < gameHalfCols; x++) {
for (float y = ...
You could similarly improve the 'y' for this way. This sin't just fewer lines of code, it also prevents the loops from spinning a bunch of extra times with no effect: the 'if' statements just make the loops spin quickly to their ends, but including the logic inside the 'for's themselves makes them only loop over values that you'll actually use in computations.
To expand my comments to a complete answer:
The normal, correct Objective-C behaviour when returning an object property is to retain and then autorelease it. That's because otherwise code like this (imagine you're in the world before ARC):
TYTemporaryWorker *object = [[TYTemporaryWorker alloc] initWithSomeValue:value];
NSNumber *someResult = object.someResult;
[object release];
return someResult;
would otherwise be invalid. object has been deallocated so if someResult hasn't been retained and autoreleased then it will become a dangling pointer. ARC makes this sort of slightly less direct (the strong reference in someResult would have retained the number beyond the lifetime of object but then it would have been autoreleased for the return) but the principle remains and, in any case, whether an individual .m file has been compiled with ARC is not supposed to affect callers.
(aside: notice that weak isn't just strong without retains — is has related costs because the runtime has to establish a link from the object to the weak reference in order to know find it again and nil it if the object begins deallocation)
Supposing you wanted to create a new type of property that isn't strong and isn't unsafe_unretained but is rather defined to be that the object returned is safe for use for as long as the original owner is alive but unsafe afterwards. So it's a strong set but an unsafe_unretained get.
It's untested but I think the correct means to do that would be:
// we can't write want a synthesised getter that doesn't attempt to retain
// or autorelease, so we'd better flag up the pointer as potentially being
// unsafe to access
#property (nonatomic, unsafe_unretained) NSNumber *someResult;
...
#implementation TYWhatever
{
NSNumber *_retainedResult; // a strong reference, since
// I haven't said otherwise —
// this reference is not publicly exposed
}
- (void)setSomeResult:(NSNumber *)number
{
// set the unsafe and unretained version,
// as the default setter would have
_someResult = number;
// also take a strong reference to the object passed in,
// to extend its lifecycle to match ours
_retainedResult = number;
}
It's going to get quite verbose as you add more properties but what you're doing is contrary to normal Objective-C conventions so limited compiler help is probably to be expected.
I'm making a simple SpriteKit game. It has one randomly generated world made up of lines. These lines are represented by the NHRLineNode class. I generate these lines all at once in the beginning of the level with two for loops, one for each side of the screen. This works fine. In addition to the main gameplay scene of the game, there is a "game over" screen that displays between plays and shows your score etc and a main menu scene. The problem comes when I play the game, die, see the game over screen, and play again. Looking at the memory usage in Xcode, it seems like the memory usage goes up when I first start the game from the menu scene, stays steady throughout the gameplay, and then jumps 6-10 MB when I die. This memory is never regained and the app uses more and more memory every time I play. I think this is because my for loops that generate the platforms are just creating a new instance of the NHRLineNode class, positioning it correctly, and then doing it again. Is this what is causing my memory issues? Or is it more likely something on the game over scene?
Relevant snippets:
The for loops that generate the platforms:
int previousXVal1 = -10;
int previousYVal1 = 425;
int newXPosition = 0;
//How many do you want?
int numToGen = 100;
for(int i = 1; i<=numToGen; i++) {
NHRLineNode *lineGen = [NHRLineNode initAtPosition:CGPointMake(previousXVal1 + arc4random_uniform(85), previousYVal1 - 75)];
[worldNode addChild:lineGen];
if(lineGen.position.x > 390) {
newXPosition = lineGen.position.x - 100; //That should bring it onscreen!
lineGen.position = CGPointMake(newXPosition, lineGen.position.y); //Make the new position
} else if (lineGen.position.x < 100) {
newXPosition = lineGen.position.x + 100; //That will bring it onscreen!!
lineGen.position = CGPointMake(newXPosition, lineGen.position.y);
}
previousXVal1 = lineGen.position.x;
previousYVal1 = lineGen.position.y;
}
//This creates the lines on the right side (performing the inverse calculation on the x pos
//int numToGen = 10;
int previousXVal2 = 350;
int previousYVal2 = 525;
for(int i = 1; i<=numToGen; i++) {
NHRLineNode *lineGen = [NHRLineNode initAtPosition:CGPointMake(previousXVal2 - arc4random_uniform(85), previousYVal2 - 75)];
[worldNode addChild:lineGen];
if(lineGen.position.x > 390) { //It is partially off-screeb=n
newXPosition = lineGen.position.x - 100; //That should bring it onscreen!
lineGen.position = CGPointMake(newXPosition, lineGen.position.y); //Make the new position
} else if (lineGen.position.x < 100) { //It is partially off-screen
newXPosition = lineGen.position.x + 100; //That will bring it onscreen!!
lineGen.position = CGPointMake(newXPosition, lineGen.position.y);
}
previousXVal2 = lineGen.position.x;
previousYVal2 = lineGen.position.y;
}
The initAtPosition method of NHRLineNode:
+(id)initAtPosition:(CGPoint)point {
//This is all the properties of one of the lines in the level
SKSpriteNode *theLine = [SKSpriteNode spriteNodeWithImageNamed:#"newLine"];
//The physics body is slightly smaller than the image itself -- why idk
theLine.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(75,5)];
//It is not affected by gravity
theLine.physicsBody.dynamic = NO;
//Its position is the point given us when the function was called
theLine.position = point;
//Return it for further positioning by the generator
return theLine;
}
Entire implementation of GameOverScene: http://pastebin.com/wUpguueb
Thanks for your help.
Even though you have ARC on your side, sometimes you need to give it "incentive" to free objects, especially when creating many in a loop. Really, this simply has to do with providing scope, so ARC understands that it may release allocated instances.
Try wrapping the bodies of your for loops (i.e. not around the entire for loops), with #autoreleasepool { …} - i.e., as if that #autoreleasepool block is the only statement for the for loop.
Let is know if it helps! I commonly have to do this when iteratively importing data to Core Data.
In my OpenGL loop, Instruments is showing a total of 14% of my processor time in my particle processing loop going to objc_object::sidetable_release(bool) and objc_object:sidetable_retain(). This is significant, because the loop is using 100% of a CPU on an iPhone 5.
I'm wondering if there's a way I can reduce this. I don't know what causes it, and I don't see these in very many of my methods. I think they are related to doing a fast enumeration of an array of objects.
Here is what the offending method looks like:
-(void) updateWithTime:(ccTime)dt sceneHeightAboveHorizon:(CGFloat)yMax{
_elapsed = (_elapsed+dt) ;
float farTotalWidth = EQ_SCENE_WIDTH + 2*EQ_SIZE_FAR;
float farHalfWidth = farTotalWidth/2.0;
for (MyParticleData *data in self.farParticleData){
//Calculate position
float newX = data.pos.x + data.xVelocity * dt;
if (newX > 1)
newX -= 1;
float newY = data.y0 + EQ_A_FAR*sin(EQ_F_FAR*_elapsed+data.phasePosition);
data.pos = cc3v(newX,newY,0);
//Apply new position to sprites
data.sprite.position = cc3v(newX*farTotalWidth-farHalfWidth, newY*yMax, 0);
data.reflectedSprite.position = cc3v(data.sprite.position.x,-data.sprite.position.y,0);
//Calculate color
float f = MIN(14, MAX(data.pos.x*14.0, 0));
ccColor4F newColor = cycBlendColors(self.settings.eqColumnColors[(int)f], self.settings.eqColumnColors[(int)f+1], f-(int)f);
float colorAmp = MAX(0, (sin(data.frequencyColor*_elapsed+data.phaseColor)+1)/2.0);
newColor = cycScaleColor(newColor,colorAmp);
colorAmp *= colorAmp;//the alpha (white component) should be squared twice
newColor.a *= colorAmp*colorAmp;
//Apply new color to sprites
data.sprite.color4F = newColor;
data.reflectedSprite.color4F = cycScaleColor(newColor, self.settings.eqReflectionBrightness);
}
}
I'll try and psychically debug here -
1) You have ARC enabled
2) Some of the intermediate variables in your expressions (ex. data.sprite, self.settings) are Objective-C objects
3) One or more of these intermediate objects are weak or atomic (or are themselves accessing weak or atomic properties), both of which will require extra retain/release handling when accessed.
- IIRC atomic properties won't involve the side table rigamarole, just normal autoreleasing, but no guarantees on that.
I would try assigning some/all of these references to a local (on the stack) variable before enumeration, and inside your loop use the local references exclusively. This will have the added benefit of shaving off some accessor time from your loop as well.
If you know these references will remain strongly referenced through the entire enumeration 100% of the time, then you can use the __unsafe_unretained specifier on your local variables, which will (mostly) prevent any ARC shenanigans whatsoever from occurring in this method.