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:
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.
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".
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:
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.
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.
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:
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:
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:
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
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.
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".
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:
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:
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.
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.
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.
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.
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).
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.
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:
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:
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:
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.