A little background here before I get started, basically we are looking to compare a UDP response with a string stored in Parse's database for our app. This issue is that I can't seem to get the strings to be considered equal by the isEqualToString function. Here's the code I have running now, I have tried a few work-arounds I've seen in other questions but it still doesn't work.
- (BOOL) onUdpSocket:(AsyncUdpSocket *)sock didReceiveData:(NSData *)data withTag:(long)tag fromHost:(NSString *)host port:(UInt16)port
{
if(tag == TAG_SINGLE_GRILL)
{
NSString *grillId = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
if(grillId.length > 11)
{
grillId = [grillId substringToIndex:11];
}
grillId = [NSString stringWithFormat:#"%#", grillId];
if([grillId hasPrefix:#"GMG"])
{
for(int i = 0; i < [parseGrills count]; i++)
{
NSString *parseGrillId = [[parseGrills objectAtIndex:i] grillId];
parseGrillId = [NSString stringWithFormat:#"%#", parseGrillId];
//If we match the id, add it to found grills
if([grillId isEqualToString:parseGrillId])
{
//do stuff
}
}
}
NSLog(#"Grill ID : %#", grillId);
}
return TRUE;
}
parseGrills is an NSMutableArray with a very basic Grill object, I use synthesize for the properties, otherwise the .m file is essentially empty.
#import <Foundation/Foundation.h>
#interface Grill : NSObject
#property (nonatomic) NSString* grillId;
#property (nonatomic) NSString* ipAddress;
#end
Here's a screen shot of the debugger after it returns false
Any help would be greatly appreciated. Thanks.
I guess that they are of different encoding.
I have run this experiment and see that if the encoding is different, it will return NO. So, try converting parseGrillId to utf8 with the code below.
NSString *s1 = [NSString stringWithCString:"HELLO123" encoding:NSUTF8StringEncoding];
NSString *s2 = [NSString stringWithCString:"HELLO123" encoding:NSUTF16StringEncoding];
NSString *s3 = [NSString stringWithUTF8String:s2.UTF8String];
if ([s1 isEqualToString:s2]) {
NSLog(#"s1 == s2");
}
if ([s1 isEqualToString:s3]) {
NSLog(#"s1 == s3");
}
Will print s1 == s3.
Related
I mainly program in Java and can't understand why this isn't working. I'm trying to create a temporary object "Judge" in my for loop. I then want to add that object to an NSMutableArray so in the end I have an array filled with different Judge objects. After the for loop I run through all the objects in the Array and they're all the last Judge Object.
The NSLog shows that "JudgeTemp" object is being assigned the right values while in the for loop. My guess is that it's not creating a new object called JudgeTemp every time but referencing the old already created JudgeTemp.
NSMutableArray *Judges = [NSMutableArray arrayWithCapacity:30];
for (int i=0; i<[courtinfoarray count]; i++) {
Judge1= [[courtinfoarray objectAtIndex:i] componentsSeparatedByString:#"|"];
Judge *JudgeTemp=[[Judge alloc]init];
[JudgeTemp setName:[Judge1 objectAtIndex:0] picture:[Judge1 objectAtIndex:1] courtroom:[Judge1 objectAtIndex:2] phone:[Judge1 objectAtIndex:3] undergrad:[Judge1 objectAtIndex:4] lawschool:[Judge1 objectAtIndex:5] opdasa:[Judge1 objectAtIndex:6] career:[Judge1 objectAtIndex:7] judgecode:[Judge1 objectAtIndex:8]];
NSLog(#"%#",[JudgeTemp getName]);
[Judges addObject:JudgeTemp];
NSLog(#"%#",[[Judges objectAtIndex:i]getName]);
}
Judges Class
#implementation Judge
NSString *name;
NSString *picture;
NSString *courtroom;
NSString *phone;
NSString *undergrad;
NSString *lawschool;
NSString *opdasa;
NSString *career;
NSString *judgecommentcode;
-(void) setName:(NSString *)n picture:(NSString *) p courtroom:(NSString *)c phone:(NSString *)ph undergrad: (NSString *) u lawschool: (NSString *)l opdasa: (NSString *) o career: (NSString *)ca judgecode: (NSString *)jcode{
name = n;
picture = p;
courtroom = c;
phone = ph;
undergrad = u;
lawschool = l;
opdasa = o;
career = ca;
judgecommentcode = jcode;
}
-(NSString*) getName{
return name;
}
The problem is with your Judge class. When you define variables directly in your #implementation they have global scope and are not instance variables. What you need to do is put those variable declarations in your #interface instead:
#interface Judge : NSObject {
NSString *name;
NSString *picture;
NSString *courtroom;
NSString *phone;
NSString *undergrad;
NSString *lawschool;
NSString *opdasa;
NSString *career;
NSString *judgecommentcode;
}
// ...
#end
Edit: Apparently you can declare them in your #implementation, you just have to wrap them in { }. See: Instance variables declared in ObjC implementation file
I'm currently teaching myself Objective-C as a first language. I understand the difficulty involved, but I'm quiet a persevering individual. I've began to do the exercises on the Apple Objective-C documentation. My goal is to have my program log out my first and last name instead of a generic Hello World greeting.
I keep receiving a Use of Undeclared identifier error. I'm trying to figure out what is causing the error.
Here is the introClass.h
#import <UIKit/UIKit.h>
#interface XYZperson : NSObject
#property NSString *firstName;
#property NSString *lastName;
#property NSDate *dateOfBirth;
- (void)sayHello;
- (void)saySomething:(NSString *)greeting;
+ (instancetype)person;
-(int)xYZPointer;
-(NSString *)fullName;
#end
Here is IntroClass.m
#import "IntroClass.h"
#implementation XYZperson
-(NSString *)fullName
{
return[NSString stringWithFormat:#" %# %#", self.firstName, self.lastName];
}
-(void)sayHello
{
[self saySomething:#"Hello %#", fullName]; //use of undeclared identifier "fullName"
};
-(void)saySomething:(NSString *)greeting
{
NSLog(#"%#", greeting);
}
+(instancetype)person{
return [[self alloc] init];
};
- (int)xYZPointer {
int someInteger;
if (someInteger != nil){
NSLog(#"its alive");
}
return someInteger;
};
#end
The problem is that fullName is the name of a method. It should be invoked on self with square brackets.
Since saySomething: expects a single parameter, you need to either (1) remove the #"Hello %#" portion of the call, like this:
-(void)sayHello {
[self saySomething:[self fullName]];
};
or to make a single string from #"Hello %#" and [self fullName], like this:
-(void)sayHello {
[self saySomething:[NSString stringWithFormat:#"Hello %#", [self fullName]]];
};
You are passing back a string of first and last name but I don't see anywhere that you had set a value for them. As others noted try
-(void)sayHello
{
_firstName = [NSString stringWithFormat:#"John"];
_lastName = [NSString stringWithFormat:#"Doe"];
//if you want to see what's happening through out your code, NSLog it like
NSLog(#"_firstName: %# ...", _firstName);
NSLog(#"_lastName: %# ...", _lastName);
NSString *strReturned = [self fullName];
NSString *concatStr = [NSString stringWithFormat:#"Hello %#", strReturned];
NSLog(#"strReturned: %# ...", strReturned);
NSLog(#"concatStr: %# ...", concatStr);
[self saySomething:concatStr];
};
-(NSString *)fullName
{
return[NSString stringWithFormat:#" %# %#", self.firstName, self.lastName];
}
use
[self saySomething:#"Hello %#", self.fullName]];
or
[self saySomething:#"Hello %#", [self fullName]];
Note: As I've posted this question, it's night time here in my place. If I haven't responded to comments or answers, I'll do it in the morning. Thank you for your understanding :-)
The idea is to format UILabel as phone number (US Format) as the user touches each UIButton.
There is a keypad layout and as the user touches each numeric key, the label displays it and at formats the resulting string on the fly. I have written a piece of code which I am not very proud of. I hope someone could help me in doing this in much better way or different approach.
The image should give you a fair idea of how it looks like. Now, getting to the logic:
In the code below, keyOne is the IBAction to append the numbers to UILabel, keyBack is the one to delete it.
So this is how it works for entering a phone number:
If I enter 1234567890:
after 1,2,3 the label is modified as 123- and gets assigned to string
Now string will be 123- and I continue touching 4567890
after 123-4567, when I touch 8, label is modified as (123)456-78 and gets assigned to string
Now string will be (123)456-7890
If I wish, I could continue entering more numbers.
As per requirement, the number should lose its formatting.
i.e. After (123)456-7890 if I press 1, it should become 12345678901
Now, the trick is to undo the steps in exact same way. Here is the pickle.
If I entered only 1234567890, _phoneNumber.text would be (123)456-7890 and pressing back three times should result in 123-4567. Then pressing back four times should result in 123
However, if I entered 12345678901, _phoneNumber.text would go to (123)456-7890, then lose formatting to become 12345678901 and when I press back once, it should become (123)456-7890 and so on.
If you whip up a new project of type single view application and paste the stuff below, (of course after creating buttons and connecting 0-9 with keyOne, back with keyBack) you would see that it works fine. But as I mentioned above, I have written a piece of code which I am not very proud of. I feel there should be a simpler way to do this.
ViewController.h
#interface ViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *lengthParam;
#property (weak, nonatomic) IBOutlet UILabel *phoneNumber;
- (IBAction)keyOne:(id)sender;
- (IBAction)keyBack:(id)sender;
- (IBAction)clearAll:(id)sender;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController () {
BOOL isReformatted;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (IBAction)keyOne:(id)sender {
UIButton *btn = (UIButton *)sender;
NSString *str = [NSString stringWithString:self.phoneNumber.text];
str = [str stringByAppendingString:btn.titleLabel.text];
self.phoneNumber.text = str;
if(str.length==4) self.phoneNumber.text = [self insertMinus:str]; //before the 4th number, insert '-' as a first step
if(str.length==9) self.phoneNumber.text = [self insertParenthesis:str]; //remove - before the 4th number, encapsulate first 3 numbers inside () and add - at end of current number
if(str.length>13) self.phoneNumber.text = [self plainFormat:str]; //if user enter more than 10 numbers, remove formatting
self.lengthParam.text = [NSString stringWithFormat:#"%d",self.phoneNumber.text.length];
}
- (IBAction)keyBack:(id)sender {
NSString *str = [NSString stringWithString:self.phoneNumber.text];
NSString *newStr = nil;
if(str.length>0) { //check for empty string
if(str.length>11 && isReformatted==NO) newStr = [str substringToIndex:str.length-1]; //string.length > 10 which means plainFormat was called earlier and reFormat isn't called yet
else if(str.length==11 && isReformatted == NO) { //string length is now 11
if([str characterAtIndex:0]!='(') newStr = [self reFormat:str]; //if entered string is 12345678901, it is not reFormatted. remove last 1 and reFormat it as (123)456-7890
else newStr = [self removeParenthesis:str]; //entered string itself is (123)456-78 so transform it as 123-4567
} else { //we are dealing with a reformatted string of length 11 now.
newStr = [str substringToIndex:str.length-1]; //String is (123)456-78, remove 8 and apply one of the below rules
if(newStr.length==10) { //transform (123)456-7 as 123-4567
newStr = [str substringToIndex:str.length-1];
newStr = [self removeParenthesis:str];
}
if(newStr.length==4&&[newStr characterAtIndex:3]=='-') newStr = [self removeMinus:str]; //transform 123-4 to 123
}
self.phoneNumber.text = newStr;
self.lengthParam.text = [NSString stringWithFormat:#"%d",self.phoneNumber.text.length];
}
}
- (IBAction)clearAll:(id)sender {
self.phoneNumber.text = #"";
self.lengthParam.text = [NSString stringWithFormat:#"%d",self.phoneNumber.text.length];
}
- (NSString *)insertMinus:(NSString *)str {
return [NSString stringWithFormat:#"%#-%#",[str substringToIndex:3],[str substringFromIndex:3]];
}
- (NSString *)insertParenthesis:(NSString *)str {
NSString *c1 = [NSString stringWithFormat:#"(%#)",[str substringToIndex:3]];
NSString *c2 = [NSString stringWithFormat:#"%#-%#",[str substringWithRange:NSMakeRange(4, 3)],[str substringFromIndex:7]];
return [NSString stringWithFormat:#"%#%#",c1,c2];
}
- (NSString *)plainFormat:(NSString *)str {
isReformatted = NO;
str = [str stringByReplacingOccurrencesOfString:#"(" withString:#""];
str = [str stringByReplacingOccurrencesOfString:#")" withString:#""];
str = [str stringByReplacingOccurrencesOfString:#"-" withString:#""];
str = [str stringByReplacingOccurrencesOfString:#" " withString:#""];
return str;
}
- (NSString *)reFormat:(NSString *)str {
isReformatted = YES;
NSString *c1 = [NSString stringWithFormat:#"(%#)",[str substringToIndex:3]];
NSString *c2 = [NSString stringWithFormat:#"%#-%#",[str substringWithRange:NSMakeRange(3, 3)],[str substringWithRange:NSMakeRange(6, 4)]];
return [NSString stringWithFormat:#"%#%#",c1,c2];
}
- (NSString *)removeParenthesis:(NSString *)str {
str = [self plainFormat:str];
NSString *newStr = [NSString stringWithFormat:#"%#-%#",[str substringToIndex:3],[str substringWithRange:NSMakeRange(3, 4)]];
return newStr;
}
- (NSString *)removeMinus:(NSString *)str {
str = [self plainFormat:str];
NSString *newStr = [NSString stringWithFormat:#"%#",[str substringToIndex:3]];
return newStr;
}
#end
If you are eager to go down the road of rolling your own phone number formatter, I would consider doing the follow:
Store the user input without formatting in a string.
After each key press, reformat the display string.
Something like:
#property (nonatomic, copy) NSMutableString *backingString;
#property (weak, nonatomic) IBOutlet UILabel *phoneNumber;
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
backingString = [NSMutableString string];
}
- (IBAction)keyOne:(id)sender
{
UIButton *btn = (UIButton *)sender;
[self.backingString appendString:btn.titleLabel.text];
[self formatBackingString];
}
- (IBAction)keyBack:(id)sender
{
[self.backingString deleteCharactersInRange:(NSRange){self.backingString.length - 1,1}];
[self formatBackingString];
}
- (void)formatBackingString
{
// Do your phone formatting here
NSMutableString *formattedString = [NSMutableString string];
NSInteger length = self.backingString.length;
if (length < 3)
{
[formattedString appendString:self.backingString];
}
else if (length == 3)
{
[formattedString appendFormat:#"%#-", self.backingString];
}
else if (length < 8)
{
// etc...
}
self.phoneNumber.text = formattedString;
}
You could also look at NSNumberFormatter.
I moved some code that will be used multiple times into a class.
I'm not getting errors, but I'm also not getting results. It seems to skip over my class completely.
Ideally, this class is supposed to do NSURL conns and XMLParser stuff to chew up the data feed from our hosting API. I already have this working but wanted to congeal and somewhat normalize/centralize some of the main logic of my code.
The one function 'bdCheckIfFileExistsAndisValid' is supposed to take a string but return BOOL and it isn't being called at all.
Neither is 'bdParsePlaylistXML' that is supposed to take a string and return an array.
I put breakpoints everywhere in my class and none are hit.
I'm new so I'm not sure if I did everything right. Here's some code, thanks in advance.
--------------------CUSTOM CLASS:(.h)
#interface bdXMLParser : NSObject {
NSMutableArray *playlist;
//Playlist XML info
BOOL recordTrackName;
BOOL recordTrackDescription;
BOOL recordTrackThumbnailAbsoluteLocation;
BOOL recordTrackURL;
NSString *TrackName;
NSString *TrackDescription;
NSString *TrackThumbnailAbsoluteLocation;
NSString *TrackURL;
}
-(NSMutableArray*) bdParsePlaylistXML:(NSString *) playlistXMLFileName;
-(BOOL) bdCheckIfFileExistsAndisValid:(NSString *) localFileName;
----------------CUSTOM CLASS (.m):
#import "bdXMLParser.h"
#implementation bdXMLParser
{
NSMutableData *webData;
NSMutableArray *playlist;
NSXMLParser *xmlParserPlaylist;
}
-(NSString*) bdDocumentsDirectory{
NSString* documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
return documentsPath;
}
-(int) bdCheckFileCreationDate:(NSString *) fileName {
//get XML file path
NSString *localFilePath = [[self bdDocumentsDirectory] stringByAppendingPathComponent:fileName];
//local file check
NSFileManager *filemgr;
filemgr = [NSFileManager defaultManager];
NSDictionary* attrs = [filemgr attributesOfItemAtPath:localFilePath error:nil];
NSDate *fileCreationDate = [attrs objectForKey: NSFileCreationDate];
NSDate *rightNow = [NSDate date];
NSTimeInterval lastDiff = [fileCreationDate timeIntervalSinceNow];
int lastDiffINT = round(lastDiff);
NSLog(#"NSFileCreationDate:%#",fileCreationDate);
NSLog(#"CurrentDate:%#",rightNow);
NSLog(#"lastDiff:%f",lastDiff);
return lastDiffINT;
}
-(BOOL) bdCheckIfFileExistsAndisValid:(NSString *) fileName {
//local file check
NSString* foofile = [[self bdDocumentsDirectory] stringByAppendingPathComponent:fileName];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:foofile];
if ((fileExists == YES) && ([self bdCheckFileCreationDate:foofile] > -86400))//(24 hrs = 86400 seconds)
return YES;
else
return NO;
}
HERE's THE VIEW WHERE I'M TRYING TO USE IT:(menu.h)
#import "bdXMLParser.h"
#interface MenuScreenViewController : UIViewController <NSXMLParserDelegate>
- (IBAction)btnPlayerPlayPause:(id)sender;
(menu.m)
- (IBAction)btnPlayerPlayPause:(id)sender {
//if array exists, don't reload xml, dont reparse xml, just go to the view
if (playlist.count == 0){
//Playlist!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//========================================================================
//1st: check to see if we have a local cached xml data
//if we do, check if it is <24hr old and if so load it
//if not, go get it with connection and overwrite/store it
//init blogs NSMutableArray
playlist = [[NSMutableArray alloc] init];
//local file check
bdXMLParser *myParser;
BOOL fileExistsAndValid = NO;
=HERE!==fileExistsAndValid = [myParser bdCheckIfFileExistsAndisValid:PlaylistName];
//1st
if (fileExistsAndValid)//(<24 hrs old)
{
NSLog (#"File fileExistsAndValid");
=AND HERE!!=playlist = [myParser bdParsePlaylistXML:PlaylistName];
NSLog(#"playlist:%u", playlist.count);
//load first track
[self LoadTrack:0];
}
else{
NSLog (#"File doesn't exist");
//call refresh function
//[self refreshAlbumPhotoXML];
[myParser bdRefreshPlaylistXML];
}
}
}
you forgot initing the class
bdXMLParser *myParser= [[bdXMLParster alloc]init];
Still learning iOS development with ObjectiveC and iOS, and trying to realy understand memory management! Appreciate any advise on the snippet below, eg:
1) Analyser says there are potential memory leaks, but can't solve them?
2) Should I keep alloc and init the NSStrings in the for loop and when appended to?
Thanks
- (NSString *) lookUpCharNameForID: (NSString *) inCharID
{
debugPrint ("TRACE", [[#"Lookup Char Name for = " stringByAppendingString: inCharID] UTF8String]);
NSString *tempName = [[NSString alloc] initWithFormat: #""];
if (![inCharID isEqualToString: #""])
{
// Potentially lookup multiple values
//
NSString *newName = [[NSString alloc] initWithFormat: #""];
NSArray *idList = [inCharID componentsSeparatedByString: #","];
for (NSString *nextID in idList)
{
NSLog( #"Lookup %i : %#", [idList count], nextID);
newName = [[NSString alloc] initWithFormat: #"C%#", nextID];
// Append strings
if ([tempName isEqualToString: #""])
tempName = [[NSString alloc] initWithFormat: #"%#", newName];
else
tempName = [[NSString alloc] initWithFormat: #"%#+%#", tempName, newName];
}
[newName release];
}
return [tempName autorelease];
}
You don't need any of the calls to alloc, release, or autorelease. Instead, use [NSString stringWithFormat:] to create instances of NSString that you don't own, and therefore don't need to manage. Also, consider using NSMutableString to simplify your code a bit, for example along the lines of the following (untested) version:
- (NSString *) lookUpCharNameForID: (NSString *) inCharID
{
NSMutableString *tempName = nil;
if (![inCharID isEqualToString: #""])
{
NSArray *idList = [inCharID componentsSeparatedByString: #","];
for (NSString *nextID in idList)
{
[tempName appendString:#"+"]; // Does nothing if tempName is nil.
if (tempName == nil)
tempName = [NSMutableString string];
[tempName appendFormat:#"C%#", nextID];
}
}
return tempName;
}
You have 2 alloc initWithFormat for tempName. One before the loop and one within the loop.
Use ARC (Automatic Reference Counting) for new projects. For older projects it may be easy to convert them, if not ARC can be disabled on a file-by-file basis where necessary.
Using a mutable string, autoreleased convience methods and a little rerfactoring:
- (NSString *) lookUpCharNameForID: (NSString *) inCharID
{
NSMutableString *tempName = [NSMutableArray array];
if (inCharID.length)
{
NSArray *idList = [inCharID componentsSeparatedByString: #","];
for (NSString *nextID in idList)
{
if (tempName.length == 0)
[tempName appendFormat: #"%#C", nextID];
else
[tempName appendFormat: #"+%#C", nextID];
}
}
return tempName;
}