Quick Tip: Going completely XIB-less

Deprecation Warning

Hi there. This post was originally written back in early 2011, a long time ago. Since then the API's and methods mentioned herein have changed a lot. I wont remove this post as it still may be helpful to some but be aware that it is pretty old.

 

Transient

In some of my tutorials on MobileTuts+ I go through explaining XIB-less development and how to make your interfaces sans Interface Builder. What I demonstrated was 99% XIB-less and there was one main XIB left, the MainWindow.xib.

At the time I was unaware of a nice method of removing this XIB. However, after reading through some posts there is an easy way to get rid of that last XIB.

 

Step 1: Info.plist change

Open up the PROJECT_NAME-Info.plist in your project. Locate the "Main nib file base name" row in the dictionary and give it a good ol' delete. Save the file.

 

Step 2: Changing main.m

Next, if you are already 99% XIB-less then go ahead now and delete MainWindow.xib. If you have view controllers setup in MainWindow.xib then you will need to move them to the Application Delegate file. See Beginning iOS Development video #3 on Interface Builder for more information on how to do this, seek to 30:00 in the video and after that then delete the MainWindow.xib.

Open the main.m (in Other Sources) file in your project and find the code shown below:

And here is the code after the change:

So lets have a look at the difference. On line 6 in the code we have the UIApplicationMain method which if we look at in the documentation says:

This function is called in the main entry point to create the application object and the application delegate and set up the event cycle.

It accepts 4 arguments. The first 2 are passing the arguments through from the main() method. The last 2 allow you to specify the 'principal class name' and the 'delegate class name'. The principal class name is the name of the class that the Application Delegate inherits from, in this case its UIApplication. Finally, the delegate class name is the name of the class that we create so the Lap Timer application's Application Delegate is called 'LapTimerAppDelegate'.

Once the change is made in main.m, as illustrated above, then its time to move to the last step.

 

Step 3: Creating the window in code

Since the MainWindow.xib file is no longer available we have to create the window used throughout the application. To do this it's a simple 1 line addition to our Application Delegate.

At the top of the main application initialisation call in the Application Delegate the window is allocated and initialised. The window's frame is set as the bounds of the current device's main screen.

Check your Application Delegates header file and make sure the UIWindow property is no longer an IBOutlet.

Thats it! No more XIB's!

Beginning iOS Development Screencast Series

Transient

Mark Hammonds (MobileTuts+ Editor) and I have started a screencast series focussing on beginning iOS Development. It's goal is to go from Day 0, from installing XCode through to development topics such as Data Retention using Core Data, UIKit objects and all of the necessary information about the iOS SDK to get anyone started.

It has been interesting producing these screencasts. It has definitely taught me a few things and corrected some wrong assumptions I had about how things in the iOS work. By far the hardest thing is making sure the information I give out is correct. This usually ends up in a screencast being re-recorded 4 times and lots of late nights in documentation but the results are awesome.

If you have been watching this series please drop a comment on what you think about it, good or bad I want to hear it :)

Working with Core Data: Versioning and Lightweight Migrations

Transient

After reading First steps with Core Data, we find ourselves enlightened in the way Core Data works and how it can help us develop data rich applications. However, the surface was only just scratched, and in some applications you might be left wondering how to implement a certain piece of functionality.

My Experience with Core Data

Over the past months I have been working with Core Data on a pet project. It is an application to pull in data from a remote service API, store the data in Core Data, and display it in a collection of UITableView objects. Over the course of development, it has gone from a Property List based data store (shudder) to now a Core Data SQL store. After three complete rebuilds and many long nights of debugging, my application has finally become a fast, crash free, and memory leak free project. For me, using Core Data has made my application what it was intended to be, and I will be sharing much of what I've learned with you in this and future articles.

For this article, we will build upon the previous LapTimer application and demonstrate performing lightweight migrations.

Filtering an NSArray using NSPredicate's

Better and updated resource 

Hi there. This post was originally written back in late 2010. Since then the API's and methods mentioned herein have changed a lot. I wont remove this post as it still may be helpful to some but be aware that it is pretty old. 

NSHipster has an excellent, thorough and updated post. I highly recommend checking out that article.


 

Simple NSPredicate filtering

Transient

This is the most documented and suggested among the ways of filtering. A simple SQL-like query to filter down on results. NSPredicate definitions iterate through the NSArray collection running the condition statement against each row. If the row fails to match the condition it is not included in the returned result. The predicate condition can use the SQL-like statements and any Key-Value Coding syntax.

Predicate condition formats are mostly self explanatory. Take the first predicate in the example to find the records where the name contains the word 'melon'. The contains method has 2 arguments, [cd], which mean the search is case and diacritic (letters with accents, umlauts etc.) insensitive. So the matching results are Watermelon and Rockmelon.

Predicates also have more condition functions, some of which I have only touched on here:

  • beginswith : matches anything that begins with the supplied condition
  • contains : matches anything that contains the supplied condition
  • endswith : the opposite of begins with
  • like : the wildcard condition, similar to its SQL counterpart. Matches anything that fits the wildcard condition
  • matches : a regular expression matching condition. Beware: quite intense to run

The syntax also contains the following other function, predicates and operations:

  • AND (&&), OR (||), NOT (!)
  • ANY, ALL, NONE, IN
  • FALSE, TRUE, NULL, SELF

Filtering with a block

Lets look at what I mean by a block, the term may not be familiar to some. In a nut shell, a block is a function that you can pass as an argument. So if you want to iterate over something with the same simple function you don't need to put it in a separate method definition, you can define it inline with your code.

Breaking it down; A block is defined using a carat (^) and in the initial syntax has the arguments and expected return type, much like any other Objective-C method definition. The minusOne block defined above receives an integer, stored as myNumber, and then returns an int as defined. It encapsulates the code in curly braces and that is a block.

This is a really handy tool for short functions that you don't really need to define in a separate method on a class. Blocks are used mostly in iterative searches and expressions, like what we want to do in this article. But you don't use them to replace methods in a class, its just for short and 'throw-away' functions.

The NSPredicate class has the method predicateWithBlock: which accepts a block we can use to iterate over the records and return what we want. Lets look at a quick example of what this looks like:

This happens to developers at least once. We have an array of data to search through and its not in the easiest format to search through. In the example we need to single out NSDate s but the dates are stored as a NSString s, ugh! This means we have to process and format the results before we can search them. Can we do this at the same time? Yes, we can.

The example above does both the formatting to get a NSDate object and the search in the one block, impossible with a normal NSPredicate.

Running through the example, the first few lines are dedicated to setting up the test and getting a date formatter allocated. The dates are stored in an array with a reference date we want to compare them with. In this example we want to find dates after the reference date.

The block accepts 2 attributes. The first is the object ( id obj ) in the current iteration the second is a dictionary ( NSDictionary *bind ) which defined by the Apple Documentation "must contain key-value pairs for all variables in the receiver". For this purpose the second dictionary is not used. We access the obj property and do the date conversion and then run the comparison with the reference date.

Next the predicate is run through filteredArrayUsingPredicate: returning the new and filtered array.

So there we have it. Using NSPredicate s we can search and filter an array. I hope this will be as useful to you as I have found it with my own projects. Keep an eye on the development of blocks, they are a handy tool to use and definitely make development a bit easier.