Sunday, November 1, 2015

iOS Tutorial - Part 35 - Popover for iPhone and iPad

Create Popover for iPhone and iPad


Video Description 
Sometimes we don't want to cover the whole view for showing another view controller. This is mostly for iPad because it has larger screen. But it's also possible to show popover on iPhone. Creating a popover is very easy, it's a type of connection between view controllers. All you have to do is to connect the button or whatever action you want to another view controller by control dragging and the choose "Present As Popover", that's it. This will show popover only for iPad but for iPhone you have to do one more step.

Popover for iPhone

iOS 8 offered an easy way to implement popover for iPhone. All you have to do is to declare UIPopoverPresentationControllerDelegate:
@interface ViewController () <UIPopoverPresentationControllerDelegate>

Then put the view controller delegate equal to self:
self.popoverTvc.popoverPresentationController.delegate = self;

And at the end implement the delegate method:
- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller
{
    return UIModalPresentationNone;
}

Adapt the popover size based on the content

The popover that we created so far has not a proper size. The default size is very big and unnecessary. In order to fix this issue we need to override the prefferedContentSize property of the popover view controller. In this example we have a table view and we need to get the size of the table view and show only the cells that has value (not empty cells).
if (self.tableView && self.presentingViewController) {
        self.preferredContentSize = [self.tableView sizeThatFits:self.presentingViewController.view.bounds.size];
    }
First we chech if tableView and presentingViewController (The view controller that is presenting at that moment) is not nill. then we set the preferredContentSize equal the tableiew size that fits presentingViewController size.

Download

Download this app here

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

Sunday, January 25, 2015

iOS Tutorial - Part 27 - HttpRequest POST, GET (NSURLConnection) II

HttpRequest POST, GET (NSURLConnection) II


Video Description 
This is the second part of NSURLConnection tutorial. If you have not read or watched the first part, click here to watch it first. In this part we will learn how to create a GET and POST request.

How to create GET request

The following method will do the GET request
- (void)httpGetRequest
{
    NSString *str = @"http://content.guardianapis.com/search?api-key=test";
    str = [str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSURL *url = [NSURL URLWithString:str];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    [request setHTTPMethod:GET];
    self.restApi.delegate = self;
    [self.restApi httpRequest:request];
}
In the first line we add the url address that we want to send the GET request. In the second line we convert the special characters of the url in first line. In the third like we convert the str into URL type that Objective-C can read it as an URL. In the fourth line we create our actual request with the URL we created. In the fifth line we specify the Http type (Here it's GET). The sixth line we are setting restApi delegate equal to self to implement RestApi class. In the last line we call RestAPI class to send our request (RestApi is created in previous session).

How to create POST request

- (void)httpPostRequest
{
    NSString *postBody = @"api-key=test";
    NSString *str = @"http://content.guardianapis.com/search";
    str = [str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSURL *url = [NSURL URLWithString:str];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    [request setHTTPMethod:POST];
    [request setHTTPBody:[postBody dataUsingEncoding:NSUTF8StringEncoding]];
    self.restApi.delegate = self;
    [self.restApi httpRequest:request];
}
It's exactly like sending GET request, the only difference is that it has 2 more lines. The first line and the seventh line. In the first line specifies the post body, which may includes post parameters. In the seventh line we attach the post body to the request.

What to do next

Click here for the third part of Http Request

Sunday, January 18, 2015

iOS Tutorial - Part 26 - HttpRequest POST, GET (NSURLConnection) I

HttpRequest POST, GET (NSURLConnection) I


Video Description 
One of the most popular functionality that many apps have is being able to send and receive data over internet. As you may know this service is called Http Request. The type of request could be POST, GET, DELETE, ... . Once you understand one type of request, you can use for other types of requests. Just to simplify the subject, it's divided into multiple sessions. In this session we talk about an API for Http Request, which is NSURLConnection.

RestAPI

I have created a class called "RestAPI". This class is designed to implement NSURLConnection delegate methods. Delegate methods that we are going to implement in this class are as follow:
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    [self.receivedData appendData:data];
}
This method appends the response data that is received from server or web. You may ask why we should append the data, It'd because most of the time server or web divides into separate parcels and sends it one by one. It's our job to append this data into a single object. We store the data in self.receivedData property. This property has a type called "NSMutableData". we define this property like bellow:
@property (nonatomic, strong) NSMutableData *receivedData;
We initialize it in it's setter like bellow:
- (NSMutableData *)receivedData
{
    if (!_receivedData)
    {
        _receivedData = [[NSMutableData alloc] init];
    }
    return _receivedData;
}
The next NSURLConnection delegate method is:
-(void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
    NSLog(@"%@", error.description);
}
If any error happens during the request, this method will be called. In this tutorial for the sake of simplicity we won't handle network errors, we just log the error in console and nothing else but you may handle the error properly. The other important delegate method is as follow:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    [self.delegate getReceivedData:self.receivedData sender:self];
    self.delegate = nil;
    self.requestConnection = nil;
    self.receivedData = nil;
}
When the response for our request becomes available this method will be called. After we are done with the response that we get, we put everything to nil because we may want to use them again through the application and they should be initialized again. The first line of the implementation of this method is calling a delegate method of "RestAPIDelegate", which is in RestAPI.h. In Session 18 (Create Protocol (Delegate), prepareForSegue) we have learnt how to create a protocol and what are they good for. In RestAPI.h file we have created a delegate method in order to be notified whenever the response becomes ready. This delegate has one method which is used in connectionDidFinishLoading.
@class RestAPI;
@protocol RestAPIDelegate
- (void)getReceivedData:(NSMutableData *)data sender:(RestAPI *)sender;
@end
Lastly we have a public method in RestAPI.h which is
- (void)httpRequest:(NSMutableURLRequest *)request;
Each class that wants to do Http Request should call this method by passing request argument. In next session we will talk how to create this request.


What to do next

Click here for the second part of Http Request