Select, Search, Delete in UITableView with powerful ViewController

The Requirement:

Very often, you have a need to:

  • display some records to the user from originating screen (view controller)
  • have user select one / many of them and return to your original screen
  • have user search through them by some field
  • have user delete some of them

This being a recurring pattern, sometimes it results in lot of duplication of code within your project.

The Solution:

Here is a simple yet powerful solution to this problem: TableSearchViewController. To be precise, this is a simple UIViewController that hosts a UITableView, and displays your supplied objects (Array) in a neat, customized way. You can choose which fields to display in rows, which fields to make search with, and how to present the data in particular format.

You can even be selective in UITableView appearance – you can select cell colors, text colors, section header colors, checkbox images and delete button images.

  • If you look carefully in the UI, it shows checkbox-flavored UITableView rows. Each time you discard the screen using Select, it gives you selected objects in an array (of original object types) in a block, defined using originating view controller’s code.
  • You can select entire section using section checkbox. Not only that, you also get one extra checkbox in the footer, which returns a bool parameter into the selection block each time you discard using “Select”.
  • You can search records using strings, numbers, or any field (property) provided your object is KVC compliant. This is highly useful when you display an array of NSManagedObjects inside TableSearchViewController.

 


















The Code:

And here is the code snippet to achieve this appearance:

TableSearchViewController * tableSearchViewController = [[TableSearchViewController alloc] initWithNibName:@"TableSearchViewController" bundle:[NSBundle mainBundle]];

CustomObject * firstObj = [[CustomObject alloc] initWithString:@"First" andNumber:@(1)];
CustomObject * secondObj = [[CustomObject alloc] initWithString:@"Second" andNumber:@(2)];
CustomObject * thirdObj = [[CustomObject alloc] initWithString:@"Third" andNumber:@(3)];
CustomObject * forthObj = [[CustomObject alloc] initWithString:@"Four" andNumber:@(4)];
CustomObject * fifthObj = [[CustomObject alloc] initWithString:@"Five" andNumber:@(5)];

NSArray * firstSectionArray = @[firstObj, secondObj, thirdObj];
NSArray * secondSectionArray = @[forthObj, fifthObj, firstObj];

tableSearchViewController.resultsArray = @[@{@"First Section" : firstSectionArray}, @{@"Second Section" : secondSectionArray}];
tableSearchViewController.tableViewStyle = UITableViewStyleGrouped;
tableSearchViewController.allowSearch = YES;
tableSearchViewController.searchKeys = @[@"stringProperty"];
tableSearchViewController.textLabelKeys = @[@"stringProperty"];
tableSearchViewController.subTitleKeys = @[@"numberProperty"];
tableSearchViewController.textLableFormats = @[@"%@"];
tableSearchViewController.subTitleFormats = @[@"%@"]; 
tableSearchViewController.selectionDoneButtonTitle = @"Select";
tableSearchViewController.dismissButtonTitle = @"Cancel";
tableSearchViewController.accessoryAction = ACCESSORY_ACTION_CHECK;
tableSearchViewController.allowSelectionCheckImage = YES;
tableSearchViewController.allowSelectAllCheckBox = YES;
tableSearchViewController.cellColorStyle = CELL_COLOR_STYLE_ALTERNATE_DOUBLE;
tableSearchViewController.selectionDoneBlock = ^(NSArray* _Nullable  selectedKVCObjects, BOOL bExtraFlag)

{
        NSLog(@"%@", selectedKVCObjects);
        _valueLabel.text = [NSString stringWithFormat:@"%@", [selectedKVCObjects componentsJoinedByString:@","]];
};    

UINavigationController * navCtrl = [[UINavigationController alloc] initWithRootViewController:tableSearchViewController];
[self presentViewController:navCtrl animated:YES completion:nil];

CustomObject in the above is an NSObject derived KVC compliant object, included in the Github project.

The Swift version is under progress, and should soon be available.

Easy, isn’t it? So do feel free to download, leverage, and improve!

iOS app design blog: how to fix XCode Autolayout errors and warnings

iOS Autolayout is a groundbreaking feature that has been around since iOS 6.0. Yet, there are apprehensions in developers against using autolayout. These concerns usually stem from 3 facts:

  • Late adoption of Autolayout: Most developers realize it quite late their app must be usable across various sized devices and orientations. There is already lot of Objective C / Swift code that is based on fixed frames (320, 480) or (786, 1024). Moving this code means killing something that already works. Creating it on paper, and rendering it on to storyboards / XIBs with generalized / specialized constraints for each device / orientation combination is tremendous work of calculations.
  • Misleading autolayout shortcuts: Some of the inertia against autolayout stems from the fact that IB’s controls aren’t intuitive enough when it comes to autolayout. Microsoft Visual Studio’s designer tool was great in aligning / stacking elements – by simply using menu shortcuts. In XCode, aligning is already there, but stacking isn’t there yet. Making commonly used features readily available is something that autolayout IB lacks.
  • Autolayout errors and warnings defy novice developer: Despite autolayout being a great tool aimed at making a developer’s job easy, it ended up trying to be panacea for every possible UI layout – thus producing confusing semantics, hard to reach actions, and counter intuitive errors / warnings. Problems?
    • The moment you start with your first constraint, it starts complaining about missing constraints. This sometimes defeats the purpose of a simplification tool. It would be good to have “validate constraints” button to check them all at once.
    • It does fine job of pointing out missing constraints, but when it comes to conflicting ones, it often fails to point out the culprits.
    • There are visible inconsistencies in the tool, even until XCode 9, and here they are:

In this relative width constraint, the only variation that one can add is of the constant, despite the fact that multiplier has bigger impact. Although it’s a known fact that one could always separate constraint with trait variation for multiplier, it is counter-intuitive. Which brings us to another point.

 

The Add variation box following + sign looks like it adds a constraint for each variation – but all it does is specifying the fact that this constraint will be used for the variation you are specifying.

If you want to add 2nd variation, you need to go back to elements, and add another constraint, and specify the desired 2nd variation there. Besides, you must also uncheck “Install” box, or you will end up having the constraint for all variations, not alone wRhC.XCode autolayout has misguiding size class controls

 

In any case, it’s Apple’s job to improve upon it’s autolayout tool. Meanwhile, we will focus upon some basic principles that make this tool work – according to our wishes.

Some Definitions:

Was it too hard? Let us go through some basics first:

  • A constraint is x, y, width, or height value for a given view, for a given size class.
  • A size class is a combination of device width and device height, according to orientation.
    • Apple defines size classes  for various devices over here.

What are XCode Autolayout errors and warnings:

When it comes to errors and warnings in auto layout, there are three situations:

  • If you don’t specify ANY constraint at all, and just position your elements, there probably won’t be any errors. IB will simply assume absolute positions and sizes for all elements. And this will ONLY BE VALID for the size class.
  • If you specify just one constraint / some constraints for some of the elements, this will begin the nightmare. XCode will start complaining about the missing constraints, using red arrow error sign in “Document outline”.
  • You will then usually go through the nitty-gritty details of measurements, and specify constraints for each UI elements. Note that a view’s resulting constraints are the final result of all constraints that the view is part of. XCode will keep popping “Conflicting constraints” error until you have got them all right.
  • If an element is misplaced with respect to its specified constraint in given size class, it will show up a warning (yellow arrow in Document outline).

To fix them all, you need to follow a set of principles. For a fairly complex view which spans ipad, iphones and both orientation, spare a day or half for autolayout, until you get expert at it.

It is recommended to have your coffee, sit down calmly at your mac, and do it in one go rather than committing, rolling back, merging with others and so on.

Autolayout Principles:

  • Each element must have x, y, width, and height dimensions defined (unless you have no constraint at all in the view). What this means is,
    • This principle must be followed by all views except top level view. Dimensions of top level view are decided, also using an auto-generated constraints, by UIKit at runtime. No need to worry about it. But all elements except top level view must have their dimensions defined.
    • This becomes nasty because in order to really exploit auto-layout, you will have relative constraints (one view’s right edge touching another view’s left, one view’s width is half than its superview, and so on.). Hence, you must satisfy all four dimensions in a chained-manner
    • Which brings us to the question – where to begin. So you must start with a favorite subview in whose relation you will position / size others. There is no rule of thumb for choosing this favorite. Once you see your UI layout in wireframe, you will know which element it will be. This favorite view will usually pin itself to one of the corners / edges of the root view, and will have some proportional width/height to the root view. Others will follow this favorite as far as position is concerned, and will also relate to the superview when it comes to width/height.
  • Four Dimensions (x, y, width, height) does not necessarily mean constraints for leading / trailing, top / bottom, width, and height. They can be defined using various combinations of auto layout constraints. Look at the following table:
x Leading, Trailing, Horizontal Center
y Top, Bottom, Vertical Center
Width Width (Absolute number) / proportional to superview, Aspect Ratio
Height Height (Absolute number) / proportional to superview, Aspect Ratio

Practical Autolayout Considerations:

While designing for iPhone and iPad, with portrait and landscape orientations in mind, following are general auto layout practices that can make your life lot easier:

  • Use absolute size constraints (width = constant, height = constant) for buttons, and labels with small amount of text. This is because user expects certain action in the UI at certain position / size, and absolute values make his life easier. Also, fixed sizes make it better for text visibility across devices as far as it is not variable length text.
  • Use relative constraints (width = superview.width * 0.4, height = superview.height * 0.6) for container views, dynamically sizing text views, labels etc. This is an obvious guideline considering the look and feel and principles of proportions.
  • It makes tremendous sense to group elements in single screen under common subview, acting as a container. For example, if you have four labels all along each other placed vertically / horizontally, you could use a common container for all of them, and pin them (using x,y, width, height dimensional constraints) to this container’s edges. This way, if you decide to move them all, you just need to move this common container, and only disrupt the container’s constraints within the superview. See Container1 and Container2 below:

autolayout using grouped views

Conclusion:

Keeping above principles in mind will fix most of your auto-layout errors/warnings, and make your XIB/storyboard clean and without yellow/red error marks.

iOS app design blog: Customizing table view layout

When it comes to iOS app design, there have been quite some posts on good graphics. Importance of great UX can never be overstated. But fewer times there is open discussion on basic methods in making UI attractive. There are principles out there, taught seamlessly by design schools. But they are implemented using non-standardized techniques, often enforced by UX people who barely know the underlying implementation details of each platform.

Table View: Most important iOS app design element

Table view is most often used element in all iOS app design. It’s quite uncommon to see its enormous benefits when it can be customized by applying simple design principles. In this article, we will discuss one such techniques.

Visual appeal comes from relative lighting and exposure. Every UX designer knows this by heart. Let us emphasize this principle from a programmer’s perspective, with a simple example.

How about creating a UITableView with alternate color scheme? It is quite easy to design such a table view:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
BOOL bOdd = (indexPath.row % 2) ? YES:NO;
NSString * cellID = @"cellID";

UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:cellID];

if (!cell)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
}

cell.textLabel.text = @"blablabla"
if (bOdd)
{
cell.backgroundColor = [UIColor brownColor];
}
else
{
cell.backgroundColor = [UIColor blueColor];
}

return cell;
}

The result will be something like:

UITableView Alternate coloring

UITableView Alternate coloring

But this code fails to exploit UITableView’s most interesting layout strategy: UITableViewCell layout caching. Reason? we use different layout for same cell ID. What this essentially means is, using the same key, UITableView has to draw different layout each time. It’s a performance hit, because each time redraw must happen.

Solution is to use two different cellIDs for each color.

BOOL bOdd = (indexPath.row % 2) ? YES:NO;
NSString * cellID = (bOdd) ? cellIDOdd : cellIDEven;

UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:cellID];

if (!cell)
{
     cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault      reuseIdentifier:cellID];
}

cell.textLabel.text = @"blablabla"
if (bOdd)
{
     cell.backgroundColor = [UIColor brownColor];
}
else
{
     cell.backgroundColor = [UIColor blueColor];
}

return cell;

Now upon each call to dequeue statement, UITableView fetches the correctly colored cell. And cell.backgroundColor statement is effectively a no-op because same color is passed to the setter as the existing color. Because of UIColor’s own caching scheme, this is quite an efficient operation.

Finally, some consideration on visual appeal. The above layout convey’s programmer’s iOS acumen. But is it really appealing? Not quite.

For better visual appeal, it is recommended to use colors that are not too bright. Also it is recommended that things arranged in similar manner do not contrast each other too much. Something like below colors:

    UIColor * offWhite = [UIColor colorWithRed:247/255.0f green:241/255.0f blue:234/255.0f alpha:1.0];
    UIColor * lightGray = [UIColor colorWithRed:175/255.0f green:184.0/255.0f blue:183.0/255.0f alpha:1.0];
Alternate coloring

Alternate coloring

Looks appealing? Definitely, not the best, but lot better.

Better yet, one could make a preloaded array of colors, and fetch each color based on cell index. Something like:

    cell.backgroundColor = [self.cellColorArray objectAtIndex:(indexPath.row%(2))];

As you can see,

self.cellColorArray

is an array preloaded in viewDidLoad

or

viewWillAppear

, having both colors offWhite and lightGray as its elements. Also, modulo by 2 operation always yields 0 or 1, depending upon whether the row is odd or even. Note that if we want 3 alternate colors instead of 2, we can simply do modulo by 3 instead of modulo by 2 operation and get desired colors from alternate color scheme.

Main advantage of this approach is that you can have all your color values in one place, callable from

viewDidLoad

or

viewWillAppear

. You do not have to make calls to UIColor in each

cellForRowAtIndexPath

call.

Conclusion:

Never be afraid to experiment. iOS app design is not a foray only for UI and UX designers. If learned well by programmers, it can do wonders. There is never a limit how much device capabilities can be exploited to render attractive graphics and provide seamless user experience.

iOS app Design Blog: How to load images asynchronously inside UITableView

We are back, once again!

Which hosting company is trusted by over 9 million websites? Find out here!

One of the most common scenarios that iOS app devs face is when they have to load images from a network resource. While this is just first part of the challenge, you need to decide how you want to do it – synchronously or asynchronously.

iOS app design challenge: load images asynchronously

iOS app design needs to take care of many things. And great UX is first & last among them. Most of the time, you are required to display images inside a table / collection view. And it is implied that there is lot of information to be presented to the user at once. In apps for online shopping, catalogs – this becomes real challenge for iOS programmers because user is quite anxious to see a hundred items in a single table view, in least possible amount of time.

As a result, synchronous loading almost makes things impossible to run. This is because all UI updates occur on main queue, which in turn does its work through main thread. Fetching images synchronously on main thread directly kills user experience.

The risk? Before it turns your customers away, it can get you fired from your iOS Dev’s job!

The answer is async loading, also called lazy loading. In case you are looking for an iOS programmers job, familiarize yourself with this phase – you are going to meet this lazy loading chap somewhere down the line.

So our task for the day is clear: Develop an iOS app design that will:

  • load images from a REST API end point – we covered the initial loading of JSON data in our last tutorial. We will take it as base point and take our journey forward.
  • load them asynchronously i.e. without blocking the UI / displaying appropriate placeholder image
  • display them inside a table view
  • Ensure that scrolling is smooth, there is no overlapping of images, and most importantly: correct images load inside any given UITableviewCell

iOS App Design: steps to load images asynchronously

Our first job is to provide UI for our the JSON data we fetched last time, through our APIDataFetcher component. We will build this tutorial upon that.

If you remember, our APIDataFetcher component is capable enough of notifying its caller to receive the data / receive the error. Remember _successBlock and _failureBlock iVars? APIDataFetcher calls these blocks at proper times. It calls  _successBlock whenever it fetches data, and calls_failureBlock whenever it encounters error.

All we need to do is, supply these blocks, at appropriate points in our UI Code. And those blocks will be invoked, updating our UI with data / error.

Our obvious choice for the UI will be UITableview. We plan to do things in following order:

  1. Create app and import APIDataFetcher.m and APIDataFetcher.h files inside it.
  2. Load data as soon as the view is loaded – through APIDataFetcher – see loadData function below. If data is available, refresh table view using [tableView reloadData] call. If error has occurred, simply show blank, and log error description for now. You can also display some user friendly error message on the UI, which is trivial part for this tutorial.
  3. Derive UITableViewCell to create a subclass. Create XIB for this subclass and attach outlets to it.
  4. Create necessary UITableView datasource and delegate methods to display the data fetched in step 2
  5. While loading data in UITableView, ensure that all images are loaded lazily, that is, asynchronously, and most importantly, correctly. (we will cover why this last part is important aspect). Importantly, this task is not accomplished inside our ViewController but the UITableViewCell derived class that we designed in step 3 above.

Let’s look at each, one by one.

UK Dedicated Servers

Step 1 – Create single view app with table view

This is rather self-explanatory. We need to have at least one view controller that has a table view instance, implements protocols UITableViewDataSource and UITableViewDelegate, and that’s that. Once you are done, be sure to import APIDataFetcher.m and APIDataFetcher.h inside your project, or refer to this link to have entire project at your disposal.

Step 2 – Load data through APIDataFetcher

Take a look at loadData function below, which is called from viewDidLoad. Why call it from viewDidLoad? Simple – to avoid network call. Because it should only do REST API call if the entire view was dumped out of memory and loaded again.

If it was made part of viewDidAppear, it will be called every time even when you come back from a popped or modal view controller, or come back from a phone call.

- (void) loadData
{
    if (!resultArray)
    {
        resultArray = [[NSMutableArray alloc] init];
    }
    else
    {
        [resultArray removeAllObjects];
    }

    [self startActivityIndicator];
    [APIDataFetcher loadDataFromAPI:API_URL :^(id result)

    {
        [self stopActivityIndicator];
        if ([result isKindOfClass:[NSDictionary class]])
        {
            NSArray * resultsArrayfromJSON = (NSMutableArray*)[(NSDictionary*)result valueForKeyPath:@"results"];       

            for (NSDictionary * resultDict in resultsArrayfromJSON)
            {
                Track * track = [[Track alloc] initWithDictionary:resultDict];
                [resultArray addObject:track];
            }            
            [_tableView reloadData];
        }

    } :^(NSError *error)

    {
        [self stopActivityIndicator];
        if (error)
        {
            NSLog(@"%@", error.localizedDescription);
        }

    }];

}

What’s going on? It’s simple as 1-2-3. We are using the two blocks that we passed to APIDataFetcher as arguments in our previous tutorial. But their importance is being known now.

Blocks are powerful – and you don’t realize it when you invoke them. You realize it when you define when will you invoke them.

Another small thing to note is that we are using resultArray – which is to cache the APIDataFetcher response inside our view controller. Note that in real, large scale apps, this iVar can reside anywhere other than a view controller, in order to make it sharable across various view controllers. Here, for simplicity’s sake, we have kept it inside ViewController.

startActivityIndicator and stopActivityIndicator calls are nothing but ways to manipulate UIActivityIndicatorView’s visibility – that piece of code is self-explanatory.

So, what’s the big deal? You call it ‘the iOS app design blog’:

The heart of loadData is a major design decision we took, in case you haven’t seen it so far: The Track Object. This object stores whatever data REST API supplies it.

But why on earth, the Track? Oh yes, I forgot to tell you – Track is a model object, so its name shows what it stores. The track information. Come on! what tracks? Well, well, this deserves an explanation, but is a no-brainer. For our example’s sake, we are fetching iTunes live track data, the URL being: https://itunes.apple.com/search?term=Tom. This provides JSON response that is list of Track Details, and here is one – out of the list:




 

 

{
 "resultCount":50,
 "results": 
[
{
  "artistName": "Brad Bird", 
  "artworkUrl100": "http://is1.mzstatic.com/image/thumb/Video6/v4/c5/ab/8e/c5ab8e28-11b8-11a0-77db-cf0b77da27ce/source/100x100bb.jpg", 
  "artworkUrl30": "http://is1.mzstatic.com/image/thumb/Video6/v4/c5/ab/8e/c5ab8e28-11b8-11a0-77db-cf0b77da27ce/source/30x30bb.jpg", 
  "artworkUrl60": "http://is1.mzstatic.com/image/thumb/Video6/v4/c5/ab/8e/c5ab8e28-11b8-11a0-77db-cf0b77da27ce/source/60x60bb.jpg",  
  "longDescription": "From Disney comes two-time Oscar\u00ae winner Brad Bird\u2019s \u201cTomorrowland,\u201d a riveting mystery adventure starring Academy Award\u00ae winner George Clooney. Bound by a shared destiny, former boy-genius Frank (Clooney), jaded by disillusionment, and Casey (Britt Robertson), a bright, optimistic teen bursting with scientific curiosity, embark on a danger-filled mission to unearth the secrets of an enigmatic place somewhere in time and space known only as \u201cTomorrowland.\u201d What they must do there changes the world\u2014and them\u2014forever.", 
  ...,
  ...
},
 ...,
 ...,
 ]
}

If you are familiar with JSON serialization, you will know that every JSON element can be stored into either an array / dictionary. Dictionaries have key/value pairs, which you can see above, such as artistName, country etc. Our APIDataFetcher gives us the JSON serialized data, and we extract results array – the top level element. And we then extract dictionaries from this array.

We have our data with us, in the form of dictionaries. We can right away display it. Why the hell Track object still trolling around? We need it, because we need to wrap this dictionary information into something meaningful, called Track. Dictionaries can store Artists too, but with Track, we know what kind of dictionary we are dealing with. And that’s the first principle of Object Oriented Programming: Everything is Object.

There are obvious and immediate advantages of this approach – the first one being, you can have properties inside Track Object that map to above dictionary keys. Another advantage is extensibility. If you try to add one more piece of track info inside your app, you don’t have to perform nasty search for dictionaries through out your code to see where your Dictionaries mean Tracks. As soon as you get dictionary from JSON, you convert it into a Track and do whatever you want with it, until you need to send it across the network, at which point you need to serialize it again to a dictionary.

OK, OK,  so Track is what it is. How does it wrap the dictionary data? It possesses just one method that does it:

//  Track.m
- (instancetype) initWithDictionary : (NSDictionary *) dictionary
{
    self = [super init];
    
    if (self)
    {
        _trackArtist = [dictionary valueForKey:@"artistName"];
        _trackDescription = [dictionary valueForKey:@"shortDescription"];
        _trackImgURL = [dictionary valueForKey:@"artworkUrl60"];
    }
    
    return self;
}

Track has following properties, and as you need more, you just need to add more mappings to above init method, and you are done. Every time, create a Track object, and type “track." – and XCode will do the rest for you.

Step 3 – Derive UITableViewCell to create a subclass

This one is rather easy. Just look around for examples how to add a subclass to existing iOS class (UITableViewCell), and associate an XIB with it, with some outlets mapped to the subclass .h file. Here is the code for .h file.

#import <UIKit/UIKit.h>
#import "Track.h"

@interface APITableViewCell : UITableViewCell
@property (weak, nonatomic) IBOutlet UILabel *labelDescription;
@property (weak, nonatomic) IBOutlet UILabel *labelArtist;
@property (weak, nonatomic) IBOutlet UIImageView *cellImageView;
- (void) bindDataWithCell : (Track *) track :(NSIndexPath *) indexPath :(UITableView*) tableView;
@end

The property names are self explanatory, and they will, at some point, hold Track artist, Track description, and Track image (fetched from one of the URLs specified in REST API JSON response, shown at the top). Let’s not discuss the source file for APITableViewCell, because that is where the asynchronous image loading logic takes place.

Step 4 – Create necessary UITableView datasource and delegate

In this step, we shall cover the bare bones of UITableView delegate and datasource. Who is that? No one else – but our view controller itself. In the grand design, our view controller often gets to play the role of delegate and data source every time collection of items are to be dealt with. Data source methods tells where the item data is coming from, and how many of them are lined up. Delegate methods controls the UI related behavior – selection of cells, appearance of cells etc. Without going into details, here they are:

- (void) registerCells
{
    [_tableView registerNib:[UINib nibWithNibName:@"APITableViewCell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:@"APITableViewCell"];
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    NSInteger count = [resultArray count];

    return count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    APITableViewCell * cell = [_tableView dequeueReusableCellWithIdentifier:@"APITableViewCell"];

    if (!cell)
    {
        cell = [[APITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"APITableViewCell"];
    }
    
    Track * track = [resultArray objectAtIndex:indexPath.row];
    
    if (track)
    {
        [cell bindDataWithCell:track :indexPath :tableView];
    }
    
    return cell;
}

The first method registerCells is not a datasource method, the rest three are. Inside registerCells, registerNib is to tell the table view that since we are using the same layout for each cell, queue it. We also tell the XIB name to fetch the layout from. In a scrollable view with thousand cells, it doesn’t instantiate UITableViewCell (read view) each time you scroll. Instead, it just creates a screenful of them. Once you scroll down the screen, the ones that go up are queued, and the ones that come down are displayed – or dequeued from the list of those which are queued – off course, filtered by the XIB name which was used to register the cell. And this dequeueing happens inside the last method – cellForRowAtIndexPath. Instead of doing [alloc] init with a new APITableViewCell each time, it gets one from the table view method: dequeueReusableCellWithIdentifier. This wouldn’t be possible without registerNib – that’s the use of registerCells.

The next two, numberOfSectionsInTableView and numberOfRowsInSection simply tells table view to load 1 section, and load all tracks that are fetched from REST API JSON response into resultsArray.

The last one, cellForRowAtIndexPath is where the magic must happen. Where else  the asynchronous loading of images in table view will succeed?

Here, dequeueReusableCellWithIdentifier tries to fetch some preloaded cell, and if it fails, we alloc init it. Then, we go on loading the Track from resultsArray – the track for this cell.

Surprisingly, without doing much, we return the cell – after doing bindDataWithCell, which is the method of the cell itself. And that is where the asynchronous image loading magic happens.

Remember why we skipped to cover APITableViewCell.m. Well, now we will fully visit it, and see the pieces falling together.

Step 5 – Lazy Loading A.K.A. Asynchronous image loading in UITableView

Lazy Loading obviously means you don’t tie the main UI thread with loading of image data. But it also has a deeper meaning.

Windows Reseller Hosting

Loading something lazily means sometimes you fetch it from local cache (although this blog does not address it). Only if you detect that there is no local data, and / or your business logic requires you to refresh the image, you load it from server, necessitating a REST API call.

One more aspect that’s covered under the term lazy loading is that all you get inside JSON response is not an actual image, but a URL to it. There are obvious advantages of this approach.

  1. Every API call should not need to be burdened with fat images. Why display images if they aren’t needed at all?
  2. Depending on the target device, you may want to provide different dimension images, in which case supplying single image data to form a bulky response is nonsense. Providing different image URL puts the freedom in app client’s hands – you choose your image size and fetch it wherever you want. That’s all about lazy loading.

Here is the implementation of APITableViewCell.m – ignore the setSelected method. Let’s jump inside bindDataWithCell:

- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
    [super setSelected:selected animated:animated];
}

- (void) bindDataWithCell : (Track *) track :(NSIndexPath *) indexPath :(UITableView*) tableView
{
    static UIImage * placeHolder;

    placeHolder = [UIImage imageNamed:@"placeholder"];
    
    self.labelArtist.text = track.trackArtist;
    self.labelDescription.text = track.trackDescription;
    self.cellImageView.image = placeHolder;
    
    NSString *imageUrl = track.trackImgURL;
    
    BOOL bNeedsToFetch = [self.cellImageView.image isEqual:placeHolder];
    
    if (bNeedsToFetch && imageUrl && ![imageUrl isEqualToString:@""])
    {
        //[NSURLConnection sendAsynchronousRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:imageUrl]] queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
        NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString: imageUrl] completionHandler:^(NSData * data, NSURLResponse * response, NSError * error)
        {
            if (!error && data)
            {
                UIImage *image = [UIImage imageWithData:data];
                //request succeeded, overwrite cellImage
                if (image)
                {
                    dispatch_async(dispatch_get_main_queue(),
                    ^{
                        APITableViewCell *cell = (id)[tableView cellForRowAtIndexPath:indexPath];
                        if (cell)
                            cell.cellImageView.image = image;
                    });
                }
            }
            else
            {
                NSLog(@"Failed to load the image from URL: %@", imageUrl);
            }
        }];
        [task resume];
    }
}

Inside bindDataWithCell, we get a Track object. This is obvious because it is our Model object. This method will simply read different properties of Track object that’s supplied to it, and sets the cell UI elements – labelArtist and labelDescription text. cellImageView is the imageview where we need to load the images, lazily.

Need better web hosting? Choose 1&1. Free: domains, marketing tools, search engine ad & more. Check OFFERS!

We begin by setting the image to placeholder image, which should be something of a meaning to say ‘wait, I am loading’. Note that it’s a static UIImage variable, which means every call to bindDataWithCell will not set it. It is set just the first time, and reused forever.

Fetching of actual image happens via following statement:

NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString: imageUrl] completionHandler:^(NSData * data, NSURLResponse * response, NSError * error)

followed by:

[task resume];

Now, the usage of NSURLSessionTask is new, but not very new, since it’s available since iOS 7. It simply fetches the data on a background thread, and when done, it leaves you inside a completionHandler – saying – play with your data, or handle where you screwed up (error). It also hands you an NSURLResponse object, in case you need some additional information.

Irrespective of what you got (valid data or error) – you must remember that you are on background queue! You must fetch everything that you can, while on background queue.

Then, and only then, you should resurrect yourself into the main queue with the image data!

(Well, if you don’t, your image won’t show up probably. Phsst.)

Back inside main queue, however, there is a bigger thing to understand – we get the cell reference, again. Yes, again. Then we set the image view image property = the one we got from NSURLSessionTask call. Focus on the following statements:

APITableViewCell *cell = (id)[tableView cellForRowAtIndexPath:indexPath];
if (cell)
   cell.cellImageView.image = image;

If we are already inside the cell, and this cell is the one that’s being created, why do we need explicit cell reference again? That’s the heart of how dequeueReusableCellWithIdentifier works. Remember that cells are reused. Only visible cells are created by table view. During scrolling, cell instances are queued and dequeued, altering their data only. That’s what cellForRowAtIndexPath we wrote above does – setting the cell data of an already existing OR newly created UITableViewCell (or it’s derivative, APITableViewCell).

When we are inside APITableViewCell instance method, we only know we are dealing with a cell; we don’t know which cell out of all cells that user is able to scroll through.

But we already on the call stack of cellForRowAtIndexPath, that was the method that called bindDataWithCell in the first place. Aren’t we creating recursion?

The answer to that question is, my friend, No. [tableView cellForRowAtIndexPath:indexPath] is a call to cellForRowAtIndexPath belonging to UITableView, which is different from the one with the same name of UITableViewDataSource, implemented by our own view controller which is the data source in present case.

The former one simply returns a cell of the table view, and it must be called explicitly, to get the cell at desired index path. The later method, the one we usually encounter and write, is called by table view during reloadData call, and it is the version implemented by the data source is invoked. It should never be invoked directly.

The case is put to rest. Here is the entire project, you may use it, contribute to it, and share with friends.

Scroll farther as you want. Just don’t screw up with the cells anymore.

iOS app Design Blog – How to get JSON data from REST API?

UPDATE:

Many readers, while appreciating the need for the tutorial, made me aware that NSURLConnection has aged enough since iOS 9. While I agree, this is not quite the case yet. NSURLSession is a great grand umbrella under which everything that earlier resided under NSURLConnection – will move.

Considering so many newbie devs confused about which one to use, I have updated the code base to also use NSURLSession.

Verdict: NSURLSession or NSURLConnection?

NSURLConnection, though deprecated, isn’t going anywhere soon. Mac OS library still has it. However, if you want to use per request session configuration settings (cache, credential policies etc) – NSURLSession is better candidate. NSURLConnection will still work for the purpose at hand – but going down the line it is likely to be unsupported.

OK, read on now.

Most iOS apps today rely upon displaying data to user from a server. There are obvious advantages of this approach over displaying it from local app data source:

  • Limited local storage
  • Maintaining data updates through server controlled by developer
  • No need to release app updates with respect to data change

JSON is the most popular data format considering the support it enjoys with modern programming languages. So our today’s blog is dedicated to designing how you can GET ANY JSON data from any REST API endpoint.

As part of this tutorial, we will build an objective-C class that can be reused through out your app. This class – let’s call it APIDataFetcher:

  • will be a singleton / only hold class methods so instantiation does not matter.
  • will fetch data from given REST URL (supplied by caller function – typically this would be your UI, but it can also be a background queue that does this via a non-UI thread)
  • will report errors to the caller

So let’s build it from scratch.

API Data Fetcher – what it contains:

Nothing. Since all it provides are static functions, there are no class members. It will have to expose these functions though. For now, let’s assume

  • it has functions named loadDataFromAPI and loadDataFromAPIUsingSession
  • loadDataFromAPI or loadDataFromAPIUsingSession calls a (success) handler block (that the caller provides) with JSON data it fetched from the API
  • loadDataFromAPI or loadDataFromAPIUsingSession calls a (failure) handler block (again, the caller provided one) with the error it received from the API in case something goes wrong

Cut short to the .h file:

#import <Foundation/Foundation.h>

typedef void (^SuccessBlock)(id result);
typedef void (^FailureBlock)(NSError * error);

@interface APIDataFetcher : NSObject
+ (void) loadDataFromAPI : (NSString *) url : (SuccessBlock) successBlock :(FailureBlock) failureBlock;
+ (void) loadDataFromAPIUsingSession : (NSString *) url : (SuccessBlock) successBlock :(FailureBlock) failureBlock;
@end

And that’s that. Let’s move on to the implementation.

API Data Fetcher – what would it additionally need:

Though no instance members, APIDataFetcher.m would need some everlasting static objects to do its job.  They are:

  • an NSOperationQueue object – this is necessary because multiple REST API request from your app can be serialized and tracked effectively using this class. Serialized and tracked effectively – What? You don’t get it? That’s why it exists – you don’t have to care a bit about that phrase when you use NSOperationQueue, and this is not the only scenario where it’s useful. There are plenty of times in iOS app design where an operation queue is inevitable, and we will keep visiting it often.
  • a success block – static one. Definition inside the header.   this is removed due to potential bug in multiple request use case.
  • a failure block – static one. Again, the definition inside the header.  – this is removed due to potential bug in multiple request use case.

So now what? Fire – straight from the hell.

API Data Fetcher – how it’s implemented:

Straight to the code for APIDataFetcher.m file:

//  APIDataFetcher.m
//
//  Created by Nirav Bhatt on 9/5/15.
//  Copyright (c) 2015 IphoneGameZone. All rights reserved.
/* Generic JSON fetch routines through NSURLConnection
 Part of: https://github.com/vividcode/iOSAPIDataApp/tree/master/iOSAPIDataApp*/

#import "APIDataFetcher.h"

static NSOperationQueue * _connectionQueue = nil;
static NSURLSession * _session = nil;

@implementation APIDataFetcher

+ (NSOperationQueue *) connectionQueue
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if (!_connectionQueue)
        {
            _connectionQueue = [[NSOperationQueue alloc] init];
        }
    });
    return _connectionQueue;
}

+ (void) createURLSession
{
    static dispatch_once_t onceToken;
    
    if (!_session)
    {
        dispatch_once(&onceToken, ^{
            _session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
        });
    }
}

+ (void) loadDataFromAPIUsingSession : (NSString *) url : (SuccessBlock) successBlock :(FailureBlock) failureBlock
{
    NSURLRequest * request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
    
    [self createURLSession];
    
    NSURLSessionDataTask * task = [_session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
    {
        if (response != nil)
        {
            if ([[self acceptableStatusCodes] containsIndex:[(NSHTTPURLResponse *)response statusCode]])
            {
                if ([data length] > 0)
                {
                    NSError *jsonError  = nil;
                    id jsonObject  = nil;
                    
                    jsonObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&jsonError];
                    
                    if (jsonObject != nil)
                    {
                        [self presentData:jsonObject :successBlock];
                    }
                    else
                    {
                        [self presentError:jsonError :failureBlock];
                    }
                }
                else
                {
                    [self presentError:nil :failureBlock];
                }
            }
            else
            {
                [self presentError:nil :failureBlock];
            }
        }
        else
        {
            [self presentError:error :failureBlock];
        }
    }];
    
    [task resume];
}

+ (void) loadDataFromAPI : (NSString *) url : (SuccessBlock) successBlock :(FailureBlock) failureBlock
{
    NSURLRequest * request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
    [NSURLConnection sendAsynchronousRequest:request queue:[self connectionQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError)
     {
         if (response != nil)
         {
             if ([[self acceptableStatusCodes] containsIndex:[(NSHTTPURLResponse *)response statusCode] ])
             {
                 if ([data length] > 0)
                 {
                     NSError *jsonError  = nil;
                     id jsonObject  = nil;
                     
                     jsonObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&jsonError];
                     
                     if (jsonObject != nil)
                     {
                         [self presentData:jsonObject :successBlock];
                     }
                     else
                     {
                         [self presentError:jsonError :failureBlock];
                     }
                 }
                 else
                 {
                     [self presentError:nil :failureBlock];
                 }
             }
             else
             {
                 [self presentError:nil :failureBlock];
             }
         }
         else
         {
             [self presentError:connectionError :failureBlock];
         }
     }];
}

+ (NSIndexSet *) acceptableStatusCodes
{
    return [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 99)];
}

+ (void) presentData:(id)jsonObject :(SuccessBlock) block
{
    [[NSOperationQueue mainQueue] addOperationWithBlock:
     ^{
         block(jsonObject);
     }];
}

+ (void) presentError:(NSError *)error :(FailureBlock) block
{
    [[NSOperationQueue mainQueue] addOperationWithBlock:
     ^{
         block(error);
     }];
}
@end

And now let’s look at the main functions one by one.

The first one – connectionQueue (which is only applicable for loadDataFromAPI which uses NSURLConnection)-  returns a static singletone instance of type NSOperationQueue, which is quite obvious, because you don’t want to create & recreate your NSOperationQueue during the lifetime of your app. Single _connectionQueue instance should be able to keep track of all your REST API request. Again, none of much of your concern.

The next one, loadDataFromAPI (or loadDataFromAPIUsingSession), is the heart of this post.  It accepts the REST API URL to fetch the data from. In addition to that, it expects two execution blocks – a success block and a failure block – to be invoked in the context of view controllers who called these functions – for data update and error respectively.

Do not forget that these are the very things given to loadDataFromAPI from it’s caller, mostly the view controller – view controller expects data, or in the worst case, some error info, and successBlock and failureBlock stack variables are our only way to give it back. APIDataFetcher does not, and must not know anything about it’s callers.

  • Create NSURLRequest object from the URL passed (in case of POST request, this request object must additionally be initialized with payload data, but for now, let’s only worry about GET request)
  • If using loadDataFromAPI, Invoke [NSURLConnection sendAsynchronousRequest] which fires the REST API GET request. If URL and everything else is correct with the REST API, this function comes back with a valid NSURLResponse object, along with some NSData. If not, it comes back with NSError object. In any case, completionHandler of sendAsynchronousRequest  marks the end of the URL request, and you have the task of notifying your caller what you got.
  • If using loadDataFromAPIUsingSession, create NSURLSession using default configuration first. Notice the use of dispatch_once_t token to ensure multiple requests do not recreate the session. This session will then create NSURLSessionDataTask with URL request as in above step. You need to resume this task in order for things to set off. Everything else is common to loadDataFromAPI or loadDataFromAPIUsingSession.
  • Inside completionHandler, we perform checks of received NSData, and convert it to id type JSON var using function [NSJSONSerialization JSONObjectWithData]. This function gives a JSON object from the data only if the data is valid JSON. If not, it returns nil, and you may want to notify caller about the error.
  • Helper function acceptableStatusCodes tells if the received NSURLResponse belongs to valid Http status codes, depending upon which you may want to perform specific user notification tasks.

  • Helper function presentError does the simple task: Invoking _failureBlock block to notify caller of the error. However, an important thing to note is that it does this using [NSOperationQueue mainQueue] – the queue using the UI thread of your app.
  • Helper function presentData does exactly the same thing as presentError – except that it does it with the JSON object by invoking the _successBlock.

And we are done. Get all the code for APIDataFetcher, use it with your view controllers, and play with your REST APIs forever!

iOS app Design Blog: Observer vs Delegate Design Patterns

Observers and Delegates are famous design patterns. And they are most easy to be confused about. This article explains basics of Observers vs Delegates.

While writing iOS apps, a good dev always follow design pattern. The reason many devs won’t do is – mobile development is considered more as a hobby than a business – the very reason it has attracted indie community. If an app studio is a shopping mall, indie dev is a shopkeeper on the street. To enforce his independent identity he would love to brag about his non-conformity to established norms.

However, writing robust apps is not a choice but a pre-requisite. Every failed indie dev realizes this easy or hard way. Practices such as Massive View Controllers (MVC?) and copy-paste code would render themselves obsolete as languages like Swift evolve with time. But while they do, there are certain easy to follow rules that every dev can follow to make their living better – especially amid constant flux of changes and upgrades in device software space.

Design patterns are such subset of rules that no one will repent following. The most common types used my many devs are obviously observers and delegates. It is quite easy to intermingle the two.

Both Observer & Delegate design patterns come into picture when interaction between two objects is involved. They both are useful when one object needs to perform certain task when the other object wants it to perform it.

Observers:

Observers are – let me guess – your twitter followers. Any updates you post, they all get it in their timelines. The reverse isn’t true however – you don’t get to know about them. The flow of information is unidirectional.

Delegates:

Delegates are – stop being pluralistic. A delegate is like a friend in need. He does his assigned task and resigns gracefully. There can be only one delegate for certain type of task.

Observer vs Delegate:

Both observers & delegates work on some common premises of one thing – the object who is notifying (notifier) and the object being notified. Having fixed this terminology, it is easy to understand the difference.

In observer pattern, there can be single notifier and multitude of objects being notified. No matter which classes those objects implement, no matter how many instances of them being alive, they all can be notified of a change that their notifier object is eager to report.

In Apple’s world, a widely-implemented example of an observer is NSNotificationCenter’s postNotification functionality. Using postNotification, one can notify as many objects (irrespective of their type) at once. An object can receive a notification as long as it has registered itself as an observer to certain notification type. This notification type is the single bond between the notifier and the one being notified. The objects do not know each other at all.

Another well-implemented Observer example is SKPaymentTransactionObserver. This is not a class but a protocol. Whichever object in your app implements this protocol (by implementing its mandatory updatedTransactions method) – that object automatically becomes an observer for any notifications that storekit has for the transactions. Storekit has no knowledge of your in-app purchase class. Your app should tell it at the time of launching through [[SKPaymentQueue defaultQueue] addTransactionObserver:<Your Observer Instance>], and at runtime storekit will notify your observer about all transaction status changes – via updatedTransactions.

Delegates do the same tasks as observers do – perform an action in response to a change. But instead of performing things themselves, the object responsible for change must invoke them. The notifier object already knows (at compile time) who is it’s delegate – at runtime it invokes certain delegate method (implemented through the delegate protocol) and performs the task. The method definition lies with delegate class definition, but the invocation happens from the notifier.

Do I need to remind you of UITableView and its relatives? UITableViewDelegate protocol’s didSelectRowAtIndexPath is always implemented inside your table view controller. But you do not invoke it directly. When you select a row on table view, the table view, and not your view controller, knows about it first hand. UITableView’s _selectRowAtIndexPath is directly invoked through selection. UITableView then asks about it’s delegate’s implementation of didSelectRowAtIndexPath. If this implementation exist, it is invoked. If not, nothing happens and table view goes about its usual business.

But who is the delegate? Your own view controller. How did table view know about it? In other words, who established this relationship? The following statement in your code (written in viewDidLoad or somewhere similar – or connected via Storyboard):

_mytTableView.delegate = self;

XCode compiler ensures that whoever is self (your view controller) – that class should implement UITableViewDelegate for the above statement to hold true. The notifier knows in advance who their delegate is, from the time of compilation.

Observer vs Delegate: What to use & when:

When you want anonymity about the object being notified, use observer design pattern. An observer must know who it is observing, but the reverse is not true. You can have single notifier and multiple observers in this pattern.

Notifications are easy to implement from programming perspective because all they require is posting notifications to anonymous observers, and observers declaring their own notification handlers themselves, like this:

[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notificationPosted) name:kNotificationName object:nil];

Upon deallocation:

[[NSNotificationCenter defaultCenter] removeObserver:self name:kNotificationName object:nil];

One thing to take care of while doing this is to remove observers as and when their need to observe changes is over. NSNotificationCenter has removeObserver set of methods just for this purpose. Observer notifications to non-existing observers cause significant performance decay.

When you want tight coupling between the notifier and the object being notified, use delegate design pattern. Delegates also require that there is one-to-one relationship between object being notified and the notifier object. From programming complexity standpoint, delegates are harder to implement, but issues related to it are easy to debug because they are easily traceable.

It’s easy to ignore Design patterns and code your way in haste to make your app public. It’s easy to define as many properties as you want and use them at leisure wherever required. However, as you go along and when your code requires modifications, or when you assign your development tasks to someone else (delegation!) – code reusability and extensibility becomes necessity. Efforts invested in following design patterns justify themselves when such benefits are reaped.

Museum Tours 5.0 is out – on the app store!

Compatible with the newer iOS, offering so much on the platter – Museum Tours – it’s officially out!

With this version, Museum Tours officially targets homeschooling audiences and teachers alike. With as many as six most important Museum collections, including Science & Anthropology ones, it is set to become the first app you want to browse each morning to get your daily dose of World Museums. Simply because these collections don’t come as subscriptions, they come as just one time purchases!

For those curious arts scouts, this is the only app that offers most number of Museums across the world. Yes, Museum Tours has an unlimited collection that offers 2000+ Museums – as many as Wikipedia can offer.

And, let’s not forget, it is available in French, German, Portuguese, and Spanish language too!

Along with Flickr, I am planning to bring more relevant set of artifacts during forthcoming updates. There is just so much possible with newer set of iOS 8 APIs, one needs to prioritize what to offer and what to wait for!

iOS 8 – is it the end of an era for indie mavericks?

iOS 8 – It’s out, officially. And things are never the same.

Indie iOS Dev – the long time victim:

Indie iOS developers find themselves at the crossroads of something radical. While I don’t go far to conclude things are worsening, things are definitely evolving.

Whenever evolution takes place, old species must mutate, or make ways for the newer ones.

This time around, (again!) it’s likely to be the indie dev community. To everyone who has slightest idea, this is an ever-shrinking sailing ship since iOS inception, not necessarily pitted against steam powered boats or anything of the cruise class. But as everyone knows, iOS Appstore is the pinnacle of the crudest capitalist inequality on the planet. In other words, rephrasing the 80-20 principle, 1% of the app publishers draw away 99% of the app store revenue – the majority comprising the indie devs.

The irony is – it’s this community that keeps app store dream alive, eventually keeping the app market afloat on the planet.

Because more than God, it’s the faith in God that is important. The loss of this faith scares even the priests, like hell.

-Anonymous

Indie devs bear the hardest blows, either from big boats or the never-yielding tides. On the surface, it seems it doesn’t change anything for all those super-excited fanboys and gamers. The laws of evolution automatically pushes better boys to the top, who in turn keep indie dream alive: If someone belongs to the top lists, she deserves to be there. Following the laws of free market, customers must be happy too, for they are the ones who have pushed the biggies towards where they stand today.

However, when a quality indie fail, there are some side effects waiting to emerge after some time. One of those were demonstrated pretty well during the flight of Flappy Bird. Yes, the entire app-cloning industry relies on indie devs who made an ingenious piece of software but simply failed to secure the biggest validators of their success – money and fame.

The result? They make app (& game) templates of successful apps made by themselves, or someone else. Then they sell them for good (but not great) money. Copycats purchase them for a dime (OK, $99). Clones flood the top lists. Gamers enjoy, but only for a while until the charm lasts, and the entire mania recedes. The app clones get pushed towards the bottom. But by the time, cloners have already made more than what they deserved, due to sheer volume of the store. And there is nothing built inside app store algorithm to push quality indie devs further up the chart when clones endure the fall.

The end result? Users get the shit. App store will keep inflating till a point when the bubble will burst. Note the dilemma – the app store, and not the iOS itself, will take the plunge. Lest someone big really makes something worthwhile that can keep the flock invested.

Either way, the indie dev who made the original piece never gets his due – neither money, nor the fame. All wasn’t lost, however.

Until iOS 8 happened.

Precursor – the predator in disguise:

iOS 8 was a change waiting to happen. But it’s preamble was set with the release of iOS 7 – which brought forth major shifts such as a thing called skeuomorphism – a shift from the world of bevels and shadows. And numbered became the days of UI experts who made our apps truly outstanding, in literal sense. Off course, gaming industry will keep employing them heavier than ever, but as far as app UI design is concerned, the creativity domain of a UI designer will become fairly limited.

Apple also became sensitive towards its role in enterprise domain by introducing iBeacon in iOS 7. Being dependent on big chains for its adoption, this is one more domain where little can be done through indie dev’s will (but definitely not without his skill).

Even bigger shift in direction came via Spritekit. And to understand it, one must go back to foundation days of iOS. When I was new to iOS world, I was continually amazed how so many 2D and 3D games flooded the app stores despite steep learning curve of OpenGL. And I didn’t have to bury my head into books before I knew there existed a framework called Cocos2D that filled the gap between a game designer’s scene and complex shaders of OpenGL.

With the introduction of Spritekit, the entire ilk of Cocos2d evangelist would be rendered useless. Not that they wouldn’t find something worthwhile to do; they will, for sure. But few novice gamers would be eager to know about them, and even fewer people will realize how an entire Apple framework was conceived and born through their sheer indie will.

iOS 8 – predator or savior?

With iOS 8, all this evolved into its fullest metaphysical sense of existence. iOS 8 completed full circle of many changes that iOS 7 initiated. In parlance of software source control management:

iOS 7 can be termed as a build; iOS 8 is a version. And a major one.

Extensions brought in the long-sought customizations into UI Design. This will bring so many developers into the mainstream, who earlier had to develop their own extension frameworks – sometimes just to release their apps on Cydia-guild app stores, instead of Apple’s own. Extensions in iOS 8, especially aimed at app bundles instead of single apps, would benefit big studios more than indie ones who have one or two high quality apps at max. The app audience would surely benefit, but the steam would be lost, with sophisticated APIs to assist Swift newbies. And all those Objective-C veterans who had it the hard way would sit and watch.

That reminded us of Swift. There are few meek voices raising their concern about the very reason of Swift’s existence. Except for Apple. Yes, yet another block of clueless programmers waiting to create mobile apps would jump in the Apple queue. Not that they aren’t welcome.

Everyone who entered the programming foray had it easier than their ancestors.

With Swift’s oversimplified programming constructs (still arguable), many hypotheses would be laid to rest. One of them being: ‘An app developer should be a programming veteran having stronghold on OS, resources and memory management’. Perhaps it was Apple’s way to pre-defying any possible competition in iOS app code generation. But it may turn itself into a war between Objective C veterans and the new age Swift developers where the later may have an unfair advantage of better hardware and simpler structures. True, same argument can held between assembly and C++ camps, but C++ still maintained the need for software programmers’ understanding of hardware capability and sensible class design. With Swift’s super-easy programming constructs that are never destined for crash, the road will be over-smooth, 6-lane wide and without any apparent traffic. While such roads improve driving experience, overspeeding is inevitable; and innocents are victims most of the time, if not always.

Cloudkit is forever set to obliterate many use cases for 3rd party back-end. This is one of the changes that deserves an extra article. And to be fair, it is something Apple did in favor of indie devs, as far as intention is concerned. With 50 GB of storage incentive, it is lucrative enough for newcomers to defy any server side development and research on external APIs. While it may lure indie devs with almost free data storage, they would need to upgrade themselves if they want their cloud to be smart enough to handle complex application logic. At the same time, all those upgrades will happen inside Apple’s cloud walls, so the community would be at a loss. Smart code, but chained.

Healthkit is one more feature that is likely to drive niche developers – someone having some medical background in addition to programming. Considering the research and resources this field requires, and the regulations it entails, this is more likely to attract enterprises who are already into the foray, rather than indie programmers.

Since 2010 with retina screen of iPhone 4, there came a herd of Photo-filter apps, most of them relying on open source third party SDKs to create creative effects. In the absence of such SDKs, mavericks often wrote them. The whole effort gave us some really awesome image processing algorithms, both using Core Image as well as OpenGL. But this trend will go downhill after the introduction of Photokit. New programmers, especially the ones who joined the Swift bandwagon, are never likely to know about those awesome third party SDKs, and the hours of perspiration spent for the benefit of community.

Conclusion:

  • Like any other feature rich update, iOS 8 will set the tone for newer kind of apps. However, these changes being in favor of large scale enterprises or Apple itself, indie devs are going to take the blow.
  • Change is inevitable. Earlier you embrace it, the better. Indie devs must suit themselves to iOS systems aimed at enterprise, for only they can churn out utilities from frameworks. And while doing this, keep the torch of community contributions alive, to keep the app world livable. Advice? Hope for the best, and never be unprepared to face the worse.
  • iOS (objective C?) veterans aren’t an endangered species waiting to be rescued from winds of change. What needs to be rescued is their undying attitude and will to change things for future.
  • Despite it’s radical set of innovations, iOS 8 is not declaratively good. On the other hand, it’s not bad either. The only thing that is sure is, it’s different. The change doesn’t ooze freshness as it should, for now.
  • Despite all the pessimism around indie devs who cannot sustain motivation to create and contribute, there exists torch-bearers who have kept the flame burning. Till this flame lasts, the programming passions will keep burning and enlightening the universe.

For all we know for now, iOS 8 is an evolution that gives us new weapons, at the cost of killer instinct.