In this tutorial we cover the following topics
- Data types sources of informations
- Excercise 1
- Excercise 2
- Hint 1 for the exercises
- Hint 2 for the exercises
Data types sources of informations
Excercise 1: class for multidimensional (2D) array
- Assumptions
- Class should allow to store objects in a dynamic 2D array.
Excercise 2: runners log application
- Assumptions
- Application should read data from a text file.
- Each line describes one training.
- Training data are expressed in the form
1data_name_1:"value 1" data_name_2:"value 2" ... data_name_n:"value n" - Not all training data are obligatory - some of them may be missing.
- The following data are defined
- Training date
- Training time
- Distance
- Time
- Equipment (for example shoes)
- You may also add your own data types
- The user should have a menu with options like
- Print total distance
- Print total training time
- Print an average speed
- Print total distence per week
- etc
Hint 1 for the exercises
Simple application which reads some data from a file, creates an array and puts this data into array. Note that the following code is just a hint so it doesn't work as 2D array but as 1D array. Anyway some names and comments related to 2D array were used to help implement desired solution.
1 2 3 4 5 6 7 8 9 10 |
#import <Foundation/Foundation.h> @interface Array2D : NSObject{ NSMutableArray * array; } - (id)initWithCapacity: (int) capacity; -(void) add: (NSObject*) element index:(int) index; - (NSObject *) get: (int) index; @end |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
#import "Array2D.h" @implementation Array2D - (id)initWithCapacity: (int) capacity{ self = [super init]; if (self) { array = [[NSMutableArray alloc] initWithCapacity: capacity]; for (int i=0; i<capacity; i++) { [array setObject:[NSNull null] atIndexedSubscript: i]; } } return self; } -(void) add: (NSObject*) element index:(int) index{ [array replaceObjectAtIndex: index withObject: element]; } - (NSObject *) get: (int) index{ return array[index]; } @end |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
/* This application reads a file of the format 10 0 foo_0 2 foo_2 7 foo_7 where line 0: max number of elements line 1: number of columns line x: <index><space><string_without_space> */ #import <Foundation/Foundation.h> #import "Array2D.h" int main(int argc, const char * argv[]) { @autoreleasepool { int capacity = 0; int numberOfDataLines; int index; // Reading data from a file NSString *filepath = @"/Users/fulmanp/Desktop/iOS/tutorials/ReadFileTest/data.txt"; //Don't know how to use the follwing on OS X //NSString *filepath = [[NSBundle mainBundle] pathForResource:@"running_data" ofType:@"strings"]; NSError *error; NSLog(@"Use path: %@", filepath); NSString *fileContents = [NSString stringWithContentsOfFile:filepath encoding:NSUTF8StringEncoding error:&error]; if (error) NSLog(@"Error reading file: %@", error.localizedDescription); // Process this data NSArray *dataLines = [fileContents componentsSeparatedByString:@"\n"]; NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init]; numberFormatter.numberStyle = NSNumberFormatterDecimalStyle; NSNumber *number = [numberFormatter numberFromString: dataLines[0]]; if (number){ capacity = [number intValue]; Array2D * myArray = [[Array2D alloc] initWithCapacity: capacity]; numberOfDataLines = (int)([dataLines count]); for(int i = 1; i < numberOfDataLines; ++i){ NSArray *data = [dataLines[i] componentsSeparatedByString:@" "]; number = [numberFormatter numberFromString: data[0]]; if (number){ index = [number intValue]; if (index < capacity){ [myArray add: data[1] index: index]; } } } NSObject * obj; for(int i=0; i<capacity; ++i){ obj = [myArray get: i]; if ([obj isKindOfClass:[NSNull class]]){ NSLog(@"At index %d we have: ---", i); } else { NSLog(@"At index %d we have: %@", i, [myArray get: i]); } } } } return 0; } |
Tested with a file
1 2 3 4 |
10 0 foo_0 2 foo_2 7 foo_7 |
should return something similar to
2016-03-18 16:55:34.635 ReadFileTest[14412:1484597] Use path: /Users/fulmanp/Desktop/iOS/tutorials/ReadFileTest/data.txt
2016-03-18 16:55:34.643 ReadFileTest[14412:1484597] At index 0 we have: foo_0
2016-03-18 16:55:34.643 ReadFileTest[14412:1484597] At index 1 we have: ---
2016-03-18 16:55:34.643 ReadFileTest[14412:1484597] At index 2 we have: foo_2
2016-03-18 16:55:34.644 ReadFileTest[14412:1484597] At index 3 we have: ---
2016-03-18 16:55:34.644 ReadFileTest[14412:1484597] At index 4 we have: ---
2016-03-18 16:55:34.644 ReadFileTest[14412:1484597] At index 5 we have: ---
2016-03-18 16:55:34.644 ReadFileTest[14412:1484597] At index 6 we have: ---
2016-03-18 16:55:34.644 ReadFileTest[14412:1484597] At index 7 we have: foo_7
2016-03-18 16:55:34.644 ReadFileTest[14412:1484597] At index 8 we have: ---
2016-03-18 16:55:34.645 ReadFileTest[14412:1484597] At index 9 we have: ---
Program ended with exit code: 0
Hint 2 for the exercises
- Assumptions
- Application should read data from a text file.
- Each line describes one training.
- Training data are expressed in the form
1[date] [distance (in meters)] [time (in seconds)] - One training data should be represented in application as an object.
- All training data (object) should be collected in an array.
1 2 3 4 5 6 7 8 9 10 11 12 |
#import <Foundation/Foundation.h> @interface Record : NSObject{ } - (void) setDataDate:(NSString *)dateValue withDuration: (NSString *) durationValue withDistance: (NSString *) distanceValue; -(NSString *) getAllDataAsString; @end |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
#import "klasa.h" @implementation Record { NSDate * date; int duration; int distance; } -(void) setDataDate:(NSString *)dateValue withDuration: (NSString *) durationValue withDistance: (NSString *) distanceValue { int tmp; // Deal with integer values NSNumber *number; NSNumberFormatter *numberFormatter= [[NSNumberFormatter alloc]init]; numberFormatter.numberStyle=NSNumberFormatterDecimalStyle; number = [numberFormatter numberFromString: durationValue]; duration = [number intValue]; number = [numberFormatter numberFromString: distanceValue]; distance = [number intValue]; // Deal with time NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; NSDateComponents *components = [[NSDateComponents alloc] init]; NSArray *dateComponentsAsString = [dateValue componentsSeparatedByString: @"-"]; tmp = [[numberFormatter numberFromString: dateComponentsAsString[0]] intValue]; [components setYear:tmp]; tmp = [[numberFormatter numberFromString: dateComponentsAsString[1]] intValue]; [components setMonth:tmp]; tmp = [[numberFormatter numberFromString: dateComponentsAsString[2]] intValue]; [components setDay:tmp]; date = [calendar dateFromComponents:components]; } -(NSString *) getAllDataAsString { NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; NSCalendarUnit units = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay; NSDateComponents *components = [calendar components:units fromDate:date]; NSString * dateAsString = [NSString stringWithFormat:@"%4ld-%02ld-%02ld", [components year], [components month], [components day]]; return [NSString stringWithFormat:@"%@ %d %d", dateAsString, duration, distance]; } @end |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
#import "klasa.h" #import <Foundation/Foundation.h> int main(int argc, const char * argv[]) { @autoreleasepool { NSMutableArray * runningData = [[NSMutableArray alloc] init]; NSString * filepath = @"/Users/fulmanp/Desktop/iOS/app_data/projekcik/run.txt"; NSError *error; NSString* fileContents = [NSString stringWithContentsOfFile:filepath encoding:NSUTF8StringEncoding error: &error]; if (error) { NSLog(@"%@",error.localizedDescription); } else { NSArray *dataLines = [fileContents componentsSeparatedByString: @"\n"]; int numberOfLines =(int)[dataLines count]; NSArray *line; for(int i=0; i<numberOfLines; i++){ line = [dataLines[i] componentsSeparatedByString: @" "]; if ((int)[line count] == 3){ Record * record = [[Record alloc] init]; [record setDataDate: line[0] withDuration: line[1] withDistance: line[2]]; [runningData addObject: record]; } } int numberOfRecords =(int)[runningData count]; for(int i=0; i<numberOfRecords; i++){ NSLog(@"%@", [runningData[i] getAllDataAsString]); } } } return 0; } |
2016-03-31 18:48:21.108 projekcik[1428:104176] 2016-03-13 1000 5
2016-03-31 18:48:21.109 projekcik[1428:104176] 2016-03-15 1500 7
2016-03-31 18:48:21.109 projekcik[1428:104176] 2016-03-22 2000 9
Program ended with exit code: 0
If you want you can use
argc
and argv
arguments to pass file name to the application. To test it in Xcode please visit Scheme Editor settings page (you can use command
+ shift
+ <
)
- From the Scheme toolbar menu, choose a scheme.
- From the same menu, choose Edit Scheme to display the scheme dialog.
- In the left column, select Run.
- To specify runtime arguments, click Arguments and then click the Add button.
- Click Close.
- Click the Run button or choose Product > Run.