0

I have experience with Java and Android development, and am now attempting to learn Objective-C and iPhone/iPad development. In order to help teach myself, I am re-writing an application I made for android over to iPhone.

The specific problem I am having has to do with using the NSScanner class. In my android application, I read in a txt file(with multiple lines) and built "member" objects that get loaded into an array. Each member has general contact info being a first name, last name, phone number, email, pledge class and major. This text file was written by me so I know the exact formatting. Below is an example of one line in the text file.

Fawzy   Jake    8144425471  someemail@gmail.com Beta    Criminal Justice & Psych Minor

In Java/android I was able to load the desired results by using multiple scan.Next() and then a scan.nextLine() for the major. Can anyone help point me in the right direction of how to use NSScanner/objective-c to perform a similar operation? Specifically, I would like to know how to properly scan through the text file/string, then build my member object with the information I grabbed from the string.

Below is an example of my code that I have been working on, but am having trouble putting what I want to do logically into syntax as I am not familiar with objective-c.

- (NSString *)loadFileToString{
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"akpsi_contact_list"
                                                     ofType:@"txt"];
NSError *error = nil;
NSString *fileContent = [NSString stringWithContentsOfFile:filePath
                                                  encoding:NSUTF8StringEncoding
                                                     error:&error];
if(error)
{
    NSLog(@"ERROR while loading from file: %@", error);
}
return fileContent;
}

-(void)readFileString{
NSScanner *scanner = [NSScanner scannerWithString: self.loadFileToString];
while ([scanner isAtEnd] == NO) {

    //member object
    AKPsiMember *member;

    //temporary variables
    NSString *thisFirstName;
    NSString *thisLastName;
    NSString *thisPhoneNum;
    NSString *thisEmail;
    NSString *thisPledge;
    NSString *thisMajor;

    //scan one line, save 
    [scanner scanUpToString:@" " intoString:&thisFirstName];
    [scanner scanUpToString:@" " intoString:&thisLastName];
    [scanner scanUpToString:@" " intoString:&thisPhoneNum];
    [scanner scanUpToString:@" " intoString:&thisEmail];
    [scanner scanUpToString:@" " intoString:&thisPledge];
    [scanner scanUpToString:@" " intoString:&thisMajor];
    //build member object with temporary variables
    // implementation must continue to next line...
}    

}

Also my member object/class

.h

@interface AKPsiMember : NSObject{
NSString *firstName;
NSString *lastName;
NSString *emailAddress;
NSString *pledgeClass;
NSString *major;
NSString *phoneNum;


}

@property (nonatomic, strong) NSString *firstName;
@property (nonatomic, strong) NSString *lastName;
@property (nonatomic, strong) NSString *emailAddress;
@property (nonatomic, strong) NSString *pledgeClass;
@property (nonatomic, strong) NSString *major;
@property (nonatomic, strong) NSString *phoneNum;


@end

And my .m

@implementation AKPsiMember

@synthesize firstName = _firstName;
@synthesize lastName = _lastName;
@synthesize phoneNum = _phoneNum;
@synthesize emailAddress = _emailAddress;
@synthesize pledgeClass = _pledgeClass;
@synthesize major = _major;

- (NSString *)phoneNum:(NSNumber *)num
{
if(num == 0)
{
    NSString *temp1 = [self.phoneNum substringWithRange:NSMakeRange(0, 3)];
    NSString *temp2 = [self.phoneNum substringWithRange:NSMakeRange(3, 6)];
    NSString *temp3 = [self.phoneNum substringWithRange:NSMakeRange(6, 9)];

    NSString *formatNum = [NSString stringWithFormat: @"(%@) %@-%@", temp1, temp2, temp3];
    return formatNum;
}
else{
    return self.phoneNum;
}
}

@end
rmaddy
  • 314,917
  • 42
  • 532
  • 579
bmjohns
  • 6,344
  • 1
  • 33
  • 39

1 Answers1

2

After you scanned all your fields you should scan the newline character in order to proceed to the next line:

NSCharacterSet *whitespace = [NSCharacterSet whitespaceCharacterSet];
[scanner scanUpToCharactersFromSet:whitespace intoString:&thisFirstName];
[scanner scanCharactersFromSet:whitespace intoString:nil];        
[scanner scanUpToCharactersFromSet:whitespace intoString:&thisLastName];
[scanner scanCharactersFromSet:whitespace intoString:nil];
[scanner scanUpToCharactersFromSet:whitespace intoString:&thisPhoneNum];
[scanner scanCharactersFromSet:whitespace intoString:nil];
[scanner scanUpToCharactersFromSet:whitespace intoString:&thisEmail];
[scanner scanCharactersFromSet:whitespace intoString:nil];
[scanner scanUpToCharactersFromSet:whitespace intoString:&thisPledge];
[scanner scanCharactersFromSet:whitespace intoString:nil];

NSCharacterSet *newLineCharacterSet = [NSCharacterSet newlineCharacterSet];
[scanner scanUpToCharactersFromSet:newLineCharacterSet intoString:&thisMajor];
[scanner scanCharactersFromSet:newLineCharacterSet intoString:nil];

Create the NSMutableArray before the loop.

NSMutableArray *members = [NSMutableArray array];

Set the values inside the loop and add your Object to the members array.

AKPsiMember *member = [[AKPsiMember alloc] init];
member.firstName = thisFirstName;
// ... set other properties
[members addObject:member];

This code will break when there are whitespaces in between the first fields of your dataset. Obviously this could be broken down into methods and results should be checked.

Karl
  • 1,233
  • 8
  • 16
  • Ok great thank you for that answer! My last question is how do I build/set the fields I have now gotten to my created AKPsiMember *member object. Normally in Java I would simply put AKPsiMember member = new member(thisFirstName, thisLastName, ect...) then add that member to my array. – bmjohns Jun 24 '13 at 21:02
  • I added some code to set properties and add that object to the array. – Karl Jun 25 '13 at 05:13
  • Sorry, I appear to be having a problem with setting putting the objects in my array, as in the objects are being built correctly, but the array is empty when I go to reference it, like lets say to fill a table view. Would you mind looking at my AKPsiMember class above? If AKPsiMember is made up of a firstName, lastName, ect. Did I define it correctly in my .m & .h files? Also, if it makes a difference which it might, my mutable arrays are defined in my .h file for the class that the string scanner is located, instead of in the actual method – bmjohns Jun 25 '13 at 17:37
  • Are you sure that your array is initialised? Just add a breakpoint at the point where you're adding an object and make sure its not nil. – Karl Jun 25 '13 at 17:43
  • Yikes, dumb move by me. My Array fills properly now. I have one last question if you don't mind. When running through the debugger, I noticed that my member object is filled with duplicates of my NSString variables. As in there is a firstName that is filled with null, and also a _firstName that is filled with the proper string. Is this normal or is something amiss? – bmjohns Jun 25 '13 at 18:27
  • 1
    In your header file you're declaring properties such as firstName and an ivar with the same name. In the implementation you're synthezing your property with firstName = _firstName which tells the compiler to create a getter and set which will be backed by an ivar named _firstName. Therefor your other ivar is not used anymore. You should get rid of the ivars in the header files and the @synthesize in your implementation file because Xcode will do that automatically for you. – Karl Jun 25 '13 at 18:32