didRangeBeaconRegion method gives repeated beacon device in objective c - objective-c

i'm new to ibeacon apps,in my app i need to find the iBeacon device.here i'm having three beacon device.i find the device by the didRangeBeaconRegion method.i showed these detected beacon in a table view.
My problem is this method calls every seconds so my value having repeated beacons and many numbers rows.
how to show the three beacons details only in the table view.
i searched in the android app it shows only that three beacons only.
below is my code,
-(void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region{
if(beacons.count>0)
{
CLBeacon *beacon=[[CLBeacon alloc]init];
beacon=[beacons firstObject];
[uuidArr addObject:beacon.proximityUUID.UUIDString];
[minArr addObject:beacon.minor];
[majArr addObject:beacon.major];
[rssiArr addObject:[NSString stringWithFormat:#"%ld",(long)beacon.rssi]];
[distanceArr addObject:[NSString stringWithFormat:#"%f m",beacon.accuracy]];
NSString *proxStr;
if (beacon.proximity == CLProximityUnknown)
{
proxStr = #"Unknown";
}
else if (beacon.proximity == CLProximityImmediate)
{
proxStr= #"Immediate";
}
else if (beacon.proximity == CLProximityNear) {
proxStr = #"Near";
}
else if (beacon.proximity == CLProximityFar) {
proxStr = #"Far";
}
[proxArr addObject:proxStr];
}
else
{
}
[self.tblView reloadData];
}

You are loading the first object only to the beacon so you get the first beacon Value in the Beacons Array i.e if you have 4 beacon device means you get the first beacon only & didRangeBeacons method calls every second in that your adding the first object to your array like uuidArr,minArr like that,
Now Solution is:
1.remove all the Value in array above the if Condition.
2.Don't take the first object only.
3.put one for loop to add the list of devices.
code:
[uuidArr removeAllObjects];
[minArr removeAllObjects];
[majArr removeAllObjects];
[rssiArr removeAllObjects];
[distanceArr removeAllObjects];
[proxArr removeAllObjects];
if(beacons.count>0)
{
CLBeacon *beacon=[[CLBeacon alloc]init];
for(int i=0;i<beacons.count;i++)
{
beacon=beacons[i];
[uuidArr addObject:beacon.proximityUUID.UUIDString];
[minArr addObject:beacon.minor];
[majArr addObject:beacon.major];
[rssiArr addObject:[NSString stringWithFormat:#"%ld",(long)beacon.rssi]];
[distanceArr addObject:[NSString stringWithFormat:#"%f m",beacon.accuracy]];
NSString *proxStr;
if (beacon.proximity == CLProximityUnknown)
{
proxStr = #"Unknown";
}
else if (beacon.proximity == CLProximityImmediate)
{
proxStr= #"Immediate";
}
else if (beacon.proximity == CLProximityNear) {
proxStr = #"Near";
}
else if (beacon.proximity == CLProximityFar) {
proxStr = #"Far";
}
[proxArr addObject:proxStr];
}
}
now you get the number of devices you having.i hope this is help to you

Related

Boolean changes value before I can assign it

I have a curious problem where my boolean variable is changing before I can assign it to a variable to be read in my react native code for Spotify SDK.
I have pinpointed the EXACT location as to where it changes and I am currently trying to figure out why:
I have a boolean called isLoggedIn that is set equal to 1 if a successful login occurs. This variable then sets loggedIn to a boolean value which is sent to my React Native code:
else
{
// login successful
NSLog(#"What is the value of isLoggedIn %#", [self isLoggedIn]);
////THIS shows that isLoggedIn still equal to 1.
[self initializePlayerIfNeeded:[RNSpotifyCompletion onComplete:^(id unused, RNSpotifyError* unusedError) {
NSLog(#"What is the value of isLoggedIn right after %#", [self isLoggedIn]);
/////NOW the isLoggedIn variable is now equal to 0.
// do UI logic on main thread
dispatch_async(dispatch_get_main_queue(), ^{
[authController.presentingViewController dismissViewControllerAnimated:YES completion:^{
_loggingIn = NO;
NSLog(#"What is the value of isLoggedIn %#", [self isLoggedIn]);
NSNumber* loggedIn = [self isLoggedIn]; /////this is the line we need to be == 1
resolve(loggedIn);
if(loggedIn.boolValue)
{
[self sendEvent:#"login" args:#[]];
}
}];
});
}]];
}
So obviously I assume that it is due to this line right?:
[self initializePlayerIfNeeded:[RNSpotifyCompletion onComplete:^(id unused, RNSpotifyError* unusedError)
Which is running this method: initializePlayerIfNeeded but when I read the value of the isLoggedIn variable at the end of this method it still shows a boolean value of 1 (look at last line):
-(void)initializePlayerIfNeeded:(RNSpotifyCompletion*)completion
{
if(![self hasPlayerScope])
{
[completion resolve:nil];
return;
}
// ensure only one thread is invoking the initialization at a time
BOOL initializedPlayer = NO;
NSError* error = nil;
BOOL allowCaching = (_cacheSize.unsignedIntegerValue > 0);
#synchronized(_player)
{
// check if player is already initialized
if(_player.initialized)
{
initializedPlayer = YES;
}
else
{
initializedPlayer = [_player startWithClientId:_auth.clientID audioController:nil allowCaching:allowCaching error:&error];
}
}
// handle initialization failure
if(!initializedPlayer)
{
[completion reject:[RNSpotifyError errorWithNSError:error]];
return;
}
// setup player
_player.delegate = self;
_player.playbackDelegate = self;
if(allowCaching)
{
_player.diskCache = [[SPTDiskCache alloc] initWithCapacity:_cacheSize.unsignedIntegerValue];
}
// attempt to log in the player
[self loginPlayer:completion];
NSLog(#"What is the value of isLoggedIn %#", [self isLoggedIn]);
////THIS shows that isLoggedIn still equal to 1.
}
So that method finishes up with the value still equal to 1, but why after that method returns does the next line show that isLoggedIn equal to 0? I am extremely new to objC so every bit of knowledge is helpful for me. I am using this React Native Spotify library from github: https://github.com/lufinkey/react-native-spotify
You can find the exact file I'm working with here: https://github.com/lufinkey/react-native-spotify/blob/master/ios/RNSpotify.m
What else would you need to help solve this?
EDIT: here's the method that changes the isLoggedIn:
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(isLoggedIn)
{
if(!_initialized)
{
return #NO;
}
else if(_auth.session == nil)
{
return #NO;
}
return #YES;
}

Array Mutation whilst being Enumerated

so my issue is happening only when I have two enemies on a team in my game. If it's a one versus one.. I do not get the issue.
Please look at my code and see if you can gather as to why I'm getting this fatal error.
Removes Target from players target array
-(void)removeTarget:(PlayerClass *)target withSender:(PlayerClass *)sender {
if ([sender.targets containsObject:target]) {
[sender.targets removeObject:target];
}
}
Adds Target to players target array
-(void)addTarget:(PlayerClass *)target withSender:(PlayerClass *)sender {
//check if target already exists
if ([sender.targets count] > 0) {
for (PlayerClass *players in sender.targets) {
if ([players.name isEqualToString:target.name]) {
//Checked if exists, if target exists in list then move on.
goto outer;
}
}
}
[sender.targets addObject:target];
outer:;
}
In the Update to determine whether they're a target or not
-(void)update:(CFTimeInterval)currentTime {
/* Called before each frame is rendered */
for (PlayerClass *player in _players) {
....
if (player.health > 0) { //If player is alive!
....
//Checks if the player has targets, if so & visible - Engage.
if ([player.targets count] > 0) {
for (PlayerClass *enemy in player.targets) {
if (![player.team isEqualToString:enemy.team]) {
if (enemy.health > 0) {
if ([self lineOfSightBetweenPlayers:player andPlayer:enemy]) {
[self attackWithPlayer:player againstPlayer:enemy];
break;
} else {
[player removeTarget:enemy withSender:player];
}
} else {
[player removeTarget:enemy withSender:player];
}
} else {
[player removeTarget:enemy withSender:player];
}
}
}
}
Now from debugging I've gathered that the players don't add their team mates as targets. However, the player will gather more than one target if they can see more than one target on the opposing team. However, the issue I'm guessing lies in my technique to removing a target from the array? Can anyone check over and make sure I'm not delivering a school boy error here?
Thanks in advance.
Very simple fix. Wasn't thinking outside the box.. which tends to happen when code starts getting very large!
//Checks if the player has targets, if so & visible - Engage.
if ([player.targets count] > 0) {
for (PlayerClass *enemy in player.targets) {
if (![player.team isEqualToString:enemy.team]) {
if (enemy.health > 0) {
if ([self lineOfSightBetweenPlayers:player andPlayer:enemy]) {
[self attackWithPlayer:player againstPlayer:enemy];
break;
} else {
[player removeTarget:enemy withSender:player];
break;
}
} else {
[player removeTarget:enemy withSender:player];
break;
}
} else {
[player removeTarget:enemy withSender:player];
break;
}
}
}
Fixed my issue, I wasn't breaking out. Thus enumerating after removal.

What is a convenient way to check UITextFields for errors before allowing a form to submit?

I've been at this all day and just can't get my head around it. On a form in my app, I'm using -[UITextFieldDelegate textFieldDidEndEditing]: to register any errors and store them in an NSMutableArray instance variable formErrors.
I intend to use the formErrors when my submit button is pressed, or perhaps to disable the button disabled while there are errors on the form. The problem is the error count goes all over the place. I've just ended up confusing myself as you can see my code where I'm incrementing and decrementing in order to try and control what's going on but just confusing myself more.
Error messages get put on formErrors like this:
-(void)textFieldDidEndEditing:(UITextField *)textField {
if ( textField == [self nameField] ) {
if ( ([[textField text] isEqualToString:#""]) ) {
[formErrors addObject:#"What is your name?"];
errorCount++;
} else {
errorCount--;
if ( ([[textField text] length] < 2) || ([[textField text] length] > 20) ) {
[formErrors addObject:#"Name must contain a minimum of 2 and a maximum of 20 characters only."];
errorCount++;
} else {
errorCount--;
if ([[textField text] rangeOfCharacterFromSet:alphaSet].location != NSNotFound) {
[formErrors addObject:#"Name must contain letters and spaces only."];
errorCount++;
}
}
}
}
if (textField == [self ageField]) {
if ( ([[textField text] isEqualToString:#""]) ) {
[formErrors addObject:#"How old are you?"];
errorCount++;
} else {
errorCount--;
if ( ([[textField text] intValue]) < 1 || ([[textField text] intValue] > 120) ) {
[formErrors addObject:#"Please enter an age using a number between 1 and 120."];
errorCount++;
} else {
errorCount--;
if ([[textField text] rangeOfCharacterFromSet:numericSet].location != NSNotFound) {
[formErrors addObject:#"Age must be given in numbers."];
errorCount++;
}
}
}
}
My instance var:
{
NSMutableArray *formErrors;
}
Then initialise it in viewDidLoad:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
formErrors = [[NSMutableArray alloc] init];
Then in prepareForSegue: I have some temporary code to check things are working:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
int errCount = [formErrors count];
// check if all textfield values are filled in if not then disallow form submit
for (NSString *error in formErrors) {
NSLog(#"Total %d errors, \n Error Message: %#", errCount, error);
}
All I want to do is, as I enter and leave fields, check if there are any errors; if there are, just store the error message in formErrors, so I can do what I need to do in the prepareForSegue:. Is this even the right approach? I've tried doing this many different ways but just keep on going in circles.
The submit button is linked to my segue and also is an outlet so I can enabled and disable it as I please.
Help would be appreciated
Kind regards
Your approach is a bit redundant. Validate your fields upon submission, cancel submission if there are any errors:
- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender {
NSMutableArray *errors = [NSMutableArray array];
if (self.nameTextField.text.length > 21) {
[errors addObject:#"Name cannot be longer than 21 symbols"];
}
else if (!self.nameTextField.text.length) {
[errors addObject:#"Please enter your name"];
}
if (!self.passwordTextField.text.length) {
[errors addObject:#"Please enter password"];
}
else if (!self.confirmPasswordTextField.text.length) {
[errors addObject:#"Please confirm your password"];
}
else if (self.passwordTextField.text.length < 6) {
[errors addObject:#"Password is too short, use at least 6 characters."];
}
else if (![self.passwordTextField.text isEqualToString:self.confirmPasswordTextField.text]) {
[errors addObject:#"Passwords do not match"];
}
if (!self.emailTextField.text.length) {
[errors addObject:#"Please enter your e-mail"];
}
if (!self.image) {
[errors addObject:#"Please choose a photo"];
}
if (errors.count) {
[[[UIAlertView alloc] initWithTitle:#"Error"
message:[errors componentsJoinedByString:#"\n"]
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil, nil] show];
return NO;
}
return YES;
}
You're on the right path, but here are a couple of observations.
First I would get rid of all the errorCount++ and errorCount-- lines. They don't make sense, because you can always count the items in your error array.
Every time you check your input fields, clear your error array, otherwise you will be having errors that might have been already corrected.
Inside your -(void)textFieldDidEndEditing:(UITextField *)textField method, don't only check the textfield that has been edited, because you wold need to keep track of the errors that were before, the ones that were corrected, and the new ones... too much trouble.
I think it's best to create a new method that checks all the information and returns an array of errors. Call this routine from textFieldDidEndEditing.
- (NSArray *)checkInputs
{
NSMutableArray *errors = [NSMutableArray array];
// Loop through the textfields and fill your array
return (NSArray *)errors;
}

Efficient way of checking the content of every NSDictionary in NSArray

In my app I'me getting responses from the server and I have to check that I don't create duplicate objects in the NSArray which contains NSDictionaries. Now to check if the objects exists I do this:
for (int i = 0; i < appDelegate.currentUser.userSiteDetailsArray.count; i++){
NSDictionary *tmpDictionary = [appDelegate.currentUser.userSiteDetailsArray objectAtIndex:i];
if ([[tmpDictionary valueForKey:#"webpropID"] isEqualToString:tmpWebproperty.identifier]){
needToCheck = NO;
}
if (i == appDelegate.currentUser.userSiteDetailsArray.count - 1 && ![[tmpDictionary valueForKey:#"webpropID"] isEqualToString:tmpWebproperty.identifier] && needToCheck){
// It means it's the last object we've iterated through and needToCheck is still = YES;
//Doing stuff here
}
}
I set up a BOOL value because this iteration goes numerous times inside a method and I can't use return to stop it. I think there is a better way to perform this check and I would like to hear your suggestions about it.
BOOL needToCheck = YES;
for (int i = 0; i < appDelegate.currentUser.userSiteDetailsArray.count; i++){
NSDictionary *tmpDictionary = [appDelegate.currentUser.userSiteDetailsArray objectAtIndex:i];
if ([[tmpDictionary valueForKey:#"webpropID"] isEqualToString:tmpWebproperty.identifier]){
needToCheck = NO;
break;
}
}
if (needToCheck) {
//Doing stuff here
}
But, as others have said, you can maybe keep a "summary" in a separate NSSet that you check first, vs spinning through all the dictionaries.
NSDictionary *previousThing = nil;
for (NSDictionary *thing in appDelegate.currentUser.userSiteDetailsArray) {
if ([thing[#"webpropID"] isEqualToString:newWebPropertyIdentifier]) {
previousThing = thing;
break;
}
}
if (previousThing == nil) {
// no previous thing
} else {
// duplicate
}

Do [sprite stopActionByTag: kTag]; work differently for CCAction and CCSequence?

//prog 1
-(void)gameLogic:(ccTime)dt
{
id actionMove = [CCMoveTo actionWithDuration:1.0 position:ccp(windowSize.width/2-400, actualY)];
[actionMove setTag:6];
[self schedule:#selector(update:)];
[hitBullet runAction:actionMove];
}
-(void)update:(ccTime)dt
{
if ( (CGRectIntersectsRect(hitRect, playerRect)) )
{
[[[self getActionByTag:6] retain] autorelease];
[hitBullet stopActionByTag: 6];
}
}
//prog 2
-(void)gameLogic:(ccTime)dt
{
id actionMove = [CCMoveTo actionWithDuration:1.0 position:ccp(windowSize.width/2-400, actualY)];
id hitBulletAction = [CCSequence actionWithDuration:(intervalforEnemyshoot)];
id hitBulletSeq = [CCSequence actions: hitBulletAction, actionMove, nil];
[hitBulletSeq setTag:5];
[self schedule:#selector(update:)];
[hitBullet runAction:hitBulletSeq];
}
-(void)update:(ccTime)dt
{
if ( (CGRectIntersectsRect(hitRect, playerRect)) )
{
[[[self getActionByTag:5] retain] autorelease];
[hitBullet stopActionByTag: 5];
}
}
While prog1 is working prog2 is not working ? I think the both are same. But why the two stopActions are working differently in two prog1 and prog2 ? I mean the actions are stopped in prog1 but the actions are not stopping in prog2 ?
thank You.
Srikanth, what version of cocos2d are you using?
The answer to your question is no. All actions are treated the same.
The code responsible for removing the action is the following:
// -[CCActionManager removeActionByTag:target:]
-(void) removeActionByTag:(int) aTag target:(id)target
{
NSAssert( aTag != kActionTagInvalid, #"Invalid tag");
NSAssert( target != nil, #"Target should be ! nil");
tHashElement elementTmp;
elementTmp.target = target;
tHashElement *element = ccHashSetFind(targets, CC_HASH_INT(target), &elementTmp);
if( element ) {
NSUInteger limit = element->actions->num;
for( NSUInteger i = 0; i < limit; i++) {
CCAction *a = element->actions->arr[i];
if( a.tag == aTag && [a originalTarget]==target)
return [self removeActionAtIndex:i hashElement:element];
}
// CCLOG(#"cocos2d: removeActionByTag: Action not found!");
} else {
// CCLOG(#"cocos2d: removeActionByTag: Target not found!");
}
}
What I would recommend you do is turn on Cocos2d debugging, and un-comment those two CCLog lines. That should tell you if there's a problem in there.
If that doesn't tell you anything, it may be of interest to look into the CCSequence class. Perhaps, if the sequence is being removed, it doesn't remove the actions IN the sequence itself?
All actions are treated equal, but perhaps this Sequence action should be an exception to that.