Objective C iOS - objc_object :: sidetable_retain / release chewing on CPU time in my loop?

I am working on a Spritekit Tower Defense game . ARC . (And I intend to run this code in the background, although currently it just works in the main thread.)

In my update loop (which runs up to 60 times per second), I call a method with a name getTargetsForTowers. After profiling this method, I found two items on the list that chew on my CPU time: objc_object::sidetable_retain/releaseand I'm trying to figure out what they are.

I would like to know more about what it is, and if I can improve performance by reducing them or even getting rid of them.

In my test case, there are 300 enemies and 446 towers. Most CPU time is reported in the loop of the tower.

- (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 the time profile (after 60 seconds of work):

image one http://imageshack.com/a/img22/2258/y18v.png

image two http://imageshack.com/a/img833/7969/7fy3.png

(I read about blocks, arcs, strong / weak links, etc., so I tried to make variables (like CCSKTower * tower) __weak that got rid of these two elements, but this added a whole bunch of new elements related to saving / creating / destroying weak variables, and I think they consumed more processor time than before).

I would be grateful for any material on this issue. Thank.

EDIT

There is another way that I would like to improve, namely:

- (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;
}

, . , .

:

http://imagizer.imageshack.us/v2/640x480q90/59/4cle.png

http://imagizer.imageshack.us/v2/640x480q90/811/98su.png

+4
3

, tower.target, . , .

if (!passes) {
    float tdte = tower.target.distanceToEnd;
    passes = edte < tdte;
}

, /, tower.target. . , distanceToEnd , distanceToEnd . .

- (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
                        }
                    }
                }
            }
        }
    }
}

, getTilesForEnemy. Running Time getTilesForEnemy, , , 10%. getVectorForPoint . insertObject, -, addObject , , .

(. wvry.png) , getTilesForEnemy 15,3% , getTargetsForTowers. , getVectorForPoint 17,3% 7,3%, . getTilesForEnemy 10%, getTilesForEnemy 15,3% getTargetsForTowers, 1,53%.

, getTilesForEnemy 20%, getTilesForEnemy 15,3% , , getTilesForEnemy.

, - , . , - . ARC NSArray. . , . : " getTargetsForTowers ARC NSArray?". C . -

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
+4

:

    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)) {

, y, x . :

    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)) {

, for x , if , x , for(), if(). , topLeft.dx gameHalfCols, , .

, , topLeft.dx , :

    for (float x = MAX(topLeft.dx, ceil(-(gameHalfCols+1))); x < bottomRight.dx+1 && x < gameHalfCols; x++) {
        for (float y = ...

"y" . , : "if" , " " , .

+1

:

, Objective-C retain, autorelease. , (, ARC):

TYTemporaryWorker *object = [[TYTemporaryWorker alloc] initWithSomeValue:value];
NSNumber *someResult = object.someResult;
[object release];
return someResult;

. object , , someResult , . ARC ( someResult object, return), , , , .m ARC, .

( : , weak - , , , , nil it )

, , strong unsafe_unretained, , , . , strong, unsafe_unretained .

, , :

// 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;
}

, , , , Objective-C, , , .

0

Source: https://habr.com/ru/post/1534345/


All Articles