Search code examples
objective-cuitableviewios7refreshibeacon

iOS7 and iBeacon - how to prevent a table view of ranged beacons from updating too quickly to select rows?


I have the following code that ranges iBeacons and refreshes a table view with them.

A user can tap on a beacon in that table to select it. However, I'm seeing that with a 4 of beacons nearby, the table updates too frequently, about once a second. By the time I can tap on a row, another row might appear in it's place.

Has anyone solved the problem of how to "stabilize" the table view that displays iBeacons? in other words, if a user wants to select a row, I want to make sure that this row does not suddenly get a different beacon loaded into it.

My code that refreshes the tableview

    -(void)beaconManager:(ESTBeaconManager *)manager
         didRangeBeacons:(NSArray *)beacons
                inRegion:(ESTBeaconRegion *)region
    {


        ++updateCounter;

        NSMutableDictionary* datasource = [NSMutableDictionary dictionary];

        NSMutableArray* near = [NSMutableArray array];
        NSMutableArray* far = [NSMutableArray array];

        for(ESTBeacon* beacon in beacons)
        {
            NSString* name = [NSString stringWithFormat:@"Beacon (%i,%i), update:%i",beacon.major.intValue,beacon.minor.intValue,updateCounter];

            if(beacon.proximity == CLProximityFar||
               beacon.proximity == CLProximityUnknown)
            {
                [far addObject:name];
            }else if(beacon.proximity == CLProximityNear||
                     beacon.proximity == CLProximityImmediate)
            {
                [near addObject:name];
            }

        }

        [datasource setObject:near forKey:@"near"];
        [datasource setObject:far forKey:@"far"];


         [self.beaconDelegate setDatasource:datasource];
    }

//within the tableview
-(void)setDatasource:(NSDictionary *)datasource
{
    _datasource = datasource;
    [self.tableView reloadData];
}

Solution

  • I do this in the Locate app by sorting the rows by the UUID/major/minor. In an early revision, I tried sorting by distance, but I found that was too variable. Using the identifiers as the sort order proved to be an acceptably stable solution.

    PS. if beacons jump and appear/disappear, check if their refresh interval is set to be greater than 1 second.

    NSArray* nearSorted = [near sortedArrayUsingComparator:^NSComparisonResult(ESTBeacon* a, ESTBeacon* b) {
    
    
        NSString* key1 = [NSString stringWithFormat:@"%@%i%i",[a.proximityUUID UUIDString],a.major.intValue,a.minor.intValue];
    
        NSString* key2 = [NSString stringWithFormat:@"%@%i%i",[b.proximityUUID UUIDString],b.major.intValue,b.minor.intValue];
    
        return  [key1 compare:key2];
    
    }];
    
    NSArray* farSorted  = [far sortedArrayUsingComparator:^NSComparisonResult(ESTBeacon* a, ESTBeacon* b) {
    
    
        NSString* key1 = [NSString stringWithFormat:@"%@%i%i",[a.proximityUUID UUIDString],a.major.intValue,a.minor.intValue];
    
        NSString* key2 = [NSString stringWithFormat:@"%@%i%i",[b.proximityUUID UUIDString],b.major.intValue,b.minor.intValue];
    
        return  [key1 compare:key2];
    
    }];