Business of iOS Apps

August 8, 2014 Leave a comment

iOS apps business by Santiapps.com Marcio Valenzuela

iOS apps business

I keep reading articles or watching videos of iOS businesses who made it and they share their wisdom of the Common 10 Mistakes iOS developers make. Guess what? Most of those mistakes, although they are worded as developer concepts, they are really business concepts.

Common Mistakes: Don’t need a marketing guy. Don’t need a business guy. Don’t need a business perspective. Usually worded as, I thought I would get rich quick, or Im looking for a one hit wonder, or Im a great programmer and I thought that was enough.

Well guess what, if you are going to sell something and make more than 99c for it, its gonna need a Business Plan. But don’t fret, it doesn’t mean you need an MBA to help you come up with a business plan. If you are a level headed guy-or-gal, you should be ok. You just need to know what to put down on paper. You WILL need a plan if you are going to be selling something more than lemonade :)

Its a plan, take out the word ‘business’ if you don’t want to. But just think about this, Steve Jobs wasn’t the business plan type. He wanted to run his company the way he wanted to. So they kicked him out of his own company because of that. True, they begged him to come back, but Jobs had learned a thing or two about making plans. That combination took Apple to the top.

So let’s just call it a plan, because you will jot down ideas to help you organize what you need to do. Let’s add the word operating, because it will be a hands-on kind of plan. And if you wanna get fancy, throw in the word Strategic, because it will take some key ideas to put this plan into action.

Your ‘Strategic-Operating-Plan’

You need to analyze what you have and don’t have. Did you see the movie Public Enemy with Hackman and Smith? Well, if they’re big, you’re small, they’re slow and you’re mobile. To know what you can be, you gotta know what you are right now and what you’re missing.

(SWOT)

1) Know your Strengths

2) Accept your Weaknesses

3) Spot market Opportunities

4) Identify any Threats

Once you know what you have and don’t have, you probably realize you have programming skills but no selling skills. This is typical and it sucks! Guys who invented things (engine, nuclear fission, electricity) get credit, but they don’t get the ladies! Why? Cause they don’t get the moolah! You always see pictures of Einstein and Edison dying poor. But the Presidents and CEOs of companies who make cars, weapons and electricity are sitting pretty making millions every year plus bonuses and benefits.

Its a known fact, business types will always make the money while smarties slave away in a lab somewhere. You therefore need a plan to sell whatever it is you know how to make.

(Marketing Plan)

Product: The app you created is of what type? What exactly did you make and what can it do. It might seem silly, but write it down. More importantly, have others around you look at it, use it and write down what THEY think the product is and does. Did you make something you thought was cool or did you discover a need that nobody was covering quite that well? How many products can you make in a year? What kind of products will they be, will a client pull or will you push in the App Store? Your costs will vary whether its push or pull, but they won’t be zero I can promise you that!

Price: According to the type of app you made, how should you price it? Market vs Cost. You definitely need to cover your costs. But there are different types of costs. These are things you need to identify in your Strengths and Weaknesses. Your upfront costs or initial costs might be high but you can throw them all in a pile as part of the price.

If you took out a loan for 1 year of living expenses while you code (computer, internet, Apple Membership, electric bill, water bill, food, cellular etc) and ended up with a $25,000 loan, you can’t price your app at $25,500 :). You gotta know a little bit about finance such that you spread those costs out over a long period of time. If you made 1 app that sold for $1 (net) and expect 500 downloads a month, thats about $6,000 a year. That would pay off a no-interest loan in 4.1 years. But your loan payments may only be $100 a month. Think about how many apps you think you can put out a year because with 2 apps having 500 monthly downloads, your income doubles.

Place: Where will people buy it? AppStore, website, Facebook ads, Email, word of mouth. Your costs will vary depending on where you have to sell it. True, AppStore helps you lower the cost of marketing your app but it may not be the ONLY place you have to promote your app. A client-pulled app is safer in the sense that it will let you know your income upfront and significantly reduce your costs. Depending on how you defined your app, what needs it covers and how it is priced, you will decide the right place. Tech forums are not the right place for medical apps. A highly priced app would be better off at a local expensive supermarket with a nice banner than via massive emails to your friends.

Promotion: How will you promote it? InApp? iAds? As mentioned before, will this app be push or pull? That tells you where your app will be purchased and thus where you need to push it or have it be pulled. There are many ways to promote your app but in the end you need to monitor your promotions to know which ones are working our for you and which ones aren’t. That’s how you decide where to invest more money in order to promote it.

(Inherent offsync)

This is a heavy pill to swallow. Let’s define a few the kinds of concepts we have talked about and you know are required for app selling.

1) Programmers

2) Graphic Designers

3) Business

4) Sales

Like it or not, these are 4 very different types of people.

Programmers are introverted, mathematical geeks and abstract thinkers.

Graphic Designers are free spirited, un-organized rebels.

Business people are demanding, goal oriented doers.

Sales people are social, pushy creatures that hate work. Selling is not work, its their way of life.

These are mutually exclusive human traits. Ask any psychologist. This is basically why you can’t be a one-man show. You must at least be a two-man show where one programs and the other does business. That’s how most successful businesses are spawned, grown or nurtured. That means you would have to outsource graphic design and sales. Business management and operations really need to be in sync and thus should not be separated from each other and outsourced.

Graphic design is a bit easier to outsource than business-ing and programming. Sales can be ‘pushed’ or outsourced to many platforms nowadays either web, print or digital. You must still know what those platforms are, what their potential is, monitor them and grade them to see which ones work and which ones don’t. But you MUST measure everything and question why something is working (not working) the way it is (isn’t).

I don’t want you to read off with the wrong idea. Yes you CAN make it! Its just not gonna be easy, like everything in life, if you want it to be good, you have to work at it. Don’t be shy or scared of delegating and teaming up. Make sure you cover all angles, development (programming & design), business (operations & management) and sales!

Everyone must be a salesperson if they want to succeed!

Fetching data from an iOS app – The new NSURLSession API

August 1, 2014 Leave a comment
NSURLSession vs NSURLConnection by Santiapps.com Marcio Valenzuela

NSURLSession vs NSURLConnection by Santiapps.com Marcio Valenzuela

Ok, this is gonna be short, I promise! :-)

Do you remember those apps you’ve got stored away or the ones you are working on that fetch data from the web with a NSURLConnection? Time to update them, here’s how.

Basically you have a method that calls a web fetch and is somehow signaled to use that received data to refresh a UI. If you used NSURLConnection sendAsynchronousRequest:, you have the issue that it blocks the main thread. It does carry out requests asynchronously from each other, but each request does indeed block the main thread since it is carried out in the main queue. Alternatively, you can use a long brittle bunch of API’s named NSURLConnection initWithRequest: with a set of delegate callbacks. Instead, take a look at this.

If you have:

-(void)fetchDataFromWeb{
//1. LOAD DATA FROM WEB
NSURL *stringURL = [NSURL URLWithString:@"http://www.yourserver.com/appfolder/somewebserviceURL.php"];
NSURLRequest *myRequest = [NSURLRequest requestWithURL:stringURL];
[NSURLConnection sendAsynchronousRequest:myRequest queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {

//Once data is got, load local object & fire reloadData
jsonArray = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];

//UPDATE CURRENT VIEW FIRST
[self setData];

}];
}

Replace with:

-(void)fetchDataFromWeb{
//1. LOAD DATA FROM WEB
NSURLSession *session = [NSURLSession sharedSession];
[[session dataTaskWithURL:[NSURL URLWithString:@"http://www.yourserver.com/appfolder/somewebserviceURL.php"]
completionHandler:^(NSData *data, NSURLResponse *response,
NSError *error) {
// handle response
//Once data is got, load local object & fire reloadData
jsonArray = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];

//UPDATE CURRENT VIEW FIRST
[self setData];

}] resume];
}

The most important thing to note here, is perhaps an little noticed piece of code in NSURLConnection, queue:[NSOperationQueue mainQueue].

You see, other than that, the both pieces of code do pretty much the same thing. They fetch data. NSURLConnection fetches data but it will block your main thread. This means that if you call the fetch, your app will stop or hand until the NSURLResponse is received.

You could go this route:

1. Adopt the delegate:
& create a data container NSMutableData *_responseData;

2. Call your web fetch:
// Create the request.
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.yourserver.com/appfolder/somewebserviceURL.php"]];

// Create url connection and fire request
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];

3. Get your data from the callbacks:
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
// A response has been received, this is where we initialize the instance var you created
// so that we can append data to it in the didReceiveData method
// Furthermore, this method is called each time there is a redirect so reinitializing it
// also serves to clear it
_responseData = [[NSMutableData alloc] init];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// Append the new data to the instance variable you declared
[_responseData appendData:data];
}

- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
willCacheResponse:(NSCachedURLResponse*)cachedResponse {
// Return nil to indicate not necessary to store a cached response for this connection
return nil;
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// The request is complete and data has been received
// You can parse the stuff in your instance variable now
jsonArray = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
//UPDATE CURRENT VIEW FIRST
[self setData];
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
// The request has failed for some reason!
}

That’s a BIG block of code! And it can get tedious & brittle to maintain.

NSURLSession automatically calls the web fetch in a background thread so as to not block your main thread. How cool is that? :-) Enjoy!

Creating a Menu in SpriteKit

July 26, 2014 Leave a comment
SpriteKit Menu by Santiapps.com Marcio Valenzuela

SpriteKit Menu

Cocos2d has a easy to use CCMenu object to which you add CCMenuItems.  In SpriteKit however, you are back to UIKit objects.  This doesn’t not mean its more complicated, its just different :-).  You will need to create a UIControl such as a button or you can use SpriteKit’s SKNode to create the visual object onscreen:

SKLabelNode*  someNode = [SKLabelNode labelNodeWithFontNamed:@"Chalkduster"];
[someNode setText:@"Play Game"];
[someNode setPosition:CGPointMake(CGRectGetMidX(self.frame)+5,CGRectGetMidY(self.frame)-40)];
[self addChild: someNode];

Now you simply connect the object action to some event like so:

for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];

if ([someNode containsPoint:location]) {
SKTransition* present = [SKTransition revealWithDirection:SKTransitionDirectionDown duration:1];
GameScene* gameScene = [[GameScene alloc] initWithSize:CGSizeMake(1024, 768)];
[self.scene.view presentScene: someNode transition:present];

}
}

Voila!  You are DONE!

Swift Tutorial II

June 7, 2014 Leave a comment

Ok so in the first tutorial we covered let, which is the keyword for defining constants.

let thisBeAConstant = 3.141

Now we are going to cover variables, which use the var keyword like so:

var thisVariable = time

Notice 2 things about Swift:

1) We don’t use ; at the end of a line.  That’s just weird :-)

2) We don’t have to specify the type.  The type is inferred by whatever value you pass in, so:

var someString = “this is a string”

var someInteger = 5

So Swift is kinda smart.  Now let’s meet some old friends “Hao jiu bu juan”

ARRAYS

var energies = ["solar""wind""fossil", "this is a mixed array", 39]

var energies:String[] = ["solar""wind""this is a string array"]

And of course we can perform some basic operations such as:

READ

var item1 = energies[0]   // “solar”

INSERT

energies.insert(“hydro”, atIndex: 2)

MODIFY

energies[3] = “geothermal”

APPEND

energies.append(“nuclear”)

or

energies += “nuclear”

COMBINE

energies += ["biomass""hamster"]

COUNT

var lengthofArray = energies.count

LOGIC

var arrayIsEmpty = energies.isEmpty

REMOVE

energies.removeAtIndex(3)
energies.removeLast()
energies.removeAll(keepCapacity: true)
MUTATE
If we used let energies, then our array is immutable, vs if we used var energies which means its mutable.
Easy as pie.
DICTIONARIES

var energies = [

    "Solar""Thermal",
    "Photovoltaic" : "Grid",
    "Nuclear" : "Dangerous"
]
Here our keys are Solar, Photovoltaic & Nuclear.  These keys can be strings or numeric values such as integers.
Once again we can:
READ
let cheapestSolarEnergy = energies["Solar"]
COUNT
var energiesCount = energies.count
MODIFY
energies["Solar"] = “PV”
REMOVE
energies["Nuclear"] = nil;
INSERT
energies["Geo"] = “Thermal”
and of course the value of a key can be an array or another dictionary:

var typesOfEnergy =

[
    platforms["Solar"]: ["Thermal""PV""GridTied"],
    platforms["Wind"]: ["Autonomous""GridTied"],
    platforms["Nuclear"] : ["Fusion""Fission","Meltdown"]
]
and we would read it:
var type1 = typesOfEnergy["Solar"][0]
See you next time! :-)

First SWIFT Tutorial ever! :-)

June 3, 2014 Leave a comment

let is used for assigning constants whereas var is used for creating variables.

ie:

let  salute: Character = “Hey there…”

let everyone: Character = “Swift World”

var saluteEveryone = salute + everyone

saluteEveryone = saluteEveryone + “!”

Categories: Swift Tags: , , , , ,

Comment Coding – Coding for Visual Learners

May 14, 2014 Leave a comment
Visual Learning iOS Coding

Visual Learning iOS Coding

I’ve mentioned this in my online courses as well as classroom courses and its usually overlooked.  I think its an important design technique for those of us who are Visual Learners.

What’s a Visual Learner?

Many people, prime examples are asian students, are great at math because they are quick to grasp abstract tasks.  They can read a sentence or paragraph and understand everything the first time.  Not me!

I’m the kind of person that has to read concepts 10 times over and still have trouble applying it.  I need visual representations of concepts in order to understand them.  As a matter of fact, I review iOS and Cocos2D books and my comments are usually “We should insert a sketch here showing how a block of code is passed to a method and executed at a given time…”.

We visual learners have a hard time organizing concepts in our mind unless we write things down or sketch what we believe is being said.

 

Coding in 3 Steps:

1.  Draw it!

Creating an app or game is just like understanding an abstract concept.  I usually start out drawing a storyboard on paper.  I need to see a sketched drawing of what the app’s views are going to look like.  I usually draw views and some important controls that transition between one view and the next.  I also try to visualize the flow of data from one view to another.  This can get a little tricky but if one sheet of paper won’t do, Ill usually end up with 4 sheets taped together, a whiteboard of which I take pictures of or Penultimate.  Unfortunately Penultimate runs on an iPad whose screen I wish were bigger :)

iOS Sketch Comment Coding

iOS Sketch Comment Coding

2. Comment it!

This is where the magic happens.  I will basically open up Xcode, create the classes I drew out as objects and comment all my ideas.  What Ill do is go into a class and create its methods, at least the methods I think it should have.  Originally these method names were simple, such as:

somehowGetDataFromFlickr

somehowShowDataInConsole

popAlertToUser

makeCopyOfData

showListOfDataToUser

but eventually, as I picked up more knowledge, learned that many tasks are repetitive patterns and understood UX and coding techniques, those names evolved:

downloadDataFromWeb

parseDataIntoFoundationObjects

notifyUserDataDownloaded

notifyUserDataIsParsed

shareDataWithObservers

logDataInCoreData

updateUIScreenWithNewData

So now I know, in layman’s terms, what I need to do.  This would, at first, take me to Google.com and eventually to StackOverflow.com.  I would basically append “How to…” that proposed name method and “…in iOS”.  This would give me some code samples and I would begin researching the examples I found.  Eventually I learned how to read Apple Documentation (How to Read iOS or Mac OS Programming Documentation) and Apple documentation took precedence over Google and StackOverflow.

What I would do next is take a particular method and insert comments of what that method should do:

-(void)downloadDataFromWeb{

//1. NSURLConnection

//2. Get data from delegate methods

}

Then I would begin coding right underneath each comment.

 

3. Code it!

Finally I would take examples from any source I found online and download them and tinker with them until I made sure I understood what they do.  In time this is replaced by understanding how OOP works and its many useful patterns.  This is when coding gets to be a pleasure!

So it takes a while, but you WILL eventually have FUN coding.  But its a lot easier to get to the fun part if you are a Visual Learner and use Comment Coding to get you there with a decent bit of sanity left :)

Enjoy Coding!

Categories: Iphone Developer

Creating a simple UICollectionView in iOS

May 9, 2014 1 comment

Steps

1) Create Master-Detail Application & Replace the MasterViewController

First we want to create a Master-Detail Application just because it sets up a Master-Detail relationship even though thats the first thing we are going to break :).  So go ahead and create a new project in XCode4 based on a Master-Detail Application type.  Use ARC, Storyboards and CoreData because we will use CoreData to store information.  Your storyboard should look like this:

Master-Detail Storyboard

Master-Detail Storyboard

Now select the Master scene until its highlighted in blue and delete it with the Delete key.  We simply replace it by dragging in a UICollectionViewController onto the storyboard in its place.  This places a UICollectionViewController scene with a small empty collectionview cell in the top left corner.  I made a few adjustments to mine and here is what it looks like but Ill go over those later:

UICollectionViewController Storyboard

UICollectionViewController Storyboard

The changes I made to it are the following:

a – Select the entire scene (again until its highlighted blue) and change its Class type from UICollectionViewController to MasterViewController.

b – Enlarged the UICollectionViewCell from 50×50 to 145×145 in the Dimension’s Inspector

Here are some clips of the Identity Inspector of the MasterViewController and Dimension’s Inspector of the UICollectionViewCell:

UICollectionViewController Identity Inspector

UICollectionViewController Identity Inspector

UICollectionViewCell Dimensions Inspector

UICollectionViewCell Dimensions Inspector

We did set the new UICollectionViewController to a new class, the MasterViewController class.  We must do the same with the UICollectionViewCell but we must create its class first.

2)  Modify the MasterViewController class with the following in the .m file:

#import “MasterViewController.h”

#import “DetailViewController.h”

#import “MyCustomCell.h”

#import “AppDelegate.h”

static NSString *CellIdentifier = @”MyCustomCell”;

@interface MasterViewController ()

{

NSMutableArray *_objectChanges;

NSMutableArray *_sectionChanges;

}

@end

Now let’s go through the methods.  First the UICollectionView methods, which are quite similar to the UITableViewController methods:

#pragma mark – UICollectionView

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section

{

id <NSFetchedResultsSectionInfo> sectionInfo = [self.fetchedResultsController sections][section];

return [sectionInfo numberOfObjects];

}

// The cell that is returned must be retrieved from a call to -dequeueReusableCellWithReuseIdentifier:forIndexPath:

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath

{

MyCustomCell *cell = (MyCustomCell *)[collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];

NSManagedObject *object = [self.fetchedResultsController objectAtIndexPath:indexPath];

[cell setImage:[UIImage imageWithData:[object valueForKey:@"photoImageData"]]];

return cell;

}

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender

{

if ([[segue identifier] isEqualToString:@”showDetail”]) {

NSIndexPath *indexPath = [[self.collectionView indexPathsForSelectedItems] lastObject];

NSManagedObject *object = [[self fetchedResultsController] objectAtIndexPath:indexPath];

[[segue destinationViewController] setDetailItem:object];

}

}

The MyCustomCell Class is the one we will create in the next section.  For now we are simply filling in the cell’s image data with some fetched managed object which we will also create later.  A couple of more interesting tidbits for example; we gave our UICollectionViewCell a reuse identifier and we gave our segue an identifier as well.  We must make sure these identifiers also exist in the storyboard inspectors for the cell and segue respectively.

3) Create UICollectionViewCell Class & Connect it

Let’s go ahead and Create a New File in our project, base it off of Objective C Class.  Type in UICollectionViewCell as the subclass and name it MyCustomCell.  We are simply going to define a class for our UICollectionViewCell and once we are finished, we must go to Storyboard and set our cell to use this new class type.

Add a UIImageView property to the class so that your .h file looks like this:

#import <UIKit/UIKit.h>

@interface MyCustomCell : UICollectionViewCell{

IBOutlet UIImageView *imageView;

}

-(void)setImage:(UIImage *)image;

@end

and now implement the setter in your .m so that it looks like this:

#import “MyCustomCell.h”

@implementation MyCustomCell

-(void)setImage:(UIImage *)image{

[imageView setImage:image];

}

@end

4) Create the data model.  First let’s do the easiest part, which is creating the data model.  Select your project’s xcdatamodel file and create a new Entity, call it Snapshots if you’d like.  Now add 3 attributes to it and make them of this type:

Core Data Entity Data Model

Core Data Entity Data Model

Once that is done, we have a storage container for our data.  Let’s look at the code used by our app to access this store and manipulate it.

#pragma mark – Fetched results controller

- (NSFetchedResultsController *)fetchedResultsController

{

if (_fetchedResultsController != nil) {

return _fetchedResultsController;

}

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];

// Edit the entity name as appropriate.

NSEntityDescription *entity = [NSEntityDescription entityForName:@"Snapshots" inManagedObjectContext:self.managedObjectContext];

[fetchRequest setEntity:entity];

// Set the batch size to a suitable number.

[fetchRequest setFetchBatchSize:20];

// Edit the sort key as appropriate.

NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@”photoName” ascending:NO];

NSArray *sortDescriptors = @[sortDescriptor];

[fetchRequest setSortDescriptors:sortDescriptors];

// Edit the section name key path and cache name if appropriate.

// nil for section name key path means “no sections”.

NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:@”Master”];

aFetchedResultsController.delegate = self;

self.fetchedResultsController = aFetchedResultsController;

NSError *error = nil;

if (![self.fetchedResultsController performFetch:&error]) {

// Replace this implementation with code to handle the error appropriately.

// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.

NSLog(@”Unresolved error %@, %@”, error, [error userInfo]);

abort();

}

return _fetchedResultsController;

}

- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo

atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type

{

NSMutableDictionary *change = [NSMutableDictionary new];

switch(type) {

case NSFetchedResultsChangeInsert:

change[@(type)] = @(sectionIndex);

break;

case NSFetchedResultsChangeDelete:

change[@(type)] = @(sectionIndex);

break;

}

[_sectionChanges addObject:change];

}

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject

atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type

newIndexPath:(NSIndexPath *)newIndexPath

{

NSMutableDictionary *change = [NSMutableDictionary new];

switch(type)

{

case NSFetchedResultsChangeInsert:

change[@(type)] = newIndexPath;

break;

case NSFetchedResultsChangeDelete:

change[@(type)] = indexPath;

break;

case NSFetchedResultsChangeUpdate:

change[@(type)] = indexPath;

break;

case NSFetchedResultsChangeMove:

change[@(type)] = @[indexPath, newIndexPath];

break;

}

[_objectChanges addObject:change];

}

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller

{

if ([_sectionChanges count] > 0)

{

[self.collectionView performBatchUpdates:^{

for (NSDictionary *change in _sectionChanges)

{

[change enumerateKeysAndObjectsUsingBlock:^(NSNumber *key, id obj, BOOL *stop) {

NSFetchedResultsChangeType type = [key unsignedIntegerValue];

switch (type)

{

case NSFetchedResultsChangeInsert:

[self.collectionView insertSections:[NSIndexSet indexSetWithIndex:[obj unsignedIntegerValue]]];

break;

case NSFetchedResultsChangeDelete:

[self.collectionView deleteSections:[NSIndexSet indexSetWithIndex:[obj unsignedIntegerValue]]];

break;

case NSFetchedResultsChangeUpdate:

[self.collectionView reloadSections:[NSIndexSet indexSetWithIndex:[obj unsignedIntegerValue]]];

break;

}

}];

}

} completion:nil];

}

if ([_objectChanges count] > 0 && [_sectionChanges count] == 0)

{

[self.collectionView performBatchUpdates:^{

for (NSDictionary *change in _objectChanges)

{

[change enumerateKeysAndObjectsUsingBlock:^(NSNumber *key, id obj, BOOL *stop) {

NSFetchedResultsChangeType type = [key unsignedIntegerValue];

switch (type)

{

case NSFetchedResultsChangeInsert:

[self.collectionView insertItemsAtIndexPaths:@[obj]];

break;

case NSFetchedResultsChangeDelete:

[self.collectionView deleteItemsAtIndexPaths:@[obj]];

break;

case NSFetchedResultsChangeUpdate:

[self.collectionView reloadItemsAtIndexPaths:@[obj]];

break;

case NSFetchedResultsChangeMove:

[self.collectionView moveItemAtIndexPath:obj[0] toIndexPath:obj[1]];

break;

}

}];

}

} completion:nil];

}

[_sectionChanges removeAllObjects];

[_objectChanges removeAllObjects];

}

I know its long, but its pretty simple.  The first method, – (NSFetchedResultsController *)fetchedResultsController, basically opens up the store, fetches all entities by the name “Snapshots” and places them into a special object called NSFetchedResultsController.

The didChangeSection method is called when there is a change within a section.  We only have 1 section in our UICollectionView.

The didChangeObject method is called when a particular object is changed within our UICollectionView.

The controllerDidChangeContent actually manages the changes made.  Basically we update our two arrays, _sectionChanges and _objectChanges with each change in the data in order to keep our UICollectionView current.

5) Connect to Flickr API.  So what constitutes a change in those sections and objects?  There is an acronym that datastore managers use, CRUD, which basically says that everytime you create, read, update or delete you create a transaction.  Thats basically what we want to track (except for the read part :)).  So whenever we download a new photo to our datastore, update a photo or delete one, we trigger changes in objects and thus in sections.

We want to use the Flickr API to get images from the web and populate our collection view.  We are basically going to perform a fetch to Flickr API using our own key or identifier.  You must register for one at flickr.com/.

a – Get FlickrAPIKey and add it here to this string constant atop your .m file like so:

NSString *const FlickrAPIKey = @"YOURAPIKEYVALUE";

b – Add the loadFlickrPhotos method to fetch pics from the web.  So add this method:

- (void)loadFlickrPhotos{

// 1. Build your Flickr API request w/Flickr API key in FlickrAPIKey.h

NSString *urlString = [NSString stringWithFormat:@"http://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=%@&tags=%@&per_page=10&format=json&nojsoncallback=1", FlickrAPIKey, @"bayern"];

NSURL *url = [NSURL URLWithString:urlString];

// 2. Get URLResponse string & parse JSON to Foundation objects.

NSString *jsonString = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];

NSError *e = nil;

NSDictionary *results = [NSJSONSerialization JSONObjectWithData:[jsonString dataUsingEncoding:NSUTF8StringEncoding]options:NSJSONReadingMutableContainers error:&e];

photos = [[results objectForKey:@"photos"] objectForKey:@”photo”];

for (NSDictionary *photo in photos) {

// 3.a Get title for e/ photo

NSString *title = [photo objectForKey:@"title"];

[photoNames addObject:(title.length > 0 ? title : @"Untitled")];

// 3.b Construct URL for e/ photo.

NSString *photoURLString = [NSString stringWithFormat:@”http://farm%@.static.flickr.com/%@/%@_%@_s.jpg&#8221;, [photo objectForKey:@"farm"], [photo objectForKey:@"server"], [photo objectForKey:@"id"], [photo objectForKey:@"secret"]];

[photoURLs addObject:[NSURL URLWithString:photoURLString]];

}

// Process into CoreData

[self processCoreData];

}

It basically looks for Flickr photos of Bayern and stores the results in the photos ivar.  Now we must populate our CoreData db with these data.

c – Populate our CoreData model.  Add the processCoreData method to your MasterViewController.m like so:

-(void)processCoreData{

AppDelegate *myDelegate = [[UIApplication sharedApplication] delegate];

for (NSDictionary *photoDictionary in photos){

NSManagedObject *photoModel = [NSEntityDescription insertNewObjectForEntityForName:@"AFPhotoModel" inManagedObjectContext:myDelegate.managedObjectContext];

//[photoModel setValue:[photoDictionary valueForKey:@"rating"] forKey:@”photoRating”];

[photoModel setValue:[photoDictionary valueForKey:@"title"] forKey:@”photoName”];

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{

//Build URL

NSString *photoURLString = [NSString stringWithFormat:@”http://farm%@.static.flickr.com/%@/%@_%@_s.jpg&#8221;, [photoDictionary objectForKey:@"farm"], [photoDictionary objectForKey:@"server"], [photoDictionary objectForKey:@"id"], [photoDictionary objectForKey:@"secret"]];

NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:photoURLString]];

dispatch_async(dispatch_get_main_queue(), ^{

[photoModel setValue:imageData forKey:@"photoImageData"];

});

});

}

}

Voila!  Run your app!

Follow

Get every new post delivered to your Inbox.

Join 620 other followers