Saturday, September 5, 2015

iOS Tutorial - Part 34 - Split View Controller, iPad apps

Create an iPad app


Video Description 
In order to create an iPad app, all we have to do is to select iPad from the dropdown menu during the process of creating the application. It's also possible to make the existing app working on the iPad as well but this would be the subject of the future tutorial. For now we select iPad instead of iPhone when we want to create a new project.

Split View Controller

In order to create a master details view we need to use Split View Controller. If we start a new project by selecting Single View application, we can drag Split View Controller from Object library into Xcode interface. But in this tutorial we use the easiest way and instead of using single view app, we select Master-Detail Application so it adds some default classes and views for us. In Master part we have a tableView and we connect the cell via control+drag to the details view and from the opening popup for type of connection, we select the "Show Detail".

Download

Download this App from HERE.

Friday, August 7, 2015

iOS Tutorial - Part 33 - Core Data II

Core Data II


Video Description 
In previous session we learnt how to add items inside of database, in this tutorial we will learn how to search through the database and also the proper way of adding items inside of database.

Proper way of adding items in database

Previous tutorial showed the easiest way of adding items inside of database but here is the best practice of adding data into database:
+ (Students *)addStudentInfoFromDictionary:(NSDictionary *)studentInfo
{
    AppDelegate *appDelegate= (AppDelegate *)[[UIApplication sharedApplication] delegate];
    NSManagedObjectContext *context = [appDelegate managedObjectContext];
    
    Students *studentEntity = nil;
    
    NSString *studentId = studentInfo[@"studentId"];
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Students"];
    request.predicate = [NSPredicate predicateWithFormat:@"studentId = %@", studentId];
    
    NSError *error;
    NSArray *matches = [context executeFetchRequest:request error:&error];
    
    
    if (!matches || error || ([matches count] > 1))
    {
        //Handle Errors
    }
    else if ([matches count])
    {
        //Returns the existing object
        studentEntity = [matches firstObject];
    }
    else
    {
        //Create a new Object
        studentEntity = [NSEntityDescription insertNewObjectForEntityForName:@"Students" inManagedObjectContext:context];
        studentEntity.studentId = [studentInfo valueForKey:@"studentId"];
        studentEntity.name  = [studentInfo valueForKey:@"name"];
        studentEntity.lastName = [studentInfo valueForKey:@"lastName"];
        
        NSError *error;
        if (![context save:&error]) {
            NSLog(@"Whoops, couldn't save: %@", [error localizedDescription]);
        }
    }
    return studentEntity;
}
First we check for a unique identifier in order to avoid duplicating data. In this example studentId is our unique identifier. We request a fetch through the database via NSFetchRequest. It needs the entity name in order to be initialized. Our entity name is "Students" so we add Students as entity name. Then we define a predicate. Predicate is for defining our query for search. The following line means, give me all the data that has studentId that is equal to the one that is passed to this function.
[NSPredicate predicateWithFormat:@"studentId = %@", studentId];
Since during fetch request we may get some errors, we define NSError. Then we execute the fetch request and assign the result to an array because it returns all matched results as an array. Now we have to check the matches. If matches null or it's more than one item or error is not null, we know that we have error and this if statement is for handling errors. matches should not be more than one because studentId is unique and we should have only one instance of that ID.
If matches not null and equals one, it goes to the second statement. If it goes to this statement it shows that we had this item already in the database so we just return the mach that we found.
If non of the above statements get valid, we know that it's totally new item and we add it to the database. The implementations is exactly like the one that we had in previous session.

Query the database (Search through Core Data)

Suppose that we want to search the database to find all the matches for a specific name or specific lastname. The following method can search the database to find all matches for the name and lastname that you specify. It uses the same NSFetchRequest format that we used above. Also the same NSPredicate but with different format. This time we want to check for name, so it searches for name. If we want to search the name and lastname, we put AND in our format. There are other things that we can use in our format like OR. Based on your needs you can find the proper format and pass it into the predicateWithFormat. The second function is a helper function to create a temporary dictionary for each result.
+ (NSArray *)searchStudensByName:(NSString *)name lastname:(NSString *)lastname
{
    AppDelegate *appDelegate= (AppDelegate *)[[UIApplication sharedApplication] delegate];
    NSManagedObjectContext *context = [appDelegate managedObjectContext];
    
    NSError *error;
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Students"];
    request.predicate = [NSPredicate predicateWithFormat:@"name == %@ AND lastName == %@", name, lastname];
    
    NSArray *fetchedObject = [context executeFetchRequest:request error:&error];
    NSMutableArray *results = [[NSMutableArray alloc] init];
    
    for (Students *studentEntity in fetchedObject)
    {
        [results addObject:[self createObjectFromEntity:studentEntity]];
    }
    return results;
}

+(NSDictionary *)createObjectFromEntity:(Students *)studentInfo
{
    NSMutableDictionary *tempDict = [[NSMutableDictionary alloc] init];
    tempDict[@"name"] = studentInfo.name;
    tempDict[@"lastName"] = studentInfo.lastName;
    tempDict[@"studentId"] = studentInfo.studentId;
    return tempDict;
}

Download

Download this App from HERE.

Sunday, June 28, 2015

iOS Tutorial - Part 32 - Core Data I

Core Data I


Video Description 
In iOS we have two options for adding data into database. First option is Core Data and second option is SQLite. Since Core Data is more powerful and could be used in more object oriented way, so we will only talk about the first option, which is Core Data.

Add Entity, Add Attributes

If you check mark core data when you create the application, you would see a file with suffix "xcdatamodeld". If you click on it you would see
 
You can press plus button at the bottom of the page to add a new entity. Then you can add attributes by pressing add button under the attributes section. Each attribute needs a type. Here in the above screenshot all attributes are type string. Once we add all of the entities and attributes we want, we should create NSManagedObject subclass in order to have more object oriented programming style. To create NSManagedObject subclass, click on the file with suffix "xcdatamodeld" on your project structure and the from the tool menu, select Editor/Create NSManagedObject Subclass... .
Presee Next and then select the entity you want to create the subclass and then hit Create button to create your NSManagedObject class. If you open the created files you would see all of the attributes that you added for that entity. we can go ahead and add our a method in .m file for adding objects into database but it's not the best practice.

Category Files

Because later on the we may add more attribute into the application and if we auto generate the NSManagedObject superclass we would lose our functions, so it's better to add a Category class for this subclass. In order to create a category file, choose File / New / File ... Then select Objective-C File.
In the next screen give your file a name, and select a File Type as Category and select your entity name for the class field. Finally hit Create to create the Category file.

Add objects into database

Now we can add our method for adding objects into database. Here is the method we can create for adding objects:
+ (Students *)addStudentInfoFromDictionary:(NSDictionary *)studentInfo
{
    AppDelegate *appDelegate= (AppDelegate *)[[UIApplication sharedApplication] delegate];
    NSManagedObjectContext *context = [appDelegate managedObjectContext];
    
    Students *studentEntity = nil;
    
    //Create a new Object
    studentEntity = [NSEntityDescription insertNewObjectForEntityForName:@"Students" inManagedObjectContext:context];
    studentEntity.studentId = [studentInfo valueForKey:@"studentId"];
    studentEntity.name  = [studentInfo valueForKey:@"name"];
    studentEntity.lastName = [studentInfo valueForKey:@"lastName"];
    
    return studentEntity;
}
First two lines gets the context. Before using these two lines make sure you #import "AppDelegate.h" file. Next we create the instance of Students entity. We initialize it with the method insertNewObjectForEntityForName. Finally we can use entity properties to add our object value. Since we have this class in .m file we need to declare it in .h file so other classes can use it. So we should add the following line in the header file:
+ (Students *)addStudentInfoFromDictionary:(NSDictionary *)studentInfo;
Now we can use this method in any class we want. In this project we use it in our ViewController like bellow:
- (IBAction)addToDatabase:(UIButton *)sender
{
    NSDictionary *studentInfo = @{@"name": self.nameField.text,
                                  @"lastName": self.lastnameField.text,
                                  @"studentId": self.studentIdField.text};
    
    [Students addStudentInfoFromDictionary:studentInfo];
} 
Basically we create a dictionary with all the items we want to add into the database and then we pass it to the function that we creates in Student+Add class.

description property

Most Objective-C classes have a property called description. When you use this property it tries to get the description of that object. It's like toString method in other programming languages. We can use this property to get some output on the screen when we add an object into database. So we change the last line into the following line:
self.outPutTextView.text = [Students addStudentInfoFromDictionary:studentInfo].description; 

Download

Download this App from HERE.

Sunday, May 3, 2015

iOS Tutorial - Part 31 - NSNotificationCenter (Broadcasting an event)

NSNotificationCenter


Video Description 

In order to broadcast an event through the entire application, we can use NSNotificationCenter API. The usage is very simple, here are the steps: 1- Add (Register) the notification
[[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(dismissAddVC)
                                                 name:@"CallDismissAddVC"
                                               object:nil];
2- Write the method that we want to be called
- (void)dismissAddVC
{
    //implementation of the method
}
3- Post (Broadcast) notification
[[NSNotificationCenter defaultCenter] postNotificationName:@"CallDismissAddVC" object:nil];
4- Remove the observer
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"CallDismissAddVC" object:nil];
You should be careful not misuse NSNotificationCenter. For simple things like the app we created in this demo we better use delegate method, but for more complicated apps that you want to broadcast an event for more than 2 places, it's reasonable to use NSNotificationCenter.

Download

Download this App from HERE.

Sunday, March 15, 2015

iOS Tutorial - Part 30 - NSUserDefaults, UISwitch

NSUserDefaults, UISwitch


Video Description 

NSUserDefaults

Sometimes we want to save some small amount of data, which is mostly user preferences. For example if they choose to save their username, we should be able to save the username even if they kill the app. There is a useful API for doing this, which is NSUserDefaults. It can save some specific types. The types that NSUserDefaults can save are as follow: 1-NSString 2-NSArray 3-NSDictionary 4-NSData 5-NSDate 6-NSNumber.

Store preferences (User defaults)

If we want to save a username like HuxTek we can do it like bellow. We set a "HuxTek" value for a key "username". So whenever we want to retrieve the "HuxTek" we should call a key "username".
    [[NSUserDefaults standardUserDefaults] setValue:@"HuxTek" forKey:@"username"]
Now if we want to retrieve the username we can do something like bellow:
    [[NSUserDefaults standardUserDefaults] stringForKey:@"username"];
If we want to store a boolean value we can use the following api:
    [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"switchState"];
and for retrieve this boolean value we should have:
    [[NSUserDefaults standardUserDefaults] boolForKey:@"switchState"]

UISwitch

UiSwitch is a simple class with simple API. The most important APIs are as follow

isOn

If we want to check if the switch value is on or off, we can use this property like bellow:
if (self.mySwitch.isOn)
{
    //Do something when switch value is true (ON)
}
else
{
    //Do something when switch value is false (OFF)
}

setOn

In order to set the value of the switch programmatically we can use setOn api.
[self.rememberMeSwitch setOn:YES];

Download

Download this App from HERE.

Sunday, February 22, 2015

iOS Tutorial - Part 29 - Asynchronous HttpRequest

Asynchronous HttpRequest


Video Description 
In first, second and third session of HttpRequest we have learnt how to create a synchronous HttpRequest, in this session we will learn how to make a Asynchronous calls. We also learn how to add activity indicator to show the user some network calls are going on in the background.

Spinning wheel (Activity indicator)

Drag and drop Activity Indicator from Object Library from right side bar of Xcode. Add it to the storyboard of the project that we created in the previous session. Then control + drag it to it's class to create a property for it. Now in viewDidLoad before httpGetRequest method start the activity indicator like bellow:
[self.activityIndicator startAnimating];
Then we can stop it and hide it or remove it from the view like bellow:
    
    [self.activityIndicator stopAnimating];        //Stop animating
    self.activityIndicator.hidden = YES;           //Hide it
    [self.activityIndicator removeFromSuperview];  //Remove it from view

How to send Asynchronous NSURLRequest

For Asynchronous HttpRequest we don't need RestApi class that we created in last three sessions. instead we use the following method:
 

[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError)
    {
            //Do whatever you want after response received
            [self getReceivedData:data];
    }];
getReceivedData:data is a method that we created in last tutorial we changed it a little bit since we didn't need RestApi class so we removed the sender argument and also we changed the type od NSMutableData into NSData. If we want to handle errors we have:
 
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError)
    {
        if (!connectionError && [data length] > 0)
        {
            [self getReceivedData:data];
        }
        else
        {
            NSLog(@"%@", connectionError.description);
        }
    }];

Download

Download this App from here

Sunday, February 1, 2015

iOS Tutorial - Part 28 - HttpRequest POST, GET (NSURLConnection) III

HttpRequest POST, GET (NSURLConnection) III


Video Description 
In first and second session of Http request we have learned how to implement NSURLConnection delegate methods and also create Http GET and POST request. In the last session we will learn how to parse JSON format and show it in a tableView.

JSON content Type

If you copy paste the response from our Guardian News into this JSON formatter, and press Process button, you will see the JSON format in better view. If you collapse the first (-) buttons you will see it's a curly brace with something inside. This curly brace means the type of the response is dictionary. You can also say this fact by "key", "value" content. If you expand the response by taping on (+) button, and collapse the content of "response" by tapping on (-) you would see something like this
{  
   "response":{  }
}
It shows that "response" is a key and {} is it's value. Now if you expand the response value content and collapse the value of the "results", you would see something like this:
{  
   "response":{  
      "status":"ok",
      "userTier":"developer",
      "total":1732677,
      "startIndex":1,
      "pageSize":10,
      "currentPage":1,
      "pages":173268,
      "orderBy":"newest",
      "results":[  ]
   }
} 
If you notice the content of "results" is inside of Bracket []. It means that the content type of "results" is Array. The way we read JSON is based on the content type. If it's dictionary we should define NSDictionary but if the type is array we should define NSArray.

Read JSON format step by step

Since the whole response is dictionary we should define an NSDictionary and serialize the received data to make it human readable. We also handle any potential error with NSError.
- (void)getReceivedData:(NSMutableData *)data sender:(RestAPI *)sender
{
    NSError *error = nil;
    NSDictionary *receivedData =[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error];
}
Now in order to get the value of "response" we should define another dictionary like bellow and we initializing it with the key called "response":
- (void)getReceivedData:(NSMutableData *)data sender:(RestAPI *)sender
{
    NSError *error = nil;
    NSDictionary *receivedData =[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error];
    NSDictionary *response = [[NSDictionary alloc] initWithDictionary:[receivedData objectForKey:@"response"]];
}
Then we have a "results" to parse. The type of results is array so we define an array like bellow:
    NSArray *results = [[NSArray alloc] initWithArray:[response objectForKey:@"results"]];
Now we have to iterate through the array items, we do this by for loop like bellow:
for (int i; i < results.count; i++)
    {
        NSDictionary *resultsItems = [results objectAtIndex:i];
        NSString *webTitle = [resultsItems objectForKey:@"webTitle"];
        [self.webTitles addObject:webTitle];
        NSString *sectionName = [resultsItems objectForKey:@"sectionName"];
        [self.sectionNames addObject:sectionName];
    }
Since the content of each item of array is type of dictionary, we defined resultsItems variable. Then inside of this dictionary we are looking for a key "webTitle" and "sectionName". These are the values that we are going to show it in our tableView. We store these inside of two arrays to access them later for filling our tableView.

Fill out the tableView with the fetched response

Now we just have to define a number of sections, which is 1 and then number of rows in each sections, which is equal to the number items in webTitle array. And finally we implement the important tableView delegate, which is for content of each cell.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.webTitles.count;
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
    
    cell.textLabel.text = [self.webTitles objectAtIndex:indexPath.row];
    cell.detailTextLabel.text = [self.sectionNames objectAtIndex:indexPath.row];
    
    return cell;
}

Reload tableView

The last thing we have to do is to reload the tableView to show the fetched results, it's very easy to implement and it should be in the getReceivedData method.
[self.tableView reloadData];

Download

Download this App from here