Quantcast
Channel: Envato Tuts+ Code - Mobile Development
Viewing all 1836 articles
Browse latest View live

An Introduction to Swift: Part 2

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-21484

In the first article of this introductory series on Swift, we talked about Swift's philosophy, took a first look at its syntax, and highlighted a few key differences with Objective-C. In this article, we continue our exploration of Swift's syntax. You'll also learn about optionals and see how memory management works in Swift.

1. Conditionals and Loops

If

If statements are identical in Swift and Objective-C with the exception of two subtle differences:

  • parentheses around the condition variable are optional
  • curly braces are required

These are about the only differences with if statements in Objective-C.

Ranges

As we saw in the first article, Swift includes two range operators ..< and ... to specify a range of values. These two operators are the half-closed range operator and the closed range operator.

A half-closed range, such as 1..<5, represents the values 1, 2, 3, and 4, excluding 5. A closed range, such as 1...5, represents the values 1, 2, 3, 4, and includes 5.

Ranges can be used in for loops, array subscript, and even in switch statements. Take a look at the following examples.

// for loop example
for i in 1..<10 {
}
// iterates from 1 to 9
// array subscript example
let someArray = ["apple","pair","peach","watermelon","strawberry"]
for fruit in someArray[2..<4] {
    println(fruit)
}
// outputs: peach and watermelon
// switch example
switch someInt {
    case 0:
    // do something with 0
    case 1..<5:
    // do something with 1,2,3,4
    case 5...10:
    // do something with 5,6,7,8,9,10
    default:
    // everything else
}

Switch

Switch statements are more powerful in Swift than they are in Objective-C. In Objective-C,  the result of the expression of a switch statement needs to be of type integer and the values of each case statement should be a constant or a constant expression. This isn't true in Swift. In Swift, the case statements can be of any type, including ranges.

In Swift, switch has no break statements and it doesn't automatically fall through from one case to another. When writing a switch statement, care must be taken that all conditions are being handled by its case statements, failing to do so will result in a compiler error. A sure way to cover all conditions is to include a default case statement.

Here's an example of a switch statement with String cases:

let vegetable = "red pepper"
switch vegetable {
case "celery":
    let vegetableComment = "Add some raisins and make ants on a log."
case "cucumber", "watercress":
    let vegetableComment = "That would make a good tea sandwich."
default:
    let vegetableComment = "Everything tastes good in soup."
}

In Swift, case statements don't fall through by default. This was a deliberate design decision to avoid common errors. If a specific case needs to fall through, you can use the fallthrough keyword to indicate this to the compiler.

switch someInt {
    case 0:
    // do something with 0
    case 1:
    // do something with 1
    case 2:
    // do something with 2
        fallthrough
    default:
    //do something for everything else
}

// case 2 will fall through to default case

It doesn't stop here. Swift adds two other features to switch, value bindings and the whereclause. Value binding is used with the case let keywords to bind a constant with the matching case. The where clause adds an extra condition to the case statement using the where keyword.

These two concepts are better explained with examples. The following code block shows how value binding works.

let somePoint = (xaxis:2, yaxis:0)
switch somePoint {
case (let x, 0):
    println("on the x-axis with an x value of \(x)")
case (0, let y):
    println("on the y-axis with a y value of \(y)")
case let (x, y):
    println("somewhere else at (\(x), \(y))")
}

The first case statement, case (let x, 0), will match the values where yaxis is equal to 0 and any value  for xaxis, and we bind xaxis to the constant x to be used inside the case statement.

Here's an example of the where clause in action.

let vegetable = "red pepper"
switch vegetable {
case "celery":
    println("Add some raisins and make ants on a log.")
case let x where x.hasSuffix("pepper"):
    println("I'm allergic to \(x)")
default:
    println( "Everything tastes good in soup.")
}

// outputs: I'm allergic to red pepper

2. Functions and Closures

Functions

Defining functions and closures is easy in Swift. Objective-C developers know them better as functions and blocks.

In Swift, function parameters can have default values, which is reminiscent of scripting languages, such as PHP and Ruby.

The syntax for functions is as follows:

func functionName(parameterName: Type = DefaultValue) -> returnType {
    [...]
    return returnType;
}

To write a sayHello function that takes a parameter name of type String and returns a Bool when successful, we write the following:

func sayHello(name: String) -> Bool {
    println("hello \(name)");
    return true;
}

sayHello("World")
// output
// hello World

To pass a default value for the name parameter, the function's implementation would look as follows:

func sayHello(name: String = "World") -> Bool {
    println("hello \(name)");
    return true;
}

sayHello()
// output
// hello World

sayHello("mike")
// output
// hello mike

A feature that is completely absent in Objective-C are tuples. In Swift, functions can return multiple values in the form of a tuple. Tuples are treated as a single variable, which means that you can pass it around just like a variable.

Tuples are very easy to use. In fact, we've already worked with tuples in the previous article when we enumerated a dictionary. In the next code snippet, the key/value pair is a tuple.

for (key,value) in someDictionary {
    println("Key \(key) has value \(value)"
}

How are tuples used and how do you benefit from them? Let's take a look at another example. Let's modify the above sayHello function to return a boolean when successful as well as the resulting message. We do this by returning a tuple, (Bool, String). The updated sayHello function looks like this:

func sayHello(name: String = "World") -> (Bool, String) {
    let greeting = "hello \(name)"
    return (true, greeting);
}

let (success, greeting) = sayHello()
println("sayHello returned success:\(success) with greeting: \(greeting)");
// output
// sayHello returned success:1 with greeting: hello World

Tuples have been on the wish list of many Objective-C programmers for a long time.

Another cool feature of tuples is that we can name the returned variables. If we revisit the previous example and give names to the variables of the tuple, we get the following:

func sayHello(name: String = "World") -> (success: Bool, greeting: String) {
    let greeting = "hello \(name)"
    return (true, greeting);
}

let status = sayHello()
println("sayHello returned success:\(status.success) with greeting: \(status.greeting)");
// output
// sayHello returned success:1 with greeting: hello World

This means that instead of defining a separate constant for each return element of a tuple, we can access the returned tuple elements using dot notation as shown in the above example, status.success and status.greeting.

Closures

Closures in Swift are the same as blocks in Objective-C. They can be defined inline, passed as a parameter, or returned by functions. We use them exactly as we would use blocks in Objective-C.

Defining closures is also easy. Actually, a function is a special case of closures. So it's no wonder that defining a closure looks a lot like defining a function.

Closures are a first-class type, which means that they can be passed and returned by functions just like any other type, such as IntStringBool, etc. Closures are essentially code blocks that can be called later and have access to the scope in which they were defined.

Creating an nameless closure is as simple as wrapping a block of code in curly braces. The parameters and return type of the closure are separated from the closure's body with the in keyword.

Let's say we want to define a closure that returns true if a number is even, then that closure could look something like:

let isEven = {
(number: Int) -> Bool in
let mod = number % 2
return (mod==0)
}

The isEven closure takes an Int as its single parameter and returns a Bool. The type of this closure is (number: Int) -> Bool, or (Int -> Bool) for short. We can call isEven anywhere in our code just like we would invoke a code block in Objective-C.

To pass a closure of this type as a parameter of a function, we use the closure's type in the function's definition:

let isEven = {
    (number: Int) -> Bool in
    let mod = number % 2;
    return (mod==0);
}

func verifyIfEven(number: Int, verifier:(Int->Bool)) ->Bool {
    return verifier(number);
}

verifyIfEven(12, isEven);
// returns true

verifyIfEven(19, isEven);
// returns false

In the above example, the verifier parameter of the verifyIfEven function is a closure that we pass to the function.

3. Classes & Structures

Classes

It's time to talk about the cornerstone of object-oriented programming, classes. Classes, as mentioned before, are defined in a single implementation file with a .swift extension. Property declarations and methods are all defined in that file.

We create a class with the class keyword followed by the name of the class. The class's implementation is wrapped in a pair of curly braces. As in Objective-C, the naming convention for classes is to use upper camel case for class names.

class Hotel {
    //properties
    //functions
}

To create an instance of the Hotel class we write:

let h = Hotel()

In Swift, there's no need to call init on objects as init is called automatically for us.

Class inheritance follows the same pattern as in Objective-C, a colon separates the class name and that of its superclass. In the following example, Hotel inherits from the BigHotel class.

class BigHotel: Hotel {

}

As in Objective-C, we use dot notation to access an object's properties. However, Swift also uses the dot notation to invoke class and instance methods as you can see below.

// Objective-C
UIView* view = [[UIView alloc] init];
[self.view addSubview:view];

// Swift
let view = UIView()
self.view.addSubview(view)

Properties

Another difference with Objective-C is that Swift doesn't distinguish between instance variables (ivars) and properties. An instance variable is a property.

Declaring a property is just like defining a variable or a constant, using the var and let keywords. The only difference is the context in which they are defined, that is, the context of a class.

class Hotel {
    let rooms = 10
    var fullRooms = 0
}

In the above example, rooms is an immutable value, a constant, set to 10 and fullRooms is a variable with an initial value of 0, which we can change later. The rule is that properties need to be initialized when they're declared. The only exception to this rule are optionals, which we'll discuss in a moment.

Computed Properties

The Swift language also defines computed properties. Computed properties are nothing more than fancy getters and setters that don't store a value. As their name indicates, they are computed or evaluated on the fly.

Below is an example of a computed property. I have changed the rooms property to a var for the rest of these examples. You'll find out why later.

class Hotel {
    var rooms = 10
    var fullRooms = 0
    var description: String {
        get {
            return "Size of Hotel: \(rooms) rooms capacity:\(fullRooms)/\(rooms)"
        }
    }
}

Because the description property is read-only and only has a return statement, we can omit the get keyword and curly braces, and only keep the return statement. This is shorthand and that's what I'll be using in the rest of this tutorial.

class Hotel {
    var rooms = 10
    var fullRooms = 0
    var description: String {
        return "Size of Hotel: \(rooms) rooms capacity:\(fullRooms)/\(rooms)"
    }    
}

We can also define read-write computed properties. In our class Hotel, we want an emptyRooms property that gets the number of empty rooms in the hotel, but we also want to update fullRooms when we set the emptyRooms computed property. We can do this by using the set keyword as shown below.

class Hotel {
    var rooms = 10
    var fullRooms = 0
    var description: String {
        return "Size of Hotel: \(rooms) rooms capacity:\(fullRooms)/\(rooms)"
    }    
    var emptyRooms :Int {
        get {
            return rooms - fullRooms
        }
        set {
            // newValue constant is available here 
            // containing the passed value
            if(newValue < rooms) {
                fullRooms = rooms - newValue
            } else {
                fullRooms = rooms
            }
        }
    }
}

let h = Hotel()
h.emptyRooms = 3
h.description
// Size of Hotel: 10 rooms capacity:7/10

In the emptyRooms setter, the newValue constant is handed to us and represents the value passed to the setter. It's also important to note that computed properties are always declared as variables, using the var keyword, because their computed value can change.

Methods

We've already covered functions earlier in this article. Methods are nothing more than functions that are tied to a type, such as a class. In the following example we implement an instance method, bookNumberOfRooms, in the Hotel class we created earlier.

class Hotel {
    var rooms = 10
    var fullRooms = 0
    var description: String {
        return "Size of Hotel: \(rooms) rooms capacity:\(fullRooms)/\(rooms)"
    }
    var emptyRooms :Int {
        get {
            return rooms - fullRooms
        }
        set {
            // newValue constant is available here
            // containing the passed value
            if(newValue < rooms) {
                fullRooms = rooms - newValue
            } else {
                fullRooms = rooms
            }
        }

    }
    func bookNumberOfRooms(room:Int = 1) -> Bool
    {
        if(self.emptyRooms>room) {
            self.fullRooms++;
            return true
        } else {
            return false
        }
    }
}

let h = Hotel()
h.emptyRooms = 7
h.description
//Size of Hotel: 10 rooms capacity:3/10
h.bookNumberOfRooms(room: 2)
// returns true
h.description
//Size of Hotel: 10 rooms capacity:5/10
h.bookNumberOfRoom()
// returns true
h.description
//Size of Hotel: 10 rooms capacity:6/10


Initializers

The default initializer for classes is init. In the init function, we set the initial values of the instance that is created.

For example, if we would need a Hotel subclass with 100 rooms, then we would need an initializer to set the rooms property to 100. Remember that I previously changed rooms from being a constant to being a variable in the Hotel class. The reason is that we cannot change inherited constants in a subclass, only inherited variables can be changed.

class BigHotel: Hotel {
    init() {
        super.init()
        rooms = 100
    }
}

let bh = BigHotel()
println(bh.description);
//Size of Hotel: 100 rooms capacity:0/100

Initializers can also take parameters. The following example shows you how this works.

class CustomHotel: Hotel {
    init(size:Int) {
        super.init()
        rooms = size
    }
}

let c = CustomHotel(size:20)
c.description
//Size of Hotel: 20 rooms capacity:0/20

Overriding Methods and Computed Properties

This is one of the coolest things in Swift. In Swift, a subclass can override both methods and computed properties. To do so, we use the override keyword. Let's override the description computed property in the CustomHotel class:

class CustomHotel: Hotel {
    init(size:Int) {
        super.init()
        rooms = size
    }
    override var description:String {
        return super.description + " Howdy!"
    }
}

let c = CustomHotel(size:20)
c.description
// Size of Hotel: 20 rooms capacity:0/20 Howdy!

The result is that description returns the result of the superclass's description method with the string "Howdy!" appended to it.

What's cool about overriding methods and computed properties is the override keyword. When the compiler sees the override keyword, it checks wether the class's superclass implements the method that's being overridden. The compiler also checks if the properties and methods of a class are in conflict with properties or methods higher up the inheritance tree.

I don't know how many times a typo in an overridden method in Objective-C made me curse, because the code wasn't working. In Swift, the compiler will tell you exactly what's wrong in these situations.

Structures

Structures, defined with the struct keyword, are more powerful in Swift than they are in C and Objective-C. In C, structs define only values and pointers. Swift structs are just like C structs, but they also support computed properties and methods.

Anything you can do with a class, you can do with a structure, with two important differences:

  • structures don't support inheritance like classes do
  • structures are passed around by value while classes are passed by reference

Here are a few examples of structures in Swift:

struct Rect {
    var origin: Point
    var size: Size
    var area: Double {
        return size.width * size.height
    }
    func isBiggerThanRect(r:Rect) -> Bool {
        return (self.area > r.area)
    }
}

struct Point {
    var x = 0
    var y = 0
}
    
struct Size {
    var width = 0
    var height = 0
}

4. Optionals

Solution To a Problem

Optionals are a new concept if you're coming from Objective-C. They solve a problem we all face as programmers. When we access a variable whose value we're not sure about, we usually return an indicator, known as a sentinel, to indicate that the returned value is a no-value. Let me illustrate this with an example from Objective-C:

NSString* someString = @"ABCDEF";
NSInteger pos = [someString rangeOfString:@"B"].location;

// pos = 1

In the above example, we are trying to find the position of @"B" in someString. If @"B" is found, its location or position is stored in pos. But what happens if @"B" isn't found in someString?

The documentation states that rangeOfString: returns an NSRange with location set to the NSNotFound constant. In the case of rangeOfString:, the sentinel is NSNotFound. Sentinels are used to indicate that the returned value is not valid.

In Cocoa, there are many uses of this concept, but the sentinel value differs from context to context, 0, -1, NULL, NSIntegerMax, INT_MAX, Nil, etc. The problem for the programmer is that she must remember which sentinel is used in which context. If the programmer isn't careful, she can mistake a valid value for a sentinel and vice versa. Swift solves this problem with optionals. To quote Brian Lanier "Optionals are the one sentinel to rule them all."

Optionals have two states, a nil state, which means the optional contains no value, and a second state, which means it holds a valid value. Think of optionals as a package with an indicator to tell you if the package's contents is valid or not.

Usage

All types in Swift can become an optional. We define an optional by adding a ? after the type declaration like so:

let someInt: Int?

// someInt == nil

We assign a value to an optional's package just like we do with constants and variables.

someInt = 10

// someInt! == 10

Remember that optionals are like packages. When we declared let someInt: Int?, we defined an empty box with a value of nil. By assigning the value 10 to the optional, the box contains an integer that is equal to 10 and its indicator or state becomes not nil.

To get to the contents of an optional we use the ! operator. We must be sure that the optional has a valid value before unwrapping it. Failing to do so will cause a runtime error. This is how we access the value stored in an optional:

if ( someInt != nil) {
    println("someInt: \(someInt!)")
} else {
    println("someInt has no value")
}

// someInt: 10

The above pattern is so common in Swift that we can simplify the above code block by using optional binding with the if let keywords. Take a look at the updated code block below.

if let value = someInt {
    println("someInt: \(value)")
} else {
    println("someInt has no value")
}

Optionals are the only type that can take a nil value. Constants and variables cannot be initialized or set to nil. This is part of Swift's safety policy, all non-optional variables and constants must have a value.

5. Memory Management

If you remember, back when ARC was introduced we were using the strong and weak keywords to define object ownership. Swift also has a strong and weak ownership model, but it also introduces a new one, unowned. Let's take a look at each object ownership model in Swift.

strong

Strong references are the default in Swift. Most of the time, we own the object that we're referencing and we are the ones responsible for keeping the referenced object alive.

Since strong references are the default, there is no need to explicitly keep a strong reference to an object, any reference is a strong reference.

weak

A weak reference in Swift indicates that the reference points to an object that we're not responsible for keeping alive. It's mainly used between two objects that don't need the other to be around in order for the object to continue its life cycle.

There is one but, however. In Swift, weak references must always be variables with an optional type, because they are set to nil when the referenced object is deallocated. The weak keyword is used to declare a variable as weak:

weak var view: UIView?

unowned

Unowned references are new for Objective-C programmers. An unowned reference means that we're not responsible for keeping the referenced object alive, just like weak references.

The difference with a weak reference is that an unowned reference is not set to nil when  the object it references is deallocated. Another important difference with weak references is that unowned references are defined as a non-optional type.

Unowned references can be constants. An unowned object doesn't exist without its owner  and therefore the unowned reference is never nil. Unowned references need the unowned keyword before the definition of the variable or constant.

unowned var view: UIView

Conclusion

Swift is an amazing language that has a lot of depth and potential. It's fun to write programs with and it removes a lot of the boilerplate code we write in Objective-C to make sure our code is safe.

I highly recommend The Swift Programming Language, which is available for free in Apple's iBooks Store.

2014-07-28T17:20:10.794Z2014-07-28T17:20:10.794ZMichael Musallam

Core Data from Scratch: More NSFetchedResultsController

$
0
0

In this tutorial, we continue our exploration of the NSFetchedResultsController class by adding the ability to update and delete to-do items. You'll notice that updating and deleting to-do items is surprisingly easy thanks to the groundwork we laid in the previous tutorial.

1. Updating a Record's Name

Step 1: Create View Controller

Start by creating a new UIViewController subclass named TSPUpdateToDoViewController. In TSPUpdateToDoViewController.h, declare an outlet, textField of type UITextField, and two properties, managedObjectContext of type NSManagedObjectContext and record of type NSManagedObject. Add an import statement for the Core Data framework at the top.

#import <UIKit/UIKit.h>

#import <CoreData/CoreData.h>

@interface TSPUpdateToDoViewController : UIViewController

@property (weak, nonatomic) IBOutlet UITextField *textField;

@property (strong, nonatomic) NSManagedObjectContext *managedObjectContext;

@property (strong, nonatomic) NSManagedObject *record;

@end

In the view controller's implementation file, TSPUpdateToDoViewController.m, create two actions, cancel: and save:. Their implementations can remain empty for the time being.

#import "TSPUpdateToDoViewController.h"

@implementation TSPUpdateToDoViewController

#pragma mark -
#pragma mark Actions
- (IBAction)cancel:(id)sender {
    
}

- (IBAction)save:(id)sender {
    
}

@end

Step 2: Update Storyboard

Open the main storyboard, Main.storyboard, add a new view controller object, and set its class to TSPUpdateToDoViewController in the Identity Inspector. Create a manual segue from the TSPViewController class to the TSPUpdateToDoViewController class. In the Attributes Inspector, set the segue's style to push and its identifier to updateToDoViewController.

Add a UITextField object to the view of the TSPUpdateToDoViewController object and configure it just like we did with the text field of the TSPAddToDoViewController class. Don't forget to connect the view controller's outlet with the text field.

As in the TSPAddToDoViewController class, add two bar button items to the view controller's navigation bar, set their identities to Cancel and Save respectively, and connect each bar button item to the corresponding action in the Connections Inspector.

Step 3: Passing a Reference

We also need to make a few changes to the TSPViewController class. Add an import statement for the TSPUpdateToDoViewController class at the top and declare a property named selection of type NSIndexPath to the private class extension in TSPViewController.m.

#import "TSPViewController.h"

#import <CoreData/CoreData.h>

#import "TSPToDoCell.h"
#import "TSPAddToDoViewController.h"
#import "TSPUpdateToDoViewController.h"

@interface TSPViewController () <NSFetchedResultsControllerDelegate>

@property (strong, nonatomic) NSFetchedResultsController *fetchedResultsController;

@property (strong, nonatomic) NSIndexPath *selection;

@end

Next, implement the tableView:didSelectRowAtIndexPath: method of the UITableViewDelegate protocol. In this method, we temporarily store the user's selection in the selection property.

#pragma mark -
#pragma mark Table View Delegate Methods
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
    // Store Selection
    [self setSelection:indexPath];
}

In the class's prepareForSegue:sender:, we fetch the record that corresponds with the user's selection and pass it to the TSPUpdateToDoViewController instance. To prevent any unexpected behavior, we only perform this step if selection isn't nil and reset the selection property after fetching the record from the fetched results controller.

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([segue.identifier isEqualToString:@"addToDoViewController"]) {
        // Obtain Reference to View Controller
        UINavigationController *nc = (UINavigationController *)[segue destinationViewController];
        TSPAddToDoViewController *vc = (TSPAddToDoViewController *)[nc topViewController];
        // Configure View Controller
        [vc setManagedObjectContext:self.managedObjectContext];
    } else if ([segue.identifier isEqualToString:@"updateToDoViewController"]) {
        // Obtain Reference to View Controller
        TSPUpdateToDoViewController *vc = (TSPUpdateToDoViewController *)[segue destinationViewController];
        // Configure View Controller
        [vc setManagedObjectContext:self.managedObjectContext];
        if (self.selection) {
            // Fetch Record
            NSManagedObject *record = [self.fetchedResultsController objectAtIndexPath:self.selection];
            if (record) {
                [vc setRecord:record];
            }
            // Reset Selection
            [self setSelection:nil];
        }
    }
}

Step 4: Populating the Text Field

In the viewDidLoad method of the TSPUpdateToDoViewController class, populate the text field with the name of the record as shown below.

#pragma mark -
#pragma mark View Life Cycle
- (void)viewDidLoad {
    [super viewDidLoad];
    if (self.record) {
        // Update Text Field
        [self.textField setText:[self.record valueForKey:@"name"]];
    }
}

Step 5: Updating the Record

In the cancel: action, we pop the update view controller from the navigation controller's navigation stack.

- (IBAction)cancel:(id)sender {
    // Pop View Controller
    [self.navigationController popViewControllerAnimated:YES];
}

In the save: action, we first check if the text field is empty and show an alert view if it is. If the text field contains a valid value, we update the record's name attribute and pop the view controller from the navigation controller's navigation stack.

- (IBAction)save:(id)sender {
    // Helpers
    NSString *name = self.textField.text;
    if (name && name.length) {
        // Populate Record
        [self.record setValue:name forKey:@"name"];
        // Save Record
        NSError *error = nil;
        if ([self.managedObjectContext save:&error]) {
            // Pop View Controller
            [self.navigationController popViewControllerAnimated:YES];
        } else {
            if (error) {
                NSLog(@"Unable to save record.");
                NSLog(@"%@, %@", error, error.localizedDescription);
            }
            // Show Alert View
            [[[UIAlertView alloc] initWithTitle:@"Warning" message:@"Your to-do could not be saved." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show];
        }
    } else {
        // Show Alert View
        [[[UIAlertView alloc] initWithTitle:@"Warning" message:@"Your to-do needs a name." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show];
    }
}

This is all it takes to update a record using Core Data. Run the application once more and see if everything is working. The fetched results controller automatically detects the change and notifies its delegate, the TSPViewController instance. The TSPViewController object, on its turn, updates the table view to reflect the change. It's that easy.

2. Updating a Record's State

Step 1: Updating TSPToDoCell

When a user taps the button on the right of a TSPToDoCell, the item's state needs to change. To accomplish this, we first need to update the TSPToDoCell class. Open TSPToDoCell.m and add a typedef for a block named TSPToDoCellDidTapButtonBlock. Next, declare a property of type TSPToDoCellDidTapButtonBlock and make sure the property is copied on assignment.

#import <UIKit/UIKit.h>

typedef void (^TSPToDoCellDidTapButtonBlock)();

@interface TSPToDoCell : UITableViewCell

@property (weak, nonatomic) IBOutlet UILabel *nameLabel;
@property (weak, nonatomic) IBOutlet UIButton *doneButton;

@property (copy, nonatomic) TSPToDoCellDidTapButtonBlock didTapButtonBlock;

@end

Head to the class's implementation file, TSPToDoCell.m, and invoke setupView, a helper method, in awakeFromNib.

#pragma mark -
#pragma mark Initialization
- (void)awakeFromNib {
    [super awakeFromNib];
    // Setup View
    [self setupView];
}

In setupView, we configure the doneButton object by setting images for each state of the button and adding the table view cell as a target. When the user taps the button, the table view cell is sent a message of didTapButton: in which we invoke the didTapButtonBlock block. You'll see in a moment how convenient this pattern is. The images are included in the source files of this tutorial, which you can find on GitHub.

#pragma mark -
#pragma mark View Methods
- (void)setupView {
    UIImage *imageNormal = [UIImage imageNamed:@"button-done-normal"];
    UIImage *imageSelected = [UIImage imageNamed:@"button-done-selected"];
    [self.doneButton setImage:imageNormal forState:UIControlStateNormal];
    [self.doneButton setImage:imageNormal forState:UIControlStateDisabled];
    [self.doneButton setImage:imageSelected forState:UIControlStateSelected];
    [self.doneButton setImage:imageSelected forState:UIControlStateHighlighted];
    [self.doneButton addTarget:self action:@selector(didTapButton:) forControlEvents:UIControlEventTouchUpInside];
}
#pragma mark -
#pragma mark Actions
- (void)didTapButton:(UIButton *)button {
    if (self.didTapButtonBlock) {
        self.didTapButtonBlock();
    }
}

Step 2: Updating TSPViewController

Thanks to the NSFetchedResultsController class and the foundation we've laid, we only need to update the configureCell:atIndexPath: method in the TSPViewController class.

- (void)configureCell:(TSPToDoCell *)cell atIndexPath:(NSIndexPath *)indexPath {
    // Fetch Record
    NSManagedObject *record = [self.fetchedResultsController objectAtIndexPath:indexPath];
    // Update Cell
    [cell.nameLabel setText:[record valueForKey:@"name"]];
    [cell.doneButton setSelected:[[record valueForKey:@"done"] boolValue]];
    [cell setDidTapButtonBlock:^{
        BOOL isDone = [[record valueForKey:@"done"] boolValue];
        // Update Record
        [record setValue:@(!isDone) forKey:@"done"];
    }];
}

Step 3: Saving Changes

You may be wondering why we aren't saving the managed object context. Won't we lose the changes we've made if we don't commit the changes to the persistent store? Yes and no.

It is true that we need to write the changes of the managed object context to the backing store at some point. If we don't, the user will lose some of its data. However, there is no need to save the changes of a managed object context every time we make a change.

A better approach is to save the managed object context the moment the application moves to the background. We can do this in the applicationDidEnterBackground: method of the UIApplicationDelegate protocol. Open TSPAppDelegate.m and implement applicationDidEnterBackground: as shown below.

- (void)applicationDidEnterBackground:(UIApplication *)application {
    NSError *error = nil;
    if (![self.managedObjectContext save:&error]) {
        if (error) {
            NSLog(@"Unable to save changes.");
            NSLog(@"%@, %@", error, error.localizedDescription);
        }
    }
}

However, this doesn't work if the application is force quit by the user. It's therefore a good idea to also save the managed object context when the application is terminated. The applicationWillTerminate: method is another method of the UIApplicationDelegate protocol that notifies the application't delegate when the application is about to be .

- (void)applicationWillTerminate:(UIApplication *)application {
    NSError *error = nil;
    if (![self.managedObjectContext save:&error]) {
        if (error) {
            NSLog(@"Unable to save changes.");
            NSLog(@"%@, %@", error, error.localizedDescription);
        }
    }
}

Note that we have duplicate code in applicationDidEnterBackground: and applicationWillTerminate:. It's therefore a good idea to create a helper method to save the managed object context and call this helper method in both delegate methods.

#pragma mark -
#pragma mark Helper Methods
- (void)saveManagedObjectContext {
    NSError *error = nil;
    if (![self.managedObjectContext save:&error]) {
        if (error) {
            NSLog(@"Unable to save changes.");
            NSLog(@"%@, %@", error, error.localizedDescription);
        }
    }
}

3. Deleting Records

You'll be surprised by how easy it is to delete records using the NSFetchedResultsController class. Start by implementing the tableView:canEditRowAtIndexPath: method of the UITableViewDataSource protocol.

- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
    return YES;
}

The second method of the UITableViewDataSource protocol that we need to implement is tableView:commitEditingStyle:forRowAtIndexPath:. In this method we fetch the managed object the user has selected for deletion and pass it to the deleteObject: method of the managed object context of the fetched results controller.

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        NSManagedObject *record = [self.fetchedResultsController objectAtIndexPath:indexPath];
        if (record) {
            [self.fetchedResultsController.managedObjectContext deleteObject:record];
        }
    }
}

Because we've already implemented the NSFetchedResultsControllerDelegate protocol, the user interface is automatically updated, animations included.

Conclusion

I hope you agree that the NSFetchedResultsController class is a very convenient member of the Core Data framework. If you understand the basics of the Core Data framework, then it's not difficult to get up to speed with this class. I encourage you to further explore the its API to find out what else it can do for you.

2014-07-30T16:45:38.000Z2014-07-30T16:45:38.000ZBart Jacobs

Core Data from Scratch: More NSFetchedResultsController

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-21777

In this tutorial, we continue our exploration of the NSFetchedResultsController class by adding the ability to update and delete to-do items. You'll notice that updating and deleting to-do items is surprisingly easy thanks to the groundwork we laid in the previous tutorial.

1. Updating a Record's Name

Step 1: Create View Controller

Start by creating a new UIViewController subclass named TSPUpdateToDoViewController. In TSPUpdateToDoViewController.h, declare an outlet, textField of type UITextField, and two properties, managedObjectContext of type NSManagedObjectContext and record of type NSManagedObject. Add an import statement for the Core Data framework at the top.

#import <UIKit/UIKit.h>

#import <CoreData/CoreData.h>

@interface TSPUpdateToDoViewController : UIViewController

@property (weak, nonatomic) IBOutlet UITextField *textField;

@property (strong, nonatomic) NSManagedObjectContext *managedObjectContext;

@property (strong, nonatomic) NSManagedObject *record;

@end

In the view controller's implementation file, TSPUpdateToDoViewController.m, create two actions, cancel: and save:. Their implementations can remain empty for the time being.

#import "TSPUpdateToDoViewController.h"

@implementation TSPUpdateToDoViewController

#pragma mark -
#pragma mark Actions
- (IBAction)cancel:(id)sender {
    
}

- (IBAction)save:(id)sender {
    
}

@end

Step 2: Update Storyboard

Open the main storyboard, Main.storyboard, add a new view controller object, and set its class to TSPUpdateToDoViewController in the Identity Inspector. Create a manual segue from the TSPViewController class to the TSPUpdateToDoViewController class. In the Attributes Inspector, set the segue's style to push and its identifier to updateToDoViewController.

Add a UITextField object to the view of the TSPUpdateToDoViewController object and configure it just like we did with the text field of the TSPAddToDoViewController class. Don't forget to connect the view controller's outlet with the text field.

As in the TSPAddToDoViewController class, add two bar button items to the view controller's navigation bar, set their identities to Cancel and Save respectively, and connect each bar button item to the corresponding action in the Connections Inspector.

Step 3: Passing a Reference

We also need to make a few changes to the TSPViewController class. Add an import statement for the TSPUpdateToDoViewController class at the top and declare a property named selection of type NSIndexPath to the private class extension in TSPViewController.m.

#import "TSPViewController.h"

#import <CoreData/CoreData.h>

#import "TSPToDoCell.h"
#import "TSPAddToDoViewController.h"
#import "TSPUpdateToDoViewController.h"

@interface TSPViewController () <NSFetchedResultsControllerDelegate>

@property (strong, nonatomic) NSFetchedResultsController *fetchedResultsController;

@property (strong, nonatomic) NSIndexPath *selection;

@end

Next, implement the tableView:didSelectRowAtIndexPath: method of the UITableViewDelegate protocol. In this method, we temporarily store the user's selection in the selection property.

#pragma mark -
#pragma mark Table View Delegate Methods
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
    // Store Selection
    [self setSelection:indexPath];
}

In the class's prepareForSegue:sender:, we fetch the record that corresponds with the user's selection and pass it to the TSPUpdateToDoViewController instance. To prevent any unexpected behavior, we only perform this step if selection isn't nil and reset the selection property after fetching the record from the fetched results controller.

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([segue.identifier isEqualToString:@"addToDoViewController"]) {
        // Obtain Reference to View Controller
        UINavigationController *nc = (UINavigationController *)[segue destinationViewController];
        TSPAddToDoViewController *vc = (TSPAddToDoViewController *)[nc topViewController];
        // Configure View Controller
        [vc setManagedObjectContext:self.managedObjectContext];
    } else if ([segue.identifier isEqualToString:@"updateToDoViewController"]) {
        // Obtain Reference to View Controller
        TSPUpdateToDoViewController *vc = (TSPUpdateToDoViewController *)[segue destinationViewController];
        // Configure View Controller
        [vc setManagedObjectContext:self.managedObjectContext];
        if (self.selection) {
            // Fetch Record
            NSManagedObject *record = [self.fetchedResultsController objectAtIndexPath:self.selection];
            if (record) {
                [vc setRecord:record];
            }
            // Reset Selection
            [self setSelection:nil];
        }
    }
}

Step 4: Populating the Text Field

In the viewDidLoad method of the TSPUpdateToDoViewController class, populate the text field with the name of the record as shown below.

#pragma mark -
#pragma mark View Life Cycle
- (void)viewDidLoad {
    [super viewDidLoad];
    if (self.record) {
        // Update Text Field
        [self.textField setText:[self.record valueForKey:@"name"]];
    }
}

Step 5: Updating the Record

In the cancel: action, we pop the update view controller from the navigation controller's navigation stack.

- (IBAction)cancel:(id)sender {
    // Pop View Controller
    [self.navigationController popViewControllerAnimated:YES];
}

In the save: action, we first check if the text field is empty and show an alert view if it is. If the text field contains a valid value, we update the record's name attribute and pop the view controller from the navigation controller's navigation stack.

- (IBAction)save:(id)sender {
    // Helpers
    NSString *name = self.textField.text;
    if (name && name.length) {
        // Populate Record
        [self.record setValue:name forKey:@"name"];
        // Save Record
        NSError *error = nil;
        if ([self.managedObjectContext save:&error]) {
            // Pop View Controller
            [self.navigationController popViewControllerAnimated:YES];
        } else {
            if (error) {
                NSLog(@"Unable to save record.");
                NSLog(@"%@, %@", error, error.localizedDescription);
            }
            // Show Alert View
            [[[UIAlertView alloc] initWithTitle:@"Warning" message:@"Your to-do could not be saved." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show];
        }
    } else {
        // Show Alert View
        [[[UIAlertView alloc] initWithTitle:@"Warning" message:@"Your to-do needs a name." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show];
    }
}

This is all it takes to update a record using Core Data. Run the application once more and see if everything is working. The fetched results controller automatically detects the change and notifies its delegate, the TSPViewController instance. The TSPViewController object, on its turn, updates the table view to reflect the change. It's that easy.

2. Updating a Record's State

Step 1: Updating TSPToDoCell

When a user taps the button on the right of a TSPToDoCell, the item's state needs to change. To accomplish this, we first need to update the TSPToDoCell class. Open TSPToDoCell.m and add a typedef for a block named TSPToDoCellDidTapButtonBlock. Next, declare a property of type TSPToDoCellDidTapButtonBlock and make sure the property is copied on assignment.

#import <UIKit/UIKit.h>

typedef void (^TSPToDoCellDidTapButtonBlock)();

@interface TSPToDoCell : UITableViewCell

@property (weak, nonatomic) IBOutlet UILabel *nameLabel;
@property (weak, nonatomic) IBOutlet UIButton *doneButton;

@property (copy, nonatomic) TSPToDoCellDidTapButtonBlock didTapButtonBlock;

@end

Head to the class's implementation file, TSPToDoCell.m, and invoke setupView, a helper method, in awakeFromNib.

#pragma mark -
#pragma mark Initialization
- (void)awakeFromNib {
    [super awakeFromNib];
    // Setup View
    [self setupView];
}

In setupView, we configure the doneButton object by setting images for each state of the button and adding the table view cell as a target. When the user taps the button, the table view cell is sent a message of didTapButton: in which we invoke the didTapButtonBlock block. You'll see in a moment how convenient this pattern is. The images are included in the source files of this tutorial, which you can find on GitHub.

#pragma mark -
#pragma mark View Methods
- (void)setupView {
    UIImage *imageNormal = [UIImage imageNamed:@"button-done-normal"];
    UIImage *imageSelected = [UIImage imageNamed:@"button-done-selected"];
    [self.doneButton setImage:imageNormal forState:UIControlStateNormal];
    [self.doneButton setImage:imageNormal forState:UIControlStateDisabled];
    [self.doneButton setImage:imageSelected forState:UIControlStateSelected];
    [self.doneButton setImage:imageSelected forState:UIControlStateHighlighted];
    [self.doneButton addTarget:self action:@selector(didTapButton:) forControlEvents:UIControlEventTouchUpInside];
}
#pragma mark -
#pragma mark Actions
- (void)didTapButton:(UIButton *)button {
    if (self.didTapButtonBlock) {
        self.didTapButtonBlock();
    }
}

Step 2: Updating TSPViewController

Thanks to the NSFetchedResultsController class and the foundation we've laid, we only need to update the configureCell:atIndexPath: method in the TSPViewController class.

- (void)configureCell:(TSPToDoCell *)cell atIndexPath:(NSIndexPath *)indexPath {
    // Fetch Record
    NSManagedObject *record = [self.fetchedResultsController objectAtIndexPath:indexPath];
    // Update Cell
    [cell.nameLabel setText:[record valueForKey:@"name"]];
    [cell.doneButton setSelected:[[record valueForKey:@"done"] boolValue]];
    [cell setDidTapButtonBlock:^{
        BOOL isDone = [[record valueForKey:@"done"] boolValue];
        // Update Record
        [record setValue:@(!isDone) forKey:@"done"];
    }];
}

Step 3: Saving Changes

You may be wondering why we aren't saving the managed object context. Won't we lose the changes we've made if we don't commit the changes to the persistent store? Yes and no.

It is true that we need to write the changes of the managed object context to the backing store at some point. If we don't, the user will lose some of its data. However, there is no need to save the changes of a managed object context every time we make a change.

A better approach is to save the managed object context the moment the application moves to the background. We can do this in the applicationDidEnterBackground: method of the UIApplicationDelegate protocol. Open TSPAppDelegate.m and implement applicationDidEnterBackground: as shown below.

- (void)applicationDidEnterBackground:(UIApplication *)application {
    NSError *error = nil;
    if (![self.managedObjectContext save:&error]) {
        if (error) {
            NSLog(@"Unable to save changes.");
            NSLog(@"%@, %@", error, error.localizedDescription);
        }
    }
}

However, this doesn't work if the application is force quit by the user. It's therefore a good idea to also save the managed object context when the application is terminated. The applicationWillTerminate: method is another method of the UIApplicationDelegate protocol that notifies the application't delegate when the application is about to be .

- (void)applicationWillTerminate:(UIApplication *)application {
    NSError *error = nil;
    if (![self.managedObjectContext save:&error]) {
        if (error) {
            NSLog(@"Unable to save changes.");
            NSLog(@"%@, %@", error, error.localizedDescription);
        }
    }
}

Note that we have duplicate code in applicationDidEnterBackground: and applicationWillTerminate:. It's therefore a good idea to create a helper method to save the managed object context and call this helper method in both delegate methods.

#pragma mark -
#pragma mark Helper Methods
- (void)saveManagedObjectContext {
    NSError *error = nil;
    if (![self.managedObjectContext save:&error]) {
        if (error) {
            NSLog(@"Unable to save changes.");
            NSLog(@"%@, %@", error, error.localizedDescription);
        }
    }
}

3. Deleting Records

You'll be surprised by how easy it is to delete records using the NSFetchedResultsController class. Start by implementing the tableView:canEditRowAtIndexPath: method of the UITableViewDataSource protocol.

- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
    return YES;
}

The second method of the UITableViewDataSource protocol that we need to implement is tableView:commitEditingStyle:forRowAtIndexPath:. In this method we fetch the managed object the user has selected for deletion and pass it to the deleteObject: method of the managed object context of the fetched results controller.

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        NSManagedObject *record = [self.fetchedResultsController objectAtIndexPath:indexPath];
        if (record) {
            [self.fetchedResultsController.managedObjectContext deleteObject:record];
        }
    }
}

Because we've already implemented the NSFetchedResultsControllerDelegate protocol, the user interface is automatically updated, animations included.

Conclusion

I hope you agree that the NSFetchedResultsController class is a very convenient member of the Core Data framework. If you understand the basics of the Core Data framework, then it's not difficult to get up to speed with this class. I encourage you to further explore its API to find out what else it can do for you.

2014-07-30T16:45:38.000Z2014-07-30T16:45:38.000ZBart Jacobs

10 Alternative Android App Stores

$
0
0

You've just written a great Android app and you're ready to make some money from
it. The most common route is probably to pay $25 to get it listed on Google Play. However, there are many alternatives to Google Play, each with their own audience that can drive more downloads.

Some of these app stores are catered to a smaller audience while others are more localized. Most of them don't charge you for listing your app on their store. It can therefore pay off to publish your app in several app stores.

1. Amazon Appstore

Meet one of Google's greatest competitors, Amazon. Amazon offers the Kindle Fire and, more recently, the Fire Phone, Android powered devices that run a custom flavor of Android, Fire OS. Despite the custom operating system, a large chunk of Android apps will run fine on Fire OS. If yours doesn't, then it will probably only take a few tweaks to get it up and running.

You can also publish HTML5 and web apps on the Amazon Appstore. It currently contains more than 240,000 apps and they have a free app of the day feature. Take a look at Amazon's developer portal to get started.

2. SlideME

One of the oldest Android app marketplaces, older than Google Play, SlideME is installed on more than half of Android devices without Google Play. SlideMe takes a fee of 20% and offers a wide range of payment options, including PayPal, which Google Play doesn't offer. In some cases, putting your Android app for sale on SlideME can result in more downloads than you'd get on Google Play, so it's definitely worth a try.

3. 1Mobile Market

1Mobile Market only accepts free apps, but that doesn't mean you should discard it as an alternative to Google Play. Uploading apps is free, but there is an approval process your app has to pass through. This shouldn't be an issue as long as your app doesn't contain malware.

1Mobile Market claims to have more than 100 million installs with more than 800,000 apps listed. Users are offered recommendations based on their preferences, which is great to discover new apps.

4. Samsung Galaxy Apps

Samsung is the biggest manufacturer of Android phones and it also has it's own app store, Samsung Galaxy Apps. It is installed on all Samsung Galaxy series devices and therefore has a large user base. The only downside is the fairly small number of apps available on the store, about 13,000 in 2011.

5. Mobile9

Mobile9 has more than 40 million active users, so it's another option worth considering. Users can share and comment on the apps they have installer, similar to a social network for apps. Another upside is that publishing apps is free. With more than 200 million downloads per month and only 30,000 developers, it's definitely worth a try.

6. Opera Mobile Store

Publishing apps is free on the Opera Mobile Store, but developers only get 70% of the revenue from paid apps. Opera has an agreement with Yandex, Russia's biggest search engine, which allows Opera's apps to be shown in the Yandex App Store and vice versa. There are around 200,000 apps and the store receives more than 100 million visitors per month with 2 million apps downloaded per day.

7. Mobango

Publishing apps on Mobango is also free. With millions of users and top apps generating thousands of downloads every day, Mobango is a good choice for publishing your app. There are currently 100,000 apps in the Mobango app store.

8. Soc.io Mall

Soc.io Mall's tagline is "The Android Mall that Loves Developers". It offers high revenue share, 80/20, and listing your app is free. It currently has less than 10,000 apps, but the marketplace isn't limited to apps, users can also buy games, ebooks, and the offering will soon also include music, videos, and audiobooks. The number of active users isn't as high as other app stores, but competition is also much lower.

9. F-droid

F-droid contains only free and open source apps. You can download apps from the official website or through the official F-droid app. The F-droid app automatically updates every app you've installed through F-droid. The platform is maintained by volunteers and relies on donations to pay the bills. Every app on F-droid must have an Apache or GNU open source license. Apps that include paid add-ons or advertisements are allowed, but are not displayed by default.

10. GetJar

GetJar has more than 30 million users and includes a recommendation service, similar to that of 1Mobile. It claims to have 3 million downloads a day, with 70,000 apps in its app store. It encourages developers to use a freemium model, displaying ads and using in-app currency instead of charging for the app.They also offer the largest virtual currency on Google Play, GetJar Gold, which is available to more than 100 million users.

Conclusion

There are many alternative app stores on which you can sell you Android application, with each store having its pros and cons. Although neither of these can replace the Google Play, they can certainly drive more downloads and expose your apps to more potential customers. And since you can list your apps for free in these stores, it doesn't hurt to spend a bit of time to investigate these alternatives.

2014-08-01T16:34:23.662Z2014-08-01T16:34:23.662ZRyan Chang

10 Alternative Android App Stores

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-20999

You've just written a great Android app and you're ready to make some money from
it. The most common route is probably to pay $25 to get it listed on Google Play. However, there are many alternatives to Google Play, each with their own audience that can drive more downloads.

Some of these app stores are catered to a smaller audience while others are more localized. Most of them don't charge you for listing your app on their store. It can therefore pay off to publish your app in several app stores.

1. Amazon Appstore

Meet one of Google's greatest competitors, Amazon. Amazon offers the Kindle Fire and, more recently, the Fire Phone, Android powered devices that run a custom flavor of Android, Fire OS. Despite the custom operating system, a large chunk of Android apps will run fine on Fire OS. If yours doesn't, then it will probably only take a few tweaks to get it up and running.

You can also publish HTML5 and web apps on the Amazon Appstore. It currently contains more than 240,000 apps and they have a free app of the day feature. Take a look at Amazon's developer portal to get started.

2. SlideME

One of the oldest Android app marketplaces, older than Google Play, SlideME is installed on more than half of Android devices without Google Play. SlideMe takes a fee of 20% and offers a wide range of payment options, including PayPal, which Google Play doesn't offer. In some cases, putting your Android app for sale on SlideME can result in more downloads than you'd get on Google Play, so it's definitely worth a try.

3. 1Mobile Market

1Mobile Market only accepts free apps, but that doesn't mean you should discard it as an alternative to Google Play. Uploading apps is free, but there is an approval process your app has to pass through. This shouldn't be an issue as long as your app doesn't contain malware.

1Mobile Market claims to have more than 100 million installs with more than 800,000 apps listed. Users are offered recommendations based on their preferences, which is great to discover new apps.

4. Samsung Galaxy Apps

Samsung is the biggest manufacturer of Android phones and it also has it's own app store, Samsung Galaxy Apps. It is installed on all Samsung Galaxy series devices and therefore has a large user base. The only downside is the fairly small number of apps available on the store, about 13,000 in 2011.

5. Mobile9

Mobile9 has more than 40 million active users, so it's another option worth considering. Users can share and comment on the apps they have installer, similar to a social network for apps. Another upside is that publishing apps is free. With more than 200 million downloads per month and only 30,000 developers, it's definitely worth a try.

6. Opera Mobile Store

Publishing apps is free on the Opera Mobile Store, but developers only get 70% of the revenue from paid apps. Opera has an agreement with Yandex, Russia's biggest search engine, which allows Opera's apps to be shown in the Yandex App Store and vice versa. There are around 200,000 apps and the store receives more than 100 million visitors per month with 2 million apps downloaded per day.

7. Mobango

Publishing apps on Mobango is also free. With millions of users and top apps generating thousands of downloads every day, Mobango is a good choice for publishing your app. There are currently 100,000 apps in the Mobango app store.

8. Soc.io Mall

Soc.io Mall's tagline is "The Android Mall that Loves Developers". It offers high revenue share, 80/20, and listing your app is free. It currently has less than 10,000 apps, but the marketplace isn't limited to apps, users can also buy games, ebooks, and the offering will soon also include music, videos, and audiobooks. The number of active users isn't as high as other app stores, but competition is also much lower.

9. F-droid

F-droid contains only free and open source apps. You can download apps from the official website or through the official F-droid app. The F-droid app automatically updates every app you've installed through F-droid. The platform is maintained by volunteers and relies on donations to pay the bills. Every app on F-droid must have an Apache or GNU open source license. Apps that include paid add-ons or advertisements are allowed, but are not displayed by default.

10. GetJar

GetJar has more than 30 million users and includes a recommendation service, similar to that of 1Mobile. It claims to have 3 million downloads a day, with 70,000 apps in its app store. It encourages developers to use a freemium model, displaying ads and using in-app currency instead of charging for the app.They also offer the largest virtual currency on Google Play, GetJar Gold, which is available to more than 100 million users.

Conclusion

There are many alternative app stores on which you can sell you Android application, with each store having its pros and cons. Although neither of these can replace the Google Play, they can certainly drive more downloads and expose your apps to more potential customers. And since you can list your apps for free in these stores, it doesn't hurt to spend a bit of time to investigate these alternatives.

2014-08-01T16:34:23.662Z2014-08-01T16:34:23.662ZRyan Chang

Develop a Monkey Ball Inspired Game with Unity

$
0
0
Final product image
What You'll Be Creating

Introduction

In this tutorial, you'll learn how to create a mobile 3D game using C# and Unity. The objective of the game is to use the accelerometer to move the ball and reach the portal.

You will learn about the following aspects of Unity game development in this tutorial:

  • 3D Primitives
  • accelerometer controls
  • camera movement
  • physics
  • GUI Textures

1. Create a New Unity Project

Open Unity and select New Project from the File menu to open the new project dialog. Tell Unity where you want to save the project and set the Set up defaults for: menu to 3D.


2. Build Settings

In the next step, you're presented with Unity's user interface. Set the project up for mobile development by choosing Build Settings from the File menu and selecting your platform of choice.


3. Devices

The first thing we need to do after selecting the target platform is choosing the size of the artwork we'll be using in the game. This will help us select a proper size for the 3D textures and 2D GUI without making the artwork blurry or use textures that are too large for the target device. For example, the artwork needs to have a higher resolution if you're targeting an iPad with a retina display than a Lumia 520.

iOS

  • iPad without Retina: 1024px x 768px
  • iPad with Retina: 2048px x 1536px
  • 3.5" iPhone/iPod Touch without Retina: 320px x 480px
  • 3.5" iPhone/iPod with Retina: 960px x 640px
  • 4" iPhone/iPod Touch: 1136px x 640px

Android

Because Android is an open platform, there's a wide range of devices, screen resolutions, and pixel densities. A few of the more common ones are listed below.

  • Asus Nexus 7 Tablet: 800px x 1280px, 216 ppi
  • Motorola Droid X: 854px x 480px, 228 ppi
  • Samsung Galaxy SIII: 720px x 1280px, 306 ppi

Windows Phone & BlackBerry

  • Blackberry Z10: 720px x 1280px, 355 ppi
  • Nokia Lumia 520: 400px x 800px, 233 ppi
  • Nokia Lumia 1520: 1080px x 1920px, 367 ppi

Note that the code we'll write in this tutorial can be used to target any of the platforms.


4. Export Graphics

Depending on the devices you're targeting, you may need to convert the artwork to the recommended size and pixel density. You can do this in your favorite image editor. I've used the Adjust Size... function under the Tools menu in OS X's Preview application.


5. Unity User Interface

You can modify the resolution that's being displayed in the Game panel.


6. Game Interface

The interface of our game will be straightforward. The above screenshot gives you an idea of the artwork we'll be using and how the final game interface will end up looking. You can find the artwork and additional resources in the tutorial's source files on GitHub.


7. Programming Language

You can use one of three programming languages when using Unity, C#, UnityScript, a variation of JavaScript, and Boo. Each programming language has its pros and cons, and it's up to you to decide which one you prefer. My personal preference goes to the C# programming language so that's the language I'll be using in this tutorial.

If you decide to use another programming language, then make sure to take a look at Unity's Script Reference for examples.


8. Sound Effects

I'll use a number of sounds to improve the audial experience of the game. The sound effects used in this tutorial were obtained from playonloop.com and Freesound.


9. 3D Models

To create our game we first need to get our 3D models. I recommend 3docean for high quality models, textures, and more, but if you're testing or learning then a few free models are good as well. The models in this tutorial were downloaded from SketchUp 3D Warehouse where you can find a good variety of models of all kinds.

Now, as Unity doesn't recognize the SketchUp file format we need to convert it to something Unity can import. We first need to download the free version of SketchUp, which is called SketchUp Make

Open your 3D model in SketchUp Make, select Export > 3D Model from the File menu, and choose Collada (*.dae).

Choose a name and location, and click the save button. This will create a file and a folder for the 3D model. The file holds the data for the 3D object while the folder contains the model's textures. You can then import the model into Unity as explained in the next step.


10. Import Assets

Before we start coding, we need to add our assets to the Unity project. You can do this one of several ways:

  • select Import New Asset from the Assets menu
  • add the items to the assets folder in your project
  • drag and drop the assets in the project window

After completing this step, you should see the assets in your project's Assets folder in the Project panel.


11. Create Scene

We're ready to create the scene of our game by dragging objects to the Hierarchy or Scene panel. We'll also use Unity native 3D primitive objects to create the level as shown in the next steps.

12. Setup Camera

Let's first position our Main Camera a little bit higher to achieve the view we want. Select it from the Hierarchy panel and adjust the Transform values in the Inspector to match the  ones shown below.

Don't worry if you don't see any changes. We haven't created anything for the camera to see yet. Next, use the Inspector to set the Background color to RGB: 0, 139, 252.

13. Background

Our platform level will be floating above a background, which will be a representation of a sea. It will be created using Unity primitives, a simple Plane with a texture applied to it.

While Unity can work with 3D objects of any type created by other programs, it is sometimes easier and/or more convenient to use primitives for prototypes.

To create the sea, for example, select Create Other > Plane from the GameObject menu and adjust the Transform values in the Inspector to match the ones shown below.

You should a square in the Scene panel. We'll use it to detect when the player falls from the platform, ending the game.

It's worth mentioning that these primitive objects already have a Mesh Collider attached to them, which means that they will automatically detect collisions or trigger events when they come in contact with a RigidBody.

14. Texture Material

To apply a texture to the sea plane, we need to create a Material. A Material is used to define how a GameObject looks and it is essential to add a texture to a GameObject.

Select Create > Material from the Assets menu to create one, find it in the Assets panel, and use the Inspector to select the texture you want to use as your sea. These are the settings I've used:

You'll notice a message in the material section stating that it's recommended to use Mobile/Diffuse as a shader, because the default white color doesn't do anything. Changing it to Mobile/Diffuse will also help with performance.


15. Adding Light

You may have noticed that the sea is a bit darker than it should be. To fix this, we need to add a Light to our scene. Select Create Other from the GameObject menu and select Directional Light. This will create an object that produces a beam of light. Change its Transform values as shown in the following screenshot to make it illuminate the sea.

This looks much better.

16. Creating Platforms

The platforms are parts of our level and are used by the player to move the ball to the portal on the other side of the sea.

Create a Plane as you did for the sea and adjust the Transform values in the Inspector as shown below. This will create and put the first platform in place.

We can now use Unity's Move and Rotation tools to create the other platforms. They're all of the same size so we can use them vertically or horizontally by duplicating them using Command+D on OS X and Control+D on Windows.


17. Platform Texture

Create a new Material like we did in Step 14 and apply the texture to it. Mine looks like this:

Adjust the x and y tiling until you're happy with the result.


18. Border Cylinders

We need to create a border to prevent our player from falling off too easily. To do this, we'll use a new type of primitive, a Cylinder.

Select Create Other > Cylinder from the GameObject menu and adjust the Transform values in the Inspector as shown below.

This will add a small border to the edge of the first platform. Create a new Material and change its color in the Inspector to RGB: 255, 69, 0.

The result should look like this:

Use Command+D (Control+D on Windows) to duplicate the border and the Scale tool to change its size. Position the duplicates at the platforms' edges using Unity's tools.


19. Portal

The portal is the goal line of the game. The player will use the accelerometer to control the ball and take it to this point while picking up items and avoiding falling off the platform. The portal is a 3D model, which we imported in Step 10.

Drag and drop it on the Scene or Hierarchy panel and change its Transform values to the following:

This will position it at the end of the platforms.


20. Portal Collider

Because imported 3D models don't have a collider by default, we need to attach one. Since we only need to test if the ball hits the blue area of the portal, we'll attach the collider to it.

Take a look at the portal model in the Hierarchy view and you'll notice a small triangle to the left of its name. Click the triangle to expand the portal's group and select the first item. I've added the -Collider suffix for clarification.

Click the Add Component button in the Inspector and choose Physics > Mesh Collider. This will add a collider using the shape of the model's selected area.


21. Portal Audio Source

To provide feedback to the player, we'll play a sound effect when the ball touches the portal's collider. Because we'll be triggering the event using the previously created collider, we need to add the audio source to that same object.

Select it from the Hierarchy panel, click the Add Component button in the Inspector panel, and select Audio Source from the Audio section.

Uncheck Play on Awake and click the little dot on the right, below the gear icon, to select the sound you want to play.

22. Adding Islands

The islands are nothing more than decorative elements to make the level less empty. I've used an imported 3D model and a Cylinder to make them. I won't go into detail creating the islands since they're not essential to the game. With what you've learned so far, you should be able to create them yourself.


23. Adding Bananas

As in Monkey Ball, the player will be able to collect bananas during the game. Start by dragging the model from the Assets panel to the Scene. Don't worry about its location just yet, because we'll convert it to a Prefab later since we'll be reusing it multiple times.

24. Banana Mesh Collider

As I mentioned earlier, imported models don't have a collider by default, so we need to attach one to the banana. Click the Add Component button in the Inspector and choose Physics > Mesh Collider. This will add a collider using the model's shape. Make sure to check the Trigger checkbox, because we want to detect collisions, but we don't want the ball to react with the banana.


24. Adding the Player

It's time to create our game character, which will be a simple Sphere primitive. Select Create Other > Sphere from the GameObject menu to create the primitive and modify the Transform values in the Inspector as shown below.

This will create the sphere and position it at the start of our level.

To make the sphere semi-transparent, we need to change its Shader options. Open the Inspector and change the shader to Transparent/Diffuse.


25. Player RigidBody

To detect a collision with the player, we need to attach a RigidBody to it. To add one, select Add Component from the Inspector panel, followed by Physics > RigidBody. You can leave the settings at their defaults.


26. GUI Textures

To display the game's user interface, we'll use Unity's GUI Textures. Unity's documentation provides a clear explanation of GUI Textures:

GUI Textures are displayed as flat images in 2D. They are made especially for user interface elements, buttons, or decorations. Their positioning and scaling is performed along the x and y axes only, and they are measured in Screen Coordinates, rather than World Coordinates.

By default, images imported to the Assets folder are converted to Textures that can be applied to 3D objects. We need to change this to GUI Texture for the images we want to use in the game's user interface.

Select the images you want to convert in the Assets panel and open the Inspector, click on the Texture Type drop-down menu and select GUI.

You can now drag and drop the images to the Scene. The images will always appear in front of every object on the stage and will be treated as 2D elements.

27. GUI Text

Inside each GUI element, we'll display a number indicating the number of bananas the player has collected and the time the player has left.

Select Create Other > GUI Text from the GameObject menu to create a text object, place it at the center of the GUI element, and change the text in the Hierarchy panel to 0. Do the same for the time on the right. I've set the default time to 30 seconds.

You can use a custom font for the text by adding the font to the Assets folder and then changing the Font property of the text in the Inspector.

28. Adding Scripts

It's time to write some code. With the user interface in place, we can start writing the necessary code to add functionality to our game. We do this by means of scripts. Scripts are attached to different game objects. Follow the next steps to learn how to add interaction to the level we've just created.


29. Move Scene

We'll start by making use of the device's accelerometer. Moving the player using the accelerometer is fairly simple in Unity. There's nothing to set up and it's easy to understand.

Select the stage, click the Add Component button in the Inspector panel, and choose New Script. Name the script MoveScene and don't forget to change the language to C#. Open the newly created file and add the following code snippet.

using UnityEngine;
using System.Collections;

public class MoveScene : MonoBehaviour
{
    void Update()
    {
        transform.rotation *= Quaternion.Euler(Input.acceleration.y/6, -Input.acceleration.x/3, 0);
    }
}

We use the Update method to request data from the accelerometer in every frame using the Input.acceleration property, which measures the device's movement in a three-dimensional space. This allows us to get the x, y, and z values, and use them to control the player's position.

We then apply the obtained values to the transform.rotation property of the level by invoking Quaternion.Euler, which returns the rotation values. Note that we divide the accelerometer's values to avoid that the player moves too fast, making the gameplay difficult.

We only modify the level's x and y values, because we only need it to tilt and not to move closer to or farther from the camera.

30. Camera Follow

The following script is attached to the Main Camera. It calculates the space between the camera and the player and maintains it while the ball moves.

using UnityEngine;
using System.Collections;

public class FollowPlayer : MonoBehaviour
{
    public GameObject player;
    private Vector3 playerOffset;

    // Use this for initialization
    void Start()
    {
        playerOffset = transform.position - player.transform.position;
    }
    
    // Update is called once per frame
    void Update()
    {
        transform.LookAt(player.transform);
        transform.position = player.transform.position + playerOffset;
    }
}

The script uses two variables that are worth explaining:

  • player: This is a reference to the player in the Scene. You can set this in the Inspector.
  • playerOffset: This is the distance between the camera and the player. Because we maintain the same distance between camera and player, the camera follows the player as it moves. The offset is calculated in the Start method.

We direct the camera to the player and set its position to the player's position plus the value of playerOffset. Because we do this in the Update method, the camera position is calculated and updated in every frame. The result is that the camera follows the player. This is a simple yet effective strategy to create a camera that follows the player.

31. Picking Bananas

The following script is attached to the banana and handles any interactions with it. We start by getting references to the corresponding sound and the text displaying the number of collected bananas, which we'll need to play the sound and increase the counter in the top left when the player collides with a banana. Once you've declared the variables in the script, you need to set these references in the Inspector.

using UnityEngine;
using System.Collections;

public class PickBanana : MonoBehaviour
{
    public AudioClip bananaSound;
    public GUIText bananaText;

    void OnTriggerEnter(Collider other)
    {
        AudioSource.PlayClipAtPoint(bananaSound, transform.position);
		int score = int.Parse (bananaText.text) + 1;
		bananaText.text = score.ToString();
        Destroy(gameObject);
    }
}

Next, we call a method that detects when the ball collides with a banana. When this happens, we play the sound and increase the counter.

To modify the counter, we create a variable using the value of the GUI Text and use the int.Parse method to convert the string to a number and increment the number by 1. We then set the value to the GUI Text, first converting the number to a string by invoking the toString method. Finally, we invoke Destroy to remove the banana game object.

32. Falling Off the Platform

The following class is used to detect when the player falls off the platform into the sea. Attach the script to the sea game object.

using UnityEngine;
using System.Collections;

public class Lose : MonoBehaviour
{
    void OnCollisionEnter()
    {
        audio.Play();
        Invoke("Reload", 1.59f);
    }

    void Reload()
    {
        Application.LoadLevel(Application.loadedLevel);
    }
}

This simple class uses the OnCollisionEnter method to detect when the ball collides with the sea, which means the player has fallen off the platform. When this happens, we play the sound attached to the sea and use the Invoke method to call the Reload method, which restarts the game by reloading the current scene.

The second parameter of the Invoke method defines the delay with which the Reload method is invoked. This is necessary as we first want the sound to finish before we start a new game.

33. Monitoring Time

The next class, Timer, is attached to the time GUI in the top right. It reduces the time and ends the game when the counter reaches 0.

using UnityEngine;
using System.Collections;

public class Timer : MonoBehaviour
{
    public GUIText timeText;

    void Start()
    {
        InvokeRepeating("ReduceTime", 1, 1);
    }

    void ReduceTime()
    {
        int currentTime = int.Parse(timeText.text) - 1;
        timeText.text = currentTime.ToString();

        if (currentTime == 0)
        {
            audio.Play();
            Invoke("Reload", 1.59f);//waits until sound is played to reload
            Destroy(timeText);
        }
    }

    void Reload()
    {
        Application.LoadLevel(Application.loadedLevel);
    }
}

We keep a reference to the text in the timeText variable to make modifying the user interface easy. In the Start method, we call the InvokeRepeating method, which repeatedly invokes the ReduceTime method repeatedly.

To update the text in the user interface, we create a variable to convert the text to a number, just like we did earlier, and subtract one second and update the user interface with the result.

When the counter reaches 0, the appropriate sound is played and we destroy the counter text. We invoke the Reload method with a delay to restart the game when the sound has finished playing.

34. Level Complete

The last class, EndLevel, is used to detect when the player reaches the portal. When the player passes through the portal, we display a message on screen and destroy destroy the ball. We do this to prevent the ball from falling in the sea.

using UnityEngine;
using System.Collections;

public class EndLevel : MonoBehaviour
{
    public GameObject complete;
    public GameObject player;

    void OnTriggerEnter(Collider other)
    {
        audio.Play();
        Invoke("Restart", 2);
        GameObject alert = Instantiate(complete, new Vector3(0.5f, 0.5f, 0), transform.rotation) as GameObject;
        Destroy(player.rigidbody);
    }

    void Restart()
    {
        Application.LoadLevel(Application.loadedLevel);
    }
}

The Instantiate method is used to create an instance of the message that is displayed to the player. It lets us use the GUI element from the project's Assets instead of having it on the scene. Finally, we restart the game with a delay of two seconds.

35. Testing

It's time to test the game. Press Command+P to play the game in Unity. If everything works as expected, then you're ready for the final steps.


36. Player Settings

When you're happy with your game, it's time to select Build Settings from the File menu and click the Player Settings button. This should bring up the Player Settings in the Inspector panel where you can set the parameters for your application.

These settings are application specific data that includes the creator or company, app resolution and display mode, rendering mode (CPU, GPU), device OS compatibility, etc. Configure the settings according to the devices you're targeting and the store or market where you plan to publish the app.


37. Icons and Splash Images

Using the graphics you created earlier, you can now create a nice icon and a splash image for your game. Unity shows you the required sizes, which depend on the platform you're building for.

38. Build and Play


Once your project is properly configured, it's time to revisit the Build Settings and click the Build Button. That's all it takes to build your game for testing and/or distribution.

Conclusion

In this tutorial, we've learned how to use the accelerometer to control the movement of the player, GUI Textures, primitives, and other aspects of game development in Unity. I encourage you to experiment with the result and customize the game to make it your own. I hope you liked this tutorial and found it helpful.

2014-08-04T12:20:47.000Z2014-08-04T12:20:47.000ZCarlos Yanez

Develop a Monkey Ball Inspired Game with Unity

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-21416
Final product image
What You'll Be Creating

Introduction

In this tutorial, you'll learn how to create a mobile 3D game using C# and Unity. The objective of the game is to use the accelerometer to move the ball and reach the portal.

You will learn about the following aspects of Unity game development in this tutorial:

  • 3D Primitives
  • accelerometer controls
  • camera movement
  • physics
  • GUI Textures

1. Create a New Unity Project

Open Unity and select New Project from the File menu to open the new project dialog. Tell Unity where you want to save the project and set the Set up defaults for: menu to 3D.


2. Build Settings

In the next step, you're presented with Unity's user interface. Set the project up for mobile development by choosing Build Settings from the File menu and selecting your platform of choice.


3. Devices

The first thing we need to do after selecting the target platform is choosing the size of the artwork we'll be using in the game. This will help us select a proper size for the 3D textures and 2D GUI without making the artwork blurry or use textures that are too large for the target device. For example, the artwork needs to have a higher resolution if you're targeting an iPad with a retina display than a Lumia 520.

iOS

  • iPad without Retina: 1024px x 768px
  • iPad with Retina: 2048px x 1536px
  • 3.5" iPhone/iPod Touch without Retina: 320px x 480px
  • 3.5" iPhone/iPod with Retina: 960px x 640px
  • 4" iPhone/iPod Touch: 1136px x 640px

Android

Because Android is an open platform, there's a wide range of devices, screen resolutions, and pixel densities. A few of the more common ones are listed below.

  • Asus Nexus 7 Tablet: 800px x 1280px, 216 ppi
  • Motorola Droid X: 854px x 480px, 228 ppi
  • Samsung Galaxy SIII: 720px x 1280px, 306 ppi

Windows Phone & BlackBerry

  • Blackberry Z10: 720px x 1280px, 355 ppi
  • Nokia Lumia 520: 400px x 800px, 233 ppi
  • Nokia Lumia 1520: 1080px x 1920px, 367 ppi

Note that the code we'll write in this tutorial can be used to target any of the platforms.


4. Export Graphics

Depending on the devices you're targeting, you may need to convert the artwork to the recommended size and pixel density. You can do this in your favorite image editor. I've used the Adjust Size... function under the Tools menu in OS X's Preview application.


5. Unity User Interface

You can modify the resolution that's being displayed in the Game panel.


6. Game Interface

The interface of our game will be straightforward. The above screenshot gives you an idea of the artwork we'll be using and how the final game interface will end up looking. You can find the artwork and additional resources in the tutorial's source files on GitHub.


7. Programming Language

You can use one of three programming languages when using Unity, C#, UnityScript, a variation of JavaScript, and Boo. Each programming language has its pros and cons, and it's up to you to decide which one you prefer. My personal preference goes to the C# programming language so that's the language I'll be using in this tutorial.

If you decide to use another programming language, then make sure to take a look at Unity's Script Reference for examples.


8. Sound Effects

I'll use a number of sounds to improve the audial experience of the game. The sound effects used in this tutorial were obtained from playonloop.com and Freesound.


9. 3D Models

To create our game we first need to get our 3D models. I recommend 3docean for high quality models, textures, and more, but if you're testing or learning then a few free models are good as well. The models in this tutorial were downloaded from SketchUp 3D Warehouse where you can find a good variety of models of all kinds.

Now, as Unity doesn't recognize the SketchUp file format we need to convert it to something Unity can import. We first need to download the free version of SketchUp, which is called SketchUp Make

Open your 3D model in SketchUp Make, select Export > 3D Model from the File menu, and choose Collada (*.dae).

Choose a name and location, and click the save button. This will create a file and a folder for the 3D model. The file holds the data for the 3D object while the folder contains the model's textures. You can then import the model into Unity as explained in the next step.


10. Import Assets

Before we start coding, we need to add our assets to the Unity project. You can do this one of several ways:

  • select Import New Asset from the Assets menu
  • add the items to the assets folder in your project
  • drag and drop the assets in the project window

After completing this step, you should see the assets in your project's Assets folder in the Project panel.


11. Create Scene

We're ready to create the scene of our game by dragging objects to the Hierarchy or Scene panel. We'll also use Unity native 3D primitive objects to create the level as shown in the next steps.

12. Setup Camera

Let's first position our Main Camera a little bit higher to achieve the view we want. Select it from the Hierarchy panel and adjust the Transform values in the Inspector to match the  ones shown below.

Don't worry if you don't see any changes. We haven't created anything for the camera to see yet. Next, use the Inspector to set the Background color to RGB: 0, 139, 252.

13. Background

Our platform level will be floating above a background, which will be a representation of a sea. It will be created using Unity primitives, a simple Plane with a texture applied to it.

While Unity can work with 3D objects of any type created by other programs, it is sometimes easier and/or more convenient to use primitives for prototypes.

To create the sea, for example, select Create Other > Plane from the GameObject menu and adjust the Transform values in the Inspector to match the ones shown below.

You should a square in the Scene panel. We'll use it to detect when the player falls from the platform, ending the game.

It's worth mentioning that these primitive objects already have a Mesh Collider attached to them, which means that they will automatically detect collisions or trigger events when they come in contact with a RigidBody.

14. Texture Material

To apply a texture to the sea plane, we need to create a Material. A Material is used to define how a GameObject looks and it is essential to add a texture to a GameObject.

Select Create > Material from the Assets menu to create one, find it in the Assets panel, and use the Inspector to select the texture you want to use as your sea. These are the settings I've used:

You'll notice a message in the material section stating that it's recommended to use Mobile/Diffuse as a shader, because the default white color doesn't do anything. Changing it to Mobile/Diffuse will also help with performance.


15. Adding Light

You may have noticed that the sea is a bit darker than it should be. To fix this, we need to add a Light to our scene. Select Create Other from the GameObject menu and select Directional Light. This will create an object that produces a beam of light. Change its Transform values as shown in the following screenshot to make it illuminate the sea.

This looks much better.

16. Creating Platforms

The platforms are parts of our level and are used by the player to move the ball to the portal on the other side of the sea.

Create a Plane as you did for the sea and adjust the Transform values in the Inspector as shown below. This will create and put the first platform in place.

We can now use Unity's Move and Rotation tools to create the other platforms. They're all of the same size so we can use them vertically or horizontally by duplicating them using Command+D on OS X and Control+D on Windows.


17. Platform Texture

Create a new Material like we did in Step 14 and apply the texture to it. Mine looks like this:

Adjust the x and y tiling until you're happy with the result.


18. Border Cylinders

We need to create a border to prevent our player from falling off too easily. To do this, we'll use a new type of primitive, a Cylinder.

Select Create Other > Cylinder from the GameObject menu and adjust the Transform values in the Inspector as shown below.

This will add a small border to the edge of the first platform. Create a new Material and change its color in the Inspector to RGB: 255, 69, 0.

The result should look like this:

Use Command+D (Control+D on Windows) to duplicate the border and the Scale tool to change its size. Position the duplicates at the platforms' edges using Unity's tools.


19. Portal

The portal is the goal line of the game. The player will use the accelerometer to control the ball and take it to this point while picking up items and avoiding falling off the platform. The portal is a 3D model, which we imported in Step 10.

Drag and drop it on the Scene or Hierarchy panel and change its Transform values to the following:

This will position it at the end of the platforms.


20. Portal Collider

Because imported 3D models don't have a collider by default, we need to attach one. Since we only need to test if the ball hits the blue area of the portal, we'll attach the collider to it.

Take a look at the portal model in the Hierarchy view and you'll notice a small triangle to the left of its name. Click the triangle to expand the portal's group and select the first item. I've added the -Collider suffix for clarification.

Click the Add Component button in the Inspector and choose Physics > Mesh Collider. This will add a collider using the shape of the model's selected area.


21. Portal Audio Source

To provide feedback to the player, we'll play a sound effect when the ball touches the portal's collider. Because we'll be triggering the event using the previously created collider, we need to add the audio source to that same object.

Select it from the Hierarchy panel, click the Add Component button in the Inspector panel, and select Audio Source from the Audio section.

Uncheck Play on Awake and click the little dot on the right, below the gear icon, to select the sound you want to play.

22. Adding Islands

The islands are nothing more than decorative elements to make the level less empty. I've used an imported 3D model and a Cylinder to make them. I won't go into detail creating the islands since they're not essential to the game. With what you've learned so far, you should be able to create them yourself.


23. Adding Bananas

As in Monkey Ball, the player will be able to collect bananas during the game. Start by dragging the model from the Assets panel to the Scene. Don't worry about its location just yet, because we'll convert it to a Prefab later since we'll be reusing it multiple times.

24. Banana Mesh Collider

As I mentioned earlier, imported models don't have a collider by default, so we need to attach one to the banana. Click the Add Component button in the Inspector and choose Physics > Mesh Collider. This will add a collider using the model's shape. Make sure to check the Trigger checkbox, because we want to detect collisions, but we don't want the ball to react with the banana.


24. Adding the Player

It's time to create our game character, which will be a simple Sphere primitive. Select Create Other > Sphere from the GameObject menu to create the primitive and modify the Transform values in the Inspector as shown below.

This will create the sphere and position it at the start of our level.

To make the sphere semi-transparent, we need to change its Shader options. Open the Inspector and change the shader to Transparent/Diffuse.


25. Player RigidBody

To detect a collision with the player, we need to attach a RigidBody to it. To add one, select Add Component from the Inspector panel, followed by Physics > RigidBody. You can leave the settings at their defaults.


26. GUI Textures

To display the game's user interface, we'll use Unity's GUI Textures. Unity's documentation provides a clear explanation of GUI Textures:

GUI Textures are displayed as flat images in 2D. They are made especially for user interface elements, buttons, or decorations. Their positioning and scaling is performed along the x and y axes only, and they are measured in Screen Coordinates, rather than World Coordinates.

By default, images imported to the Assets folder are converted to Textures that can be applied to 3D objects. We need to change this to GUI Texture for the images we want to use in the game's user interface.

Select the images you want to convert in the Assets panel and open the Inspector, click on the Texture Type drop-down menu and select GUI.

You can now drag and drop the images to the Scene. The images will always appear in front of every object on the stage and will be treated as 2D elements.

27. GUI Text

Inside each GUI element, we'll display a number indicating the number of bananas the player has collected and the time the player has left.

Select Create Other > GUI Text from the GameObject menu to create a text object, place it at the center of the GUI element, and change the text in the Hierarchy panel to 0. Do the same for the time on the right. I've set the default time to 30 seconds.

You can use a custom font for the text by adding the font to the Assets folder and then changing the Font property of the text in the Inspector.

28. Adding Scripts

It's time to write some code. With the user interface in place, we can start writing the necessary code to add functionality to our game. We do this by means of scripts. Scripts are attached to different game objects. Follow the next steps to learn how to add interaction to the level we've just created.


29. Move Scene

We'll start by making use of the device's accelerometer. Moving the player using the accelerometer is fairly simple in Unity. There's nothing to set up and it's easy to understand.

Select the stage, click the Add Component button in the Inspector panel, and choose New Script. Name the script MoveScene and don't forget to change the language to C#. Open the newly created file and add the following code snippet.

using UnityEngine;
using System.Collections;

public class MoveScene : MonoBehaviour
{
    void Update()
    {
        transform.rotation *= Quaternion.Euler(Input.acceleration.y/6, -Input.acceleration.x/3, 0);
    }
}

We use the Update method to request data from the accelerometer in every frame using the Input.acceleration property, which measures the device's movement in a three-dimensional space. This allows us to get the x, y, and z values, and use them to control the player's position.

We then apply the obtained values to the transform.rotation property of the level by invoking Quaternion.Euler, which returns the rotation values. Note that we divide the accelerometer's values to avoid that the player moves too fast, making the gameplay difficult.

We only modify the level's x and y values, because we only need it to tilt and not to move closer to or farther from the camera.

30. Camera Follow

The following script is attached to the Main Camera. It calculates the space between the camera and the player and maintains it while the ball moves.

using UnityEngine;
using System.Collections;

public class FollowPlayer : MonoBehaviour
{
    public GameObject player;
    private Vector3 playerOffset;

    // Use this for initialization
    void Start()
    {
        playerOffset = transform.position - player.transform.position;
    }
    
    // Update is called once per frame
    void Update()
    {
        transform.LookAt(player.transform);
        transform.position = player.transform.position + playerOffset;
    }
}

The script uses two variables that are worth explaining:

  • player: This is a reference to the player in the Scene. You can set this in the Inspector.
  • playerOffset: This is the distance between the camera and the player. Because we maintain the same distance between camera and player, the camera follows the player as it moves. The offset is calculated in the Start method.

We direct the camera to the player and set its position to the player's position plus the value of playerOffset. Because we do this in the Update method, the camera position is calculated and updated in every frame. The result is that the camera follows the player. This is a simple yet effective strategy to create a camera that follows the player.

31. Picking Bananas

The following script is attached to the banana and handles any interactions with it. We start by getting references to the corresponding sound and the text displaying the number of collected bananas, which we'll need to play the sound and increase the counter in the top left when the player collides with a banana. Once you've declared the variables in the script, you need to set these references in the Inspector.

using UnityEngine;
using System.Collections;

public class PickBanana : MonoBehaviour
{
    public AudioClip bananaSound;
    public GUIText bananaText;

    void OnTriggerEnter(Collider other)
    {
        AudioSource.PlayClipAtPoint(bananaSound, transform.position);
		int score = int.Parse (bananaText.text) + 1;
		bananaText.text = score.ToString();
        Destroy(gameObject);
    }
}

Next, we call a method that detects when the ball collides with a banana. When this happens, we play the sound and increase the counter.

To modify the counter, we create a variable using the value of the GUI Text and use the int.Parse method to convert the string to a number and increment the number by 1. We then set the value to the GUI Text, first converting the number to a string by invoking the toString method. Finally, we invoke Destroy to remove the banana game object.

32. Falling Off the Platform

The following class is used to detect when the player falls off the platform into the sea. Attach the script to the sea game object.

using UnityEngine;
using System.Collections;

public class Lose : MonoBehaviour
{
    void OnCollisionEnter()
    {
        audio.Play();
        Invoke("Reload", 1.59f);
    }

    void Reload()
    {
        Application.LoadLevel(Application.loadedLevel);
    }
}

This simple class uses the OnCollisionEnter method to detect when the ball collides with the sea, which means the player has fallen off the platform. When this happens, we play the sound attached to the sea and use the Invoke method to call the Reload method, which restarts the game by reloading the current scene.

The second parameter of the Invoke method defines the delay with which the Reload method is invoked. This is necessary as we first want the sound to finish before we start a new game.

33. Monitoring Time

The next class, Timer, is attached to the time GUI in the top right. It reduces the time and ends the game when the counter reaches 0.

using UnityEngine;
using System.Collections;

public class Timer : MonoBehaviour
{
    public GUIText timeText;

    void Start()
    {
        InvokeRepeating("ReduceTime", 1, 1);
    }

    void ReduceTime()
    {
        int currentTime = int.Parse(timeText.text) - 1;
        timeText.text = currentTime.ToString();

        if (currentTime == 0)
        {
            audio.Play();
            Invoke("Reload", 1.59f);//waits until sound is played to reload
            Destroy(timeText);
        }
    }

    void Reload()
    {
        Application.LoadLevel(Application.loadedLevel);
    }
}

We keep a reference to the text in the timeText variable to make modifying the user interface easy. In the Start method, we call the InvokeRepeating method, which repeatedly invokes the ReduceTime method repeatedly.

To update the text in the user interface, we create a variable to convert the text to a number, just like we did earlier, and subtract one second and update the user interface with the result.

When the counter reaches 0, the appropriate sound is played and we destroy the counter text. We invoke the Reload method with a delay to restart the game when the sound has finished playing.

34. Level Complete

The last class, EndLevel, is used to detect when the player reaches the portal. When the player passes through the portal, we display a message on screen and destroy destroy the ball. We do this to prevent the ball from falling in the sea.

using UnityEngine;
using System.Collections;

public class EndLevel : MonoBehaviour
{
    public GameObject complete;
    public GameObject player;

    void OnTriggerEnter(Collider other)
    {
        audio.Play();
        Invoke("Restart", 2);
        GameObject alert = Instantiate(complete, new Vector3(0.5f, 0.5f, 0), transform.rotation) as GameObject;
        Destroy(player.rigidbody);
    }

    void Restart()
    {
        Application.LoadLevel(Application.loadedLevel);
    }
}

The Instantiate method is used to create an instance of the message that is displayed to the player. It lets us use the GUI element from the project's Assets instead of having it on the scene. Finally, we restart the game with a delay of two seconds.

35. Testing

It's time to test the game. Press Command+P to play the game in Unity. If everything works as expected, then you're ready for the final steps.


36. Player Settings

When you're happy with your game, it's time to select Build Settings from the File menu and click the Player Settings button. This should bring up the Player Settings in the Inspector panel where you can set the parameters for your application.

These settings are application specific data that includes the creator or company, app resolution and display mode, rendering mode (CPU, GPU), device OS compatibility, etc. Configure the settings according to the devices you're targeting and the store or market where you plan to publish the app.


37. Icons and Splash Images

Using the graphics you created earlier, you can now create a nice icon and a splash image for your game. Unity shows you the required sizes, which depend on the platform you're building for.

38. Build and Play


Once your project is properly configured, it's time to revisit the Build Settings and click the Build Button. That's all it takes to build your game for testing and/or distribution.

Conclusion

In this tutorial, we've learned how to use the accelerometer to control the movement of the player, GUI Textures, primitives, and other aspects of game development in Unity. I encourage you to experiment with the result and customize the game to make it your own. I hope you liked this tutorial and found it helpful.

2014-08-04T12:20:47.000Z2014-08-04T12:20:47.000ZCarlos Yanez

Core Data from Scratch: Migrations

$
0
0

In the previous articles of this series,  we've encountered an annoying issue that we need to address. Whenever we modify the data model of a Core Data application, the persistent store becomes incompatible with the data model. The result is a crash on launch, rendering the application unusable, a serious problem if this happens to an application in the App Store.

Our application crashes because we invoke abort in the persistentStoreCoordinator method if adding the persistent store to the persistent store coordinator is unsuccessful. To be clear, the abort function causes the application to terminate immediately.

if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
    NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    abort();
}

However, there is no need to terminate our application, let alone crash it. If Core Data tells us the data model and persistent store are incompatible, then it's up to us to resolve this.

In this article, we'll discuss two options to recover from such a situation, migrating the persistent store and creating a new persistent store that is compatible with the modified data model.

1. The Problem

Let me first clarify the problem that we're trying to solve. Download the sample project we created in the previous article and run it in the iOS Simulator. The application should run and work just fine.

Open Done.xcdatamodeld and add an attribute updatedAt of type Date to the TSPItem entity. Run the application one more time and notice how the application crashes as soon as it's launched. Luckily, Core Data gives us a clue as to what went wrong. Take a look at the output in Xcode's Console.

Error Domain=NSCocoaErrorDomain Code=134100 "The operation couldn’t be completed. (Cocoa error 134100.)"
UserInfo=0x7c57e980 {
metadata={
    NSPersistenceFrameworkVersion = 513;
    NSStoreModelVersionHashes =     {
        TSPItem = <ce1c6693 4229b043 7cfe7324 4718b0c4 81c9af4d 12e71373 3288b42e 7de7ac62>;
    };
    NSStoreModelVersionHashesVersion = 3;
    NSStoreModelVersionIdentifiers =     (
        ""
    );
    NSStoreType = SQLite;
    NSStoreUUID = "C6212594-143E-4A26-9990-7FE5FD8B7336";
    "_NSAutoVacuumLevel" = 2;
}, reason=The model used to open the store is incompatible with the one used to create the store},

In the last line, Core Data tells us that the data model that was used to open the persistent store is incompatible with the data model that it used to create the persistent store. Wait. What?

When we launched the application for the first time, Core Data created a SQLite database based on the data model. However, because we changed the data model by adding an attribute to the TSPItem entity, updatedAt, Core Data no longer understands how it should store TSPItem records in the SQLite database. In other words, the modified data model is no longer compatible with the persistent store it created earlier.

2. The Solution

Fortunately for us, a few clever engineers at Apple have created a solution to safely modify a data model without running into incompatibility issues. To solve the problem we're facing, we need to find a way to tell Core Data how one version of the data model relates to another version. That's correct, versioning the data model is part of the solution.

With that information, Core Data can understand how the persistent store needs to be updated to be compatible with the modified data model, that is, the new version of the data model. In other words, we need to hand Core Data the necessary information to migrate the persistent store from one version of the data model to another.

3. Migrations

There are two types of migrations, lightweight and heavy migrations. The words lightweight and heavy are pretty descriptive, but it's important that you understand how Core Data handles each type of migration.

Lightweight Migrations

Lightweight migrations require very little work from your part, the developer. I strongly recommend that you choose a lightweight migration over a heavy migration whenever you can. The cost of a lightweight migration is substantially lower than that of a heavy migration.

Of course, the flip side of lightweight migrations is that they are less powerful than heavy migrations. The changes you can make to a data model with lightweight migrations are limited. For example, a lightweight migration lets you add or rename attributes and entities, but you cannot modify the type of an attribute or the relationships between existing entities.

Lightweight migrations are ideal for expanding the data model, adding attributes and entities. If you plan to modify relationships or change attribute types, then you're in for a wild ride with heavy migrations.

Heavy Migrations

Heavy migrations are a bit trickier. Let me rephrase that. Heavy migrations are a pain in the neck and you should try to avoid them if possible. Heavy migrations are powerful, but that power comes at a cost. Heavy migrations require a lot of work and testing to make sure the migration completes successfully and, more importantly, without data loss.

We enter the world of heavy migrations if we make changes that Core Data cannot automatically infer for us by comparing versions of the data model. Core Data will then need a mapping model to understand how the versions of the data model relate to one another. Because heavy migrations are a complex topic, we won't cover it in this series.

4. Versioning

If you've worked with Ruby on Rails, then migrations will make a lot of sense to you. The idea is simple but powerful. Core Data allows us to version the data model and this enables us to safely modify the data model. Core Data inspects the versioned data model to understand how the persistent store relates to the data model. By looking at the versioned data model, it also knows if the persistent store needs to be migrated before it can be used with the current version of the data model.

Versioning and migrations go hand in hand. If you wish to understand how migrations work, you'll first need to understand how to version the Core Data data model. Let's revisit the to-do application we created in the previous article. As we saw earlier, adding an attribute, updatedAt, to the TSPItem entity results in the persistent store being incompatible with the modified data model. We now understand the cause of this.

Let's start with a clean slate by opening Done.xcdatamodeld and removing the updatedAt attribute from the TSPItem entity. It's time to create a new version of the data model.

With the data model selected, choose Add Model Version... from the Editor menu. Xcode will ask you to name the new data model version and, more importantly, on which version the new version should be based. To ensure Core Data can migrate the persistent store for us, it's important that you choose the previous version of the data model. In this example, we only have one choice.

The result of this action is that we can now see three data model files in the Project Navigator. There is one top level data model with a .xcdatamodeld extension and two children with a .xcdatamodel extension.

You can see the .xcdatamodeld file as a package for the versions of the data model, with each version represented by an .xcdatamodel file. You can verify this by right-clicking the .xcdatamodeld file and selecting Show in Finder. This will take you to the data model in the Xcode project. If you right-click that file and select Show Package Contents, you should see the two versions of the data model, Done.xcdatamodel and Done 2.xcdatamodel.

Have you noticed in the Project Navigator that one of the versions has a green checkmark? This checkmark indicates what the current model version is, Done.xcdatamodel in this example. In other words, even though we've created a new version of the data model, it isn't put to use by our application yet. Before we change this, though, we need to tell Core Data what it should do with the versioned data model.

We need to tell Core Data how to migrate the persistent store for the data model. We do this in the persistentStoreCoordinator method in TSPAppDelegate.m. In the persistentStoreCoordinator method, we create the persistent store coordinator and we add a persistent store to it by invoking addPersistentStoreWithType:configuration:URL:options:error:. This is nothing new.

The fourth parameter of this method, a dictionary of options, is currently nil. This dictionary of options includes instructions for Core Data. It gives us the opportunity to tell the persistent store coordinator how it should migrate the persistent store that we add to it.

Take a look at the updated implementation of persistentStoreCoordinator in which we pass a dictionary of options with two key-value pairs.

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
    if (_persistentStoreCoordinator) {
        return _persistentStoreCoordinator;
    }
    NSURL *applicationDocumentsDirectory = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
    NSURL *storeURL = [applicationDocumentsDirectory URLByAppendingPathComponent:@"Done.sqlite"];
    NSError *error = nil;
    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    NSDictionary *options = @{ NSMigratePersistentStoresAutomaticallyOption : @(YES),
                               NSInferMappingModelAutomaticallyOption : @(YES) };
    if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }
    return _persistentStoreCoordinator;
}

The first key, NSMigratePersistentStoresAutomaticallyOption, tells Core Data that we'd like it to attempt to migrate the persistent store for us. The second key, NSInferMappingModelAutomaticallyOption, instructs Core Data to infer the mapping model for the migration. This is exactly what we want. It should work without issues as long as we're dealing with a lightweight migration.

With this change, we are ready to migrate the data model to the new version we created a few moments ago. Start by selecting the new version, Done 2.xcdatamodel, and add a new attribute updatedAt of type Date to the TSPItem entity.

We also need to mark the new data model version as the version to use by Core Data. Select Done.xcdatamodeld in the Project Navigator and open the File Inspector on the right. In the section Model Version, set Current to Done 2.

In the Project NavigatorDone 2.xcdatamodel should now have a green checkmark instead of Done.xcdatamodel.

With this change, you can safely build and run the application. If you've followed the above steps, Core Data should automatically migrate the persistent store for you by inferring the mapping model based on the versioned data model.

Note that there are a few caveats you should be aware of. If you run into a crash, then you've done something wrong. For example, if you've set the data model version to Done 2.xcdatamodel, run the application, and then make changes to Done 2.xcdatamodel, then you'll inevitably run into a crash due to the persistent store being incompatible with the data model. Lightweight migrations are relatively powerful and they are easy to implement, but that doesn't mean you can modify the data model at any time.

The data layer of a software project requires care, attention, and preparation. Migrations are great, but they should be used sparingly. Crashes are no problem during development, but they are catastrophic in production. In the next section, we take a closer look at what this means and how to prevent crashes due to a problematic migration.

5. Avoiding Crashes

I have never come in a situation that warranted calling abort in production and it pains me when I browse a project in which Apple's default implementation for setting up the Core Data stack is used, in which abort is called when adding a persistent store is unsuccessful.

Avoiding abort is not that difficult, but it requires a few lines of code and informing the user about what went wrong in case something does go wrong. Developers are only human and we all make mistakes.

Step 1: Getting Rid of abort

Start by opening TSPAppDelegate.m and remove the line in which we call abort. That's the first step to a happy user.

if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
    NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
}

Step 2: Moving the Incompatible Store

If Core Data detects that the persistent store is incompatible with the data model, we first move the incompatible store to a safe location. We do this to make sure the user's data isn't lost. Even if the data model is incompatible with the persistent store, you may be able to recover data form it. Take a look at the updated implementation of the persistentStoreCoordinator method in TSPAppDelegate.m.

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
    if (_persistentStoreCoordinator) {
        return _persistentStoreCoordinator;
    }
    NSURL *storeURL = [[self applicationStoresDirectory] URLByAppendingPathComponent:@"Store.sqlite"];
    NSError *error = nil;
    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
        NSFileManager *fm = [NSFileManager defaultManager];
        // Move Incompatible Store
        if ([fm fileExistsAtPath:[storeURL path]]) {
            NSURL *corruptURL = [[self applicationIncompatibleStoresDirectory] URLByAppendingPathComponent:[self nameForIncompatibleStore]];
            // Move Corrupt Store
            NSError *errorMoveStore = nil;
            [fm moveItemAtURL:storeURL toURL:corruptURL error:&errorMoveStore];
            if (errorMoveStore) {
                NSLog(@"Unable to move corrupt store.");
            }
        }
    }
    return _persistentStoreCoordinator;
}

Note that I've changed the value of storeURL, the location of the persistent store. It points to a directory in the documents directory in the application's sandbox. The implementation of applicationStoresDirectory, a helper method, is straightforward as you can see below.

- (NSURL *)applicationStoresDirectory {
    NSFileManager *fm = [NSFileManager defaultManager];
    NSURL *applicationApplicationSupportDirectory = [[fm URLsForDirectory:NSApplicationSupportDirectory inDomains:NSUserDomainMask] lastObject];
    NSURL *URL = [applicationApplicationSupportDirectory URLByAppendingPathComponent:@"Stores"];
    if (![fm fileExistsAtPath:[URL path]]) {
        NSError *error = nil;
        [fm createDirectoryAtURL:URL withIntermediateDirectories:YES attributes:nil error:&error];
        if (error) {
            NSLog(@"Unable to create directory for data stores.");
            return nil;
        }
    }
    return URL;
}

If the persistent store coordinator is unable to add the existing persistent store at storeURL, we move the persistent store to a separate directory. Note that we make use of two more helper methods, applicationIncompatibleStoresDirectory and nameForIncompatibleStore. The implementation of applicationIncompatibleStoresDirectory is pretty simple as you can see below.

- (NSURL *)applicationIncompatibleStoresDirectory {
    NSFileManager *fm = [NSFileManager defaultManager];
    NSURL *URL = [[self applicationStoresDirectory] URLByAppendingPathComponent:@"Incompatible"];
    if (![fm fileExistsAtPath:[URL path]]) {
        NSError *error = nil;
        [fm createDirectoryAtURL:URL withIntermediateDirectories:YES attributes:nil error:&error];
        if (error) {
            NSLog(@"Unable to create directory for corrupt data stores.");
            return nil;
        }
    }
    return URL;
}

In nameForIncompatibleStore, we generate a name for the incompatible store based on the current date and time to avoid naming collisions.

- (NSString *)nameForIncompatibleStore {
    // Initialize Date Formatter
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    // Configure Date Formatter
    [dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4];
    [dateFormatter setDateFormat:@"yyyy-MM-dd-HH-mm-ss"];
    return [NSString stringWithFormat:@"%@.sqlite", [dateFormatter stringFromDate:[NSDate date]]];
}

Step 3: Creating a New Persistent Store

It's time to create a new persistent store to finish the setup of the Core Data stack. The next few lines should look very familiar by now.

NSError *errorAddingStore = nil;
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&errorAddingStore]) {
    NSLog(@"Unable to create persistent store after recovery. %@, %@", errorAddingStore, errorAddingStore.localizedDescription);
}

If Core Data is unable to create a new persistent store, then there are more serious problems that are not related to the data model being incompatible with the persistent store. If you do run into this issue, then double-check the value of storeURL.

Step 4: Notify the User

This step is probably the most important one in terms of creating a user friendly application. Losing the user's data is one thing, but pretending that nothing has happened is not nice. How would you feel if an airline lost your luggage, pretending as if nothing happened.

// Show Alert View
NSString *title = @"Warning";
NSString *applicationName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"];
NSString *message = [NSString stringWithFormat:@"A serious application error occurred while %@ tried to read your data. Please contact support for help.", applicationName];
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:title message:message delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[alertView show];

We show an alert view to the user, but it's a good idea to take it a few steps further. For example, you could urge them to contact support and you can even implement a feature that lets them send you the corrupt store. The latter is very useful for debugging the issue.

Step 5: Testing

Persisting data is an important aspect of most applications. It's therefore important to properly test what we've implemented in this article. To test our recovery strategy, run the application in the iOS Simulator and double-check that the persistent store was successfully created in the Application Support directory, in the Stores subdirectory.

Add a new attribute to the TSPItem entity in Done 2.xcdatamodel and run the application one more time. Because the existing persistent store is now incompatible with the data model, the incompatible persistent store is moved to the Incompatible subdirectory and a new persistent store is created. You should also see an alert view, informing the user about the problem.

Conclusion

Migrations are an important topic if you plan to make extensive use of Core Data. Migrations let you safely modify your application's data model and, in the case of lightweight migrations, without much overhead.

In the next article, we take another look at the NSManagedObject class and also discuss Core Data and concurrency.

2014-08-06T20:20:49.000Z2014-08-06T20:20:49.000ZBart Jacobs

Core Data from Scratch: Migrations

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-21844

In the previous articles of this series,  we've encountered an annoying issue that we need to address. Whenever we modify the data model of a Core Data application, the persistent store becomes incompatible with the data model. The result is a crash on launch, rendering the application unusable, a serious problem if this happens to an application in the App Store.

Our application crashes because we invoke abort in the persistentStoreCoordinator method if adding the persistent store to the persistent store coordinator is unsuccessful. To be clear, the abort function causes the application to terminate immediately.

if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
    NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    abort();
}

However, there is no need to terminate our application, let alone crash it. If Core Data tells us the data model and persistent store are incompatible, then it's up to us to resolve this.

In this article, we'll discuss two options to recover from such a situation, migrating the persistent store and creating a new persistent store that is compatible with the modified data model.

1. The Problem

Let me first clarify the problem that we're trying to solve. Download the sample project we created in the previous article and run it in the iOS Simulator. The application should run and work just fine.

Open Done.xcdatamodeld and add an attribute updatedAt of type Date to the TSPItem entity. Run the application one more time and notice how the application crashes as soon as it's launched. Luckily, Core Data gives us a clue as to what went wrong. Take a look at the output in Xcode's Console.

Error Domain=NSCocoaErrorDomain Code=134100 "The operation couldn’t be completed. (Cocoa error 134100.)"
UserInfo=0x7c57e980 {
metadata={
    NSPersistenceFrameworkVersion = 513;
    NSStoreModelVersionHashes =     {
        TSPItem = <ce1c6693 4229b043 7cfe7324 4718b0c4 81c9af4d 12e71373 3288b42e 7de7ac62>;
    };
    NSStoreModelVersionHashesVersion = 3;
    NSStoreModelVersionIdentifiers =     (
        ""
    );
    NSStoreType = SQLite;
    NSStoreUUID = "C6212594-143E-4A26-9990-7FE5FD8B7336";
    "_NSAutoVacuumLevel" = 2;
}, reason=The model used to open the store is incompatible with the one used to create the store},

In the last line, Core Data tells us that the data model that was used to open the persistent store is incompatible with the data model that it used to create the persistent store. Wait. What?

When we launched the application for the first time, Core Data created a SQLite database based on the data model. However, because we changed the data model by adding an attribute to the TSPItem entity, updatedAt, Core Data no longer understands how it should store TSPItem records in the SQLite database. In other words, the modified data model is no longer compatible with the persistent store it created earlier.

2. The Solution

Fortunately for us, a few clever engineers at Apple have created a solution to safely modify a data model without running into incompatibility issues. To solve the problem we're facing, we need to find a way to tell Core Data how one version of the data model relates to another version. That's correct, versioning the data model is part of the solution.

With that information, Core Data can understand how the persistent store needs to be updated to be compatible with the modified data model, that is, the new version of the data model. In other words, we need to hand Core Data the necessary information to migrate the persistent store from one version of the data model to another.

3. Migrations

There are two types of migrations, lightweight and heavy migrations. The words lightweight and heavy are pretty descriptive, but it's important that you understand how Core Data handles each type of migration.

Lightweight Migrations

Lightweight migrations require very little work from your part, the developer. I strongly recommend that you choose a lightweight migration over a heavy migration whenever you can. The cost of a lightweight migration is substantially lower than that of a heavy migration.

Of course, the flip side of lightweight migrations is that they are less powerful than heavy migrations. The changes you can make to a data model with lightweight migrations are limited. For example, a lightweight migration lets you add or rename attributes and entities, but you cannot modify the type of an attribute or the relationships between existing entities.

Lightweight migrations are ideal for expanding the data model, adding attributes and entities. If you plan to modify relationships or change attribute types, then you're in for a wild ride with heavy migrations.

Heavy Migrations

Heavy migrations are a bit trickier. Let me rephrase that. Heavy migrations are a pain in the neck and you should try to avoid them if possible. Heavy migrations are powerful, but that power comes at a cost. Heavy migrations require a lot of work and testing to make sure the migration completes successfully and, more importantly, without data loss.

We enter the world of heavy migrations if we make changes that Core Data cannot automatically infer for us by comparing versions of the data model. Core Data will then need a mapping model to understand how the versions of the data model relate to one another. Because heavy migrations are a complex topic, we won't cover it in this series.

4. Versioning

If you've worked with Ruby on Rails, then migrations will make a lot of sense to you. The idea is simple but powerful. Core Data allows us to version the data model and this enables us to safely modify the data model. Core Data inspects the versioned data model to understand how the persistent store relates to the data model. By looking at the versioned data model, it also knows if the persistent store needs to be migrated before it can be used with the current version of the data model.

Versioning and migrations go hand in hand. If you wish to understand how migrations work, you'll first need to understand how to version the Core Data data model. Let's revisit the to-do application we created in the previous article. As we saw earlier, adding an attribute, updatedAt, to the TSPItem entity results in the persistent store being incompatible with the modified data model. We now understand the cause of this.

Let's start with a clean slate by opening Done.xcdatamodeld and removing the updatedAt attribute from the TSPItem entity. It's time to create a new version of the data model.

With the data model selected, choose Add Model Version... from the Editor menu. Xcode will ask you to name the new data model version and, more importantly, on which version the new version should be based. To ensure Core Data can migrate the persistent store for us, it's important that you choose the previous version of the data model. In this example, we only have one choice.

The result of this action is that we can now see three data model files in the Project Navigator. There is one top level data model with a .xcdatamodeld extension and two children with a .xcdatamodel extension.

You can see the .xcdatamodeld file as a package for the versions of the data model, with each version represented by an .xcdatamodel file. You can verify this by right-clicking the .xcdatamodeld file and selecting Show in Finder. This will take you to the data model in the Xcode project. If you right-click that file and select Show Package Contents, you should see the two versions of the data model, Done.xcdatamodel and Done 2.xcdatamodel.

Have you noticed in the Project Navigator that one of the versions has a green checkmark? This checkmark indicates what the current model version is, Done.xcdatamodel in this example. In other words, even though we've created a new version of the data model, it isn't put to use by our application yet. Before we change this, though, we need to tell Core Data what it should do with the versioned data model.

We need to tell Core Data how to migrate the persistent store for the data model. We do this in the persistentStoreCoordinator method in TSPAppDelegate.m. In the persistentStoreCoordinator method, we create the persistent store coordinator and we add a persistent store to it by invoking addPersistentStoreWithType:configuration:URL:options:error:. This is nothing new.

The fourth parameter of this method, a dictionary of options, is currently nil. This dictionary of options includes instructions for Core Data. It gives us the opportunity to tell the persistent store coordinator how it should migrate the persistent store that we add to it.

Take a look at the updated implementation of persistentStoreCoordinator in which we pass a dictionary of options with two key-value pairs.

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
    if (_persistentStoreCoordinator) {
        return _persistentStoreCoordinator;
    }
    NSURL *applicationDocumentsDirectory = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
    NSURL *storeURL = [applicationDocumentsDirectory URLByAppendingPathComponent:@"Done.sqlite"];
    NSError *error = nil;
    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    NSDictionary *options = @{ NSMigratePersistentStoresAutomaticallyOption : @(YES),
                               NSInferMappingModelAutomaticallyOption : @(YES) };
    if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }
    return _persistentStoreCoordinator;
}

The first key, NSMigratePersistentStoresAutomaticallyOption, tells Core Data that we'd like it to attempt to migrate the persistent store for us. The second key, NSInferMappingModelAutomaticallyOption, instructs Core Data to infer the mapping model for the migration. This is exactly what we want. It should work without issues as long as we're dealing with a lightweight migration.

With this change, we are ready to migrate the data model to the new version we created a few moments ago. Start by selecting the new version, Done 2.xcdatamodel, and add a new attribute updatedAt of type Date to the TSPItem entity.

We also need to mark the new data model version as the version to use by Core Data. Select Done.xcdatamodeld in the Project Navigator and open the File Inspector on the right. In the section Model Version, set Current to Done 2.

In the Project NavigatorDone 2.xcdatamodel should now have a green checkmark instead of Done.xcdatamodel.

With this change, you can safely build and run the application. If you've followed the above steps, Core Data should automatically migrate the persistent store for you by inferring the mapping model based on the versioned data model.

Note that there are a few caveats you should be aware of. If you run into a crash, then you've done something wrong. For example, if you've set the data model version to Done 2.xcdatamodel, run the application, and then make changes to Done 2.xcdatamodel, then you'll inevitably run into a crash due to the persistent store being incompatible with the data model. Lightweight migrations are relatively powerful and they are easy to implement, but that doesn't mean you can modify the data model at any time.

The data layer of a software project requires care, attention, and preparation. Migrations are great, but they should be used sparingly. Crashes are no problem during development, but they are catastrophic in production. In the next section, we take a closer look at what this means and how to prevent crashes due to a problematic migration.

5. Avoiding Crashes

I have never come in a situation that warranted calling abort in production and it pains me when I browse a project in which Apple's default implementation for setting up the Core Data stack is used, in which abort is called when adding a persistent store is unsuccessful.

Avoiding abort is not that difficult, but it requires a few lines of code and informing the user about what went wrong in case something does go wrong. Developers are only human and we all make mistakes.

Step 1: Getting Rid of abort

Start by opening TSPAppDelegate.m and remove the line in which we call abort. That's the first step to a happy user.

if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
    NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
}

Step 2: Moving the Incompatible Store

If Core Data detects that the persistent store is incompatible with the data model, we first move the incompatible store to a safe location. We do this to make sure the user's data isn't lost. Even if the data model is incompatible with the persistent store, you may be able to recover data form it. Take a look at the updated implementation of the persistentStoreCoordinator method in TSPAppDelegate.m.

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
    if (_persistentStoreCoordinator) {
        return _persistentStoreCoordinator;
    }
    NSURL *storeURL = [[self applicationStoresDirectory] URLByAppendingPathComponent:@"Store.sqlite"];
    NSError *error = nil;
    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
        NSFileManager *fm = [NSFileManager defaultManager];
        // Move Incompatible Store
        if ([fm fileExistsAtPath:[storeURL path]]) {
            NSURL *corruptURL = [[self applicationIncompatibleStoresDirectory] URLByAppendingPathComponent:[self nameForIncompatibleStore]];
            // Move Corrupt Store
            NSError *errorMoveStore = nil;
            [fm moveItemAtURL:storeURL toURL:corruptURL error:&errorMoveStore];
            if (errorMoveStore) {
                NSLog(@"Unable to move corrupt store.");
            }
        }
    }
    return _persistentStoreCoordinator;
}

Note that I've changed the value of storeURL, the location of the persistent store. It points to a directory in the documents directory in the application's sandbox. The implementation of applicationStoresDirectory, a helper method, is straightforward as you can see below.

- (NSURL *)applicationStoresDirectory {
    NSFileManager *fm = [NSFileManager defaultManager];
    NSURL *applicationApplicationSupportDirectory = [[fm URLsForDirectory:NSApplicationSupportDirectory inDomains:NSUserDomainMask] lastObject];
    NSURL *URL = [applicationApplicationSupportDirectory URLByAppendingPathComponent:@"Stores"];
    if (![fm fileExistsAtPath:[URL path]]) {
        NSError *error = nil;
        [fm createDirectoryAtURL:URL withIntermediateDirectories:YES attributes:nil error:&error];
        if (error) {
            NSLog(@"Unable to create directory for data stores.");
            return nil;
        }
    }
    return URL;
}

If the persistent store coordinator is unable to add the existing persistent store at storeURL, we move the persistent store to a separate directory. Note that we make use of two more helper methods, applicationIncompatibleStoresDirectory and nameForIncompatibleStore. The implementation of applicationIncompatibleStoresDirectory is pretty simple as you can see below.

- (NSURL *)applicationIncompatibleStoresDirectory {
    NSFileManager *fm = [NSFileManager defaultManager];
    NSURL *URL = [[self applicationStoresDirectory] URLByAppendingPathComponent:@"Incompatible"];
    if (![fm fileExistsAtPath:[URL path]]) {
        NSError *error = nil;
        [fm createDirectoryAtURL:URL withIntermediateDirectories:YES attributes:nil error:&error];
        if (error) {
            NSLog(@"Unable to create directory for corrupt data stores.");
            return nil;
        }
    }
    return URL;
}

In nameForIncompatibleStore, we generate a name for the incompatible store based on the current date and time to avoid naming collisions.

- (NSString *)nameForIncompatibleStore {
    // Initialize Date Formatter
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    // Configure Date Formatter
    [dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4];
    [dateFormatter setDateFormat:@"yyyy-MM-dd-HH-mm-ss"];
    return [NSString stringWithFormat:@"%@.sqlite", [dateFormatter stringFromDate:[NSDate date]]];
}

Step 3: Creating a New Persistent Store

It's time to create a new persistent store to finish the setup of the Core Data stack. The next few lines should look very familiar by now.

NSError *errorAddingStore = nil;
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&errorAddingStore]) {
    NSLog(@"Unable to create persistent store after recovery. %@, %@", errorAddingStore, errorAddingStore.localizedDescription);
}

If Core Data is unable to create a new persistent store, then there are more serious problems that are not related to the data model being incompatible with the persistent store. If you do run into this issue, then double-check the value of storeURL.

Step 4: Notify the User

This step is probably the most important one in terms of creating a user friendly application. Losing the user's data is one thing, but pretending that nothing has happened is not nice. How would you feel if an airline lost your luggage, pretending as if nothing happened.

// Show Alert View
NSString *title = @"Warning";
NSString *applicationName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"];
NSString *message = [NSString stringWithFormat:@"A serious application error occurred while %@ tried to read your data. Please contact support for help.", applicationName];
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:title message:message delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[alertView show];

We show an alert view to the user, but it's a good idea to take it a few steps further. For example, you could urge them to contact support and you can even implement a feature that lets them send you the corrupt store. The latter is very useful for debugging the issue.

Step 5: Testing

Persisting data is an important aspect of most applications. It's therefore important to properly test what we've implemented in this article. To test our recovery strategy, run the application in the iOS Simulator and double-check that the persistent store was successfully created in the Application Support directory, in the Stores subdirectory.

Add a new attribute to the TSPItem entity in Done 2.xcdatamodel and run the application one more time. Because the existing persistent store is now incompatible with the data model, the incompatible persistent store is moved to the Incompatible subdirectory and a new persistent store is created. You should also see an alert view, informing the user about the problem.

Conclusion

Migrations are an important topic if you plan to make extensive use of Core Data. Migrations let you safely modify your application's data model and, in the case of lightweight migrations, without much overhead.

In the next article, we take another look at the NSManagedObject class and also discuss Core Data and concurrency.

2014-08-06T20:20:49.000Z2014-08-06T20:20:49.000ZBart Jacobs

HTML5: Network Information API

$
0
0

Introduction

One of the most discussed concepts in the world of the web design is responsive web design. Thousands of articles have been written on responsive web design and I therefore won't discuss it in this article. However, responsive web design has an important limitation, responsive web design is for the most part based on the size of the browser's viewport.

While this approach works well for serving up images of the right size and resolution, it isn't ideal in all situations, video content being one example. What we really need in these cases is more information about the device's network connection.

Imagine you're visiting YouTube on your smartphone or tablet. You're at home and connected over Wi-Fi. In such cases, you don't care about the number of bytes that are being downloaded, you're only interested in high quality video content. This isn't true if you're connected over a slow mobile connection. In that case, you want to see the video, the quality is secondary.

I should be clear that every developer who wants a website to be really good still has to optimize the assets it serves to allow pages to load as fast as possible. However, in the above example, serving up a high resolution video isn't a waste of the user's bandwidth, but an improvement of the user experience.

The Network Information API is exactly what we need to find out more about the network connection of the device.

1. What is it?

The Network Information API provides access to the connection type the system is using to communicate with the network, cellular, Wi-Fi, Bluetooth, etc. It also provides a means for scripts to be notified if the connection type changes. This is to allow developers to make dynamic changes to the DOM and/or inform the user that the network connection type has changed.

The first release of the specification of the Network Information API was in 2001, but the API has changed several times since. As a proof of this, the current version is a mere editor's draft, which means that it's bound to change in the future.

Despite the changes, the use cases for this API are so interesting that it's really worth exploring it. In this article, we'll discuss the latest version of the specification, but we'll also look at some of the deprecated properties and events for reasons I'll explain later.

2. Implementation

The current version of the Network Information API exposes a connection object that belongs to the window.navigator object. The connection object contains one property, type, which returns the user agent's connection type. The type property can have one of the following values:

  • bluetooth
  • cellular
  • ethernet
  • none
  • wifi
  • other
  • unknown

Some of these values, such as bluetooth and wifi, are self-explanatory while others need a bit more explaining. The cellular type refers to a mobile connection, such as EDGE, 3G, 4G, etc. The other type means that the current connection type is not unknown, but it isn't any of the other types either. The unknown type means that the user agent has established a network connection, but it is unable to determine what the connection type is.

In addition to type, the Network Information API exposes the ontypechange event. It is fired every time the type of the network connection changes.

Developers can use the Network Information API to change some features based on the current connection type. For example, we can slow down a process that takes up significant bandwidth if we detect the device is using a mobile connection. The API also lets us assign a specific class to the html element, for example high-bandwidth, in the same way Modernizr does. We can leverage CSS to change one or more properties of an element, such as the background image.

Now that we know what the Network Information API does and who we can benefit form it, let's see which browsers support the API.

3. Browser Support

At the time of writing, the Network Information API is only supported by Firefox, using its vendor prefix, and Chrome Canary. In Chrome Canary, we have to enable the experimental web platform features flag to use the API. You can find more information in this post by Paul Irish.

As if support for the Network Information API wasn't already poor enough, Firefox up to version 30, the most recent version, supports the old API specification. Because of this and in case you want to play with the Network Information API right now, it's important to take a look at the properties and events exposed by the previous specification of the API.

The old specification exposed two properties, bandwidth and metered. The bandwidth property is a double representing an estimation of the current bandwidth in megabytes per second (MB/s). The metered property is a boolean that specifies if the the network connection of the device is subject to any limitations. The previous specification also defined a onchange event to notify any listeners about changes of the aforementioned properties.

To give you an idea of the new and the old version of the specification, in the next section we'll build a demo that uses both.

4. Demo

So far, we've covered the properties and the events exposed by the API as well as the API's use cases. In this section, we're going to create a simple web page to see the API in action.

The demo consists of an HTML5 page that has an unordered list with three list items. Each item contains a text snippet to verify the value of the properties exposed by the old and the new specification of the Network Information API. The list items are hidden by default and are only shown if the corresponding properties are supported.

The demo also detects if the browser implements the old specification of the API (to target Firefox) and if the browser supports the Network Information API at all. In the first case, you'll see the message Old API version supported, in the second case the message API not supported will be displayed.

Testing for support of the Network Information API is very simple as you can see below:

// Deal with vendor prefixes
var connection = window.navigator.connection    ||
                 window.navigator.mozConnection ||
                 null;
if (connection === null) {
   // API not supported :(
} else {
   // API supported! Let's start the fun :)
}

To detect if the version implemented is the old specification, we can test for the presence of the metered property as shown below:

if ('metered' in connection) {
   // Old version
} else {
   // New version
}

Once we've tested for support of the Network Information API and we've figured out which version of the specification the browser supports, we can attach a handler to the correct event. Inside the handler we update the text of the corresponding list item, for example type for the new API specification.

You can find the complete code of the demo below and you can also play with it if you like.

<!DOCTYPE html><html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"/><meta name="author" content="Aurelio De Rosa"><title>Network Information API Demo by Aurelio De Rosa</title><style>
         *
         {
            -webkit-box-sizing: border-box;
            -moz-box-sizing: border-box;
            box-sizing: border-box;
         }

         body
         {
            max-width: 500px;
            margin: 2em auto;
            padding: 0 0.5em;
            font-size: 20px;
         }

         h1
         {
            text-align: center;
         }

         .api-support
         {
            display: block;
         }

         .hidden
         {
            display: none;
         }

         .value
         {
            font-weight: bold;
         }

         .author
         {
            display: block;
            margin-top: 1em;
         }
      </style></head><body><h1>Network Information API</h1><span id="ni-unsupported" class="api-support hidden">API not supported</span><span id="nio-supported" class="api-support hidden">Old API version supported</span><ul><li class="new-api hidden">
            The connection type is <span id="t-value" class="value">undefined</span>.</li><li class="old-api hidden">
            The connection bandwidth is <span id="b-value" class="value">undefined</span>.</li><li class="old-api hidden">
            The connection is <span id="m-value" class="value">undefined</span>.</li></ul><small class="author">
         Demo created by <a href="http://www.audero.it">Aurelio De Rosa</a>
         (<a href="https://twitter.com/AurelioDeRosa">@AurelioDeRosa</a>).<br />
         This demo is part of the <a href="https://github.com/AurelioDeRosa/HTML5-API-demos">HTML5 API demos repository</a>.</small><script>
         var connection = window.navigator.connection    ||
                          window.navigator.mozConnection ||
                          null;
         if (connection === null) {
            document.getElementById('ni-unsupported').classList.remove('hidden');
         } else if ('metered' in connection) {
            document.getElementById('nio-supported').classList.remove('hidden');
            [].slice.call(document.getElementsByClassName('old-api')).forEach(function(element) {
               element.classList.remove('hidden');
            });

            var bandwidthValue = document.getElementById('b-value');
            var meteredValue = document.getElementById('m-value');

            connection.addEventListener('change', function (event) {
               bandwidthValue.innerHTML = connection.bandwidth;
               meteredValue.innerHTML = (connection.metered ? '' : 'not ') + 'metered';
            });
            connection.dispatchEvent(new Event('change'));
         } else {
            var typeValue = document.getElementById('t-value');
            [].slice.call(document.getElementsByClassName('new-api')).forEach(function(element) {
               element.classList.remove('hidden');
            });

            connection.addEventListener('typechange', function (event) {
               typeValue.innerHTML = connection.type;
            });
            connection.dispatchEvent(new Event('typechange'));
         }
</script></body></html>

Conclusion

In this article, I introduced you to the Network Information API. In the first part of this article, we've discussed what the API is and what it can do for us. We also learned what properties and events the Network Information API exposes. As I mentioned in Browser Support, the API is currently poorly supported, but this is in part due to several changes of the API's specification.

The Network Information API is very simple to use and there are no excuses to not take advantage of the information it offers once it's supported by more browsers. What do you think of this API? Will you use it when it's supported by more browsers?

2014-08-08T16:45:05.000Z2014-08-08T16:45:05.000ZAurelio De Rosa

HTML5: Network Information API

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-21598

Introduction

One of the most discussed concepts in the world of the web design is responsive web design. Thousands of articles have been written on responsive web design and I therefore won't discuss it in this article. However, responsive web design has an important limitation, responsive web design is for the most part based on the size of the browser's viewport.

While this approach works well for serving up images of the right size and resolution, it isn't ideal in all situations, video content being one example. What we really need in these cases is more information about the device's network connection.

Imagine you're visiting YouTube on your smartphone or tablet. You're at home and connected over Wi-Fi. In such cases, you don't care about the number of bytes that are being downloaded, you're only interested in high quality video content. This isn't true if you're connected over a slow mobile connection. In that case, you want to see the video, the quality is secondary.

I should be clear that every developer who wants a website to be really good still has to optimize the assets it serves to allow pages to load as fast as possible. However, in the above example, serving up a high resolution video isn't a waste of the user's bandwidth, but an improvement of the user experience.

The Network Information API is exactly what we need to find out more about the network connection of the device.

1. What is it?

The Network Information API provides access to the connection type the system is using to communicate with the network, cellular, Wi-Fi, Bluetooth, etc. It also provides a means for scripts to be notified if the connection type changes. This is to allow developers to make dynamic changes to the DOM and/or inform the user that the network connection type has changed.

The first release of the specification of the Network Information API was in 2001, but the API has changed several times since. As a proof of this, the current version is a mere editor's draft, which means that it's bound to change in the future.

Despite the changes, the use cases for this API are so interesting that it's really worth exploring it. In this article, we'll discuss the latest version of the specification, but we'll also look at some of the deprecated properties and events for reasons I'll explain later.

2. Implementation

The current version of the Network Information API exposes a connection object that belongs to the window.navigator object. The connection object contains one property, type, which returns the user agent's connection type. The type property can have one of the following values:

  • bluetooth
  • cellular
  • ethernet
  • none
  • wifi
  • other
  • unknown

Some of these values, such as bluetooth and wifi, are self-explanatory while others need a bit more explaining. The cellular type refers to a mobile connection, such as EDGE, 3G, 4G, etc. The other type means that the current connection type is not unknown, but it isn't any of the other types either. The unknown type means that the user agent has established a network connection, but it is unable to determine what the connection type is.

In addition to type, the Network Information API exposes the ontypechange event. It is fired every time the type of the network connection changes.

Developers can use the Network Information API to change some features based on the current connection type. For example, we can slow down a process that takes up significant bandwidth if we detect the device is using a mobile connection. The API also lets us assign a specific class to the html element, for example high-bandwidth, in the same way Modernizr does. We can leverage CSS to change one or more properties of an element, such as the background image.

Now that we know what the Network Information API does and who we can benefit form it, let's see which browsers support the API.

3. Browser Support

At the time of writing, the Network Information API is only supported by Firefox, using its vendor prefix, and Chrome Canary. In Chrome Canary, we have to enable the experimental web platform features flag to use the API. You can find more information in this post by Paul Irish.

As if support for the Network Information API wasn't already poor enough, Firefox up to version 30, the most recent version, supports the old API specification. Because of this and in case you want to play with the Network Information API right now, it's important to take a look at the properties and events exposed by the previous specification of the API.

The old specification exposed two properties, bandwidth and metered. The bandwidth property is a double representing an estimation of the current bandwidth in megabytes per second (MB/s). The metered property is a boolean that specifies if the the network connection of the device is subject to any limitations. The previous specification also defined a onchange event to notify any listeners about changes of the aforementioned properties.

To give you an idea of the new and the old version of the specification, in the next section we'll build a demo that uses both.

4. Demo

So far, we've covered the properties and the events exposed by the API as well as the API's use cases. In this section, we're going to create a simple web page to see the API in action.

The demo consists of an HTML5 page that has an unordered list with three list items. Each item contains a text snippet to verify the value of the properties exposed by the old and the new specification of the Network Information API. The list items are hidden by default and are only shown if the corresponding properties are supported.

The demo also detects if the browser implements the old specification of the API (to target Firefox) and if the browser supports the Network Information API at all. In the first case, you'll see the message Old API version supported, in the second case the message API not supported will be displayed.

Testing for support of the Network Information API is very simple as you can see below:

// Deal with vendor prefixes
var connection = window.navigator.connection    ||
                 window.navigator.mozConnection ||
                 null;
if (connection === null) {
   // API not supported :(
} else {
   // API supported! Let's start the fun :)
}

To detect if the version implemented is the old specification, we can test for the presence of the metered property as shown below:

if ('metered' in connection) {
   // Old version
} else {
   // New version
}

Once we've tested for support of the Network Information API and we've figured out which version of the specification the browser supports, we can attach a handler to the correct event. Inside the handler we update the text of the corresponding list item, for example type for the new API specification.

You can find the complete code of the demo below and you can also play with it if you like.

<!DOCTYPE html><html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"/><meta name="author" content="Aurelio De Rosa"><title>Network Information API Demo by Aurelio De Rosa</title><style>
         *
         {
            -webkit-box-sizing: border-box;
            -moz-box-sizing: border-box;
            box-sizing: border-box;
         }

         body
         {
            max-width: 500px;
            margin: 2em auto;
            padding: 0 0.5em;
            font-size: 20px;
         }

         h1
         {
            text-align: center;
         }

         .api-support
         {
            display: block;
         }

         .hidden
         {
            display: none;
         }

         .value
         {
            font-weight: bold;
         }

         .author
         {
            display: block;
            margin-top: 1em;
         }
      </style></head><body><h1>Network Information API</h1><span id="ni-unsupported" class="api-support hidden">API not supported</span><span id="nio-supported" class="api-support hidden">Old API version supported</span><ul><li class="new-api hidden">
            The connection type is <span id="t-value" class="value">undefined</span>.</li><li class="old-api hidden">
            The connection bandwidth is <span id="b-value" class="value">undefined</span>.</li><li class="old-api hidden">
            The connection is <span id="m-value" class="value">undefined</span>.</li></ul><small class="author">
         Demo created by <a href="http://www.audero.it">Aurelio De Rosa</a>
         (<a href="https://twitter.com/AurelioDeRosa">@AurelioDeRosa</a>).<br />
         This demo is part of the <a href="https://github.com/AurelioDeRosa/HTML5-API-demos">HTML5 API demos repository</a>.</small><script>
         var connection = window.navigator.connection    ||
                          window.navigator.mozConnection ||
                          null;
         if (connection === null) {
            document.getElementById('ni-unsupported').classList.remove('hidden');
         } else if ('metered' in connection) {
            document.getElementById('nio-supported').classList.remove('hidden');
            [].slice.call(document.getElementsByClassName('old-api')).forEach(function(element) {
               element.classList.remove('hidden');
            });

            var bandwidthValue = document.getElementById('b-value');
            var meteredValue = document.getElementById('m-value');

            connection.addEventListener('change', function (event) {
               bandwidthValue.innerHTML = connection.bandwidth;
               meteredValue.innerHTML = (connection.metered ? '' : 'not ') + 'metered';
            });
            connection.dispatchEvent(new Event('change'));
         } else {
            var typeValue = document.getElementById('t-value');
            [].slice.call(document.getElementsByClassName('new-api')).forEach(function(element) {
               element.classList.remove('hidden');
            });

            connection.addEventListener('typechange', function (event) {
               typeValue.innerHTML = connection.type;
            });
            connection.dispatchEvent(new Event('typechange'));
         }
</script></body></html>

Conclusion

In this article, I introduced you to the Network Information API. In the first part of this article, we've discussed what the API is and what it can do for us. We also learned what properties and events the Network Information API exposes. As I mentioned in Browser Support, the API is currently poorly supported, but this is in part due to several changes of the API's specification.

The Network Information API is very simple to use and there are no excuses to not take advantage of the information it offers once it's supported by more browsers. What do you think of this API? Will you use it when it's supported by more browsers?

2014-08-08T16:45:05.000Z2014-08-08T16:45:05.000ZAurelio De Rosa

10 Xcode Plugins for iOS Development

$
0
0

A proper plugin architecture can mean all the difference for an integrated development environment. Sublime Text and TextMate are great examples. Did you know that Xcode also supports plugins? It wouldn't surprise me if you don't, Apple hasn't put much effort into advertising that part of Xcode. In fact, there is very little documentation available to create plugins for Xcode.

Fortunately, this hasn't stopped developers from creating plugins for Xcode. There is a wide range of plugins that make working with Xcode easier and more enjoyable, filling up the gaps Apple has left. In this quick tip, I will show you a few plugins I use on a daily basis.

Alcatraz

Installing Xcode plugins used to be a pain, but that's no longer the case with Alcatraz. Earlier this year, Alcatraz reached an important milestone, 1.0, and it's now compatible with Xcode 5. If you haven't installed Alcatraz yet, then I encourage you to do so first.

1. XcodeColors

XcodeColors is a plugin developed by Robbie Hanson that adds color to Xcode's console. This plugin is especially useful in combination with CocoaLumberjack, a wonderful logging library Robbie wrote. This combination has been a true lifesaver for me over the years, it has made debugging easier and more, well, colorful. Read this quick tip if you want to read more about XcodeColors and CocoaLumberjack.

2. XToDo

This plugin not only highlights TODO, FIXME, ???, and !!! comments, it also presents them in a convenient list.

3. Backlight

Some plugins may seem trivial or simple, but they are fantastic if you consider their value. Backlight is such a plugin. All it does, is highlight the line that's currently being edited. It's simple, but very helpful.

4. CocoaPods

CocoaPods is the de facto dependency manager for iOS and OS X development. If you're not using CocoaPods, then I encourage you to give it a try. This tutorial will get you started in less than ten minutes.

There's also a CocoaPods plugin for Xcode, which makes integrating CocoaPods even easier. The CocoaPods plugin adds a CocoaPods menu item to Xcode's Product menu. If you don't like the command line, then you'll certainly like this plugin.

5. ACCodeSnippetRepository

Like Xcode plugins, managing code snippets isn't trivial in Xcode. Arnaud Coomans shared this opinion and created a nifty plugin that synchronizes your Xcode code snippets with a git repository.

The beauty is that the code snippets you've manually added in Xcode are left untouched. Importing code snippets from a git repository only takes a few clicks. This is also a clever way to back up your code snippets or keep them in a central location if you use multiple machines.

6. GitDiff

A graphical user interface makes working with git less daunting for many developers. While applications like Tower and SourceTree are great, I often want to know what has changed in the file I'm currently working on, in Xcode's code editor. The GitDiff plugin makes this possible and it's great.

It's a subtle enhancement of Xcode's code editor, adding just enough visual information to know what has changed since the last commit.

7. KSImageNamed

Autocompletion is great, especially if you're writing Objective-C. Wouldn't it be great if Xcode autocompleted file names, such as the names of image files?

Kent Sutherland created the KSImageNamed plugin that does exactly that. Not only will it save you time, it will make sure that typos are a thing of the past.

8. Peckham

Adding import statements can be pesky sometimes. If you need to import a header of a pod, for example, then Xcode's autocompletion won't work for you. The Peckham plugin solves this issue.

Press Command-Control-P, type a few letters of the header you're looking for, and select it from the list of options presented by the plugin. It's a great addition to Xcode's autocomplete functionality.

9. FuzzyAutocomplete

Speaking of autocomplete, the majority of iOS and OS X developers have come to rely on Xcode's great autocomplete functionality. However, Xcode's implementation of autocomplete isn't perfect and you don't always get the suggestions you expected or hoped for.

Jack Chen and Leszek Ślażyński have created an alternative in the form of the FuzzyAutocomplete plugin. It leverages the algorithm Xcode uses for its Open Quickly feature, which does an excellent job in terms of pattern matching. It works very, very well.

10. Dash for Xcode

Dash is an amazing piece of software for browsing documentation. I use it every single day. What I like even more is its integration with Xcode, thanks to its Xcode plugin. You probably know that you can Option-Click a symbol in Xcode's editor to go to the documentation. However, I'm not a big fan of Xcode's documentation browser and that's where the Dash plugin comes into play.

The plugin opens Dash instead of Xcode's documentation browser if you Option-Click a symbol. Not only is Dash very fast, it also integrates with CocoaDocs. If you for example Option-Click a method of the AFNetworking library, then Dash will show the documentation of that method. I love this feature.

Conclusion

Xcode's plugin architecture is one of the most undervalued aspects of Apple's popular IDE. It's not simple to create an Xcode plugin without proper documentation, but I encourage you to at least try out the plugins I've listed in this article. There are dozens of other Xcode plugins out there. Which plugins do you use to get your work done? Have you created one yourself?

2014-08-11T17:45:41.000Z2014-08-11T17:45:41.000ZBart Jacobs

10 Xcode Plugins for iOS Development

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-21899

A proper plugin architecture can mean all the difference for an integrated development environment. Sublime Text and TextMate are great examples. Did you know that Xcode also supports plugins? It wouldn't surprise me if you don't, Apple hasn't put much effort into advertising that part of Xcode. In fact, there is very little documentation available to create plugins for Xcode.

Fortunately, this hasn't stopped developers from creating plugins for Xcode. There is a wide range of plugins that make working with Xcode easier and more enjoyable, filling up the gaps Apple has left. In this quick tip, I will show you a few plugins I use on a daily basis.

Alcatraz

Installing Xcode plugins used to be a pain, but that's no longer the case with Alcatraz. Earlier this year, Alcatraz reached an important milestone, 1.0, and it's now compatible with Xcode 5. If you haven't installed Alcatraz yet, then I encourage you to do so first.

1. XcodeColors

XcodeColors is a plugin developed by Robbie Hanson that adds color to Xcode's console. This plugin is especially useful in combination with CocoaLumberjack, a wonderful logging library Robbie wrote. This combination has been a true lifesaver for me over the years, it has made debugging easier and more, well, colorful. Read this quick tip if you want to read more about XcodeColors and CocoaLumberjack.

2. XToDo

This plugin not only highlights TODO, FIXME, ???, and !!! comments, it also presents them in a convenient list.

3. Backlight

Some plugins may seem trivial or simple, but they are fantastic if you consider their value. Backlight is such a plugin. All it does, is highlight the line that's currently being edited. It's simple, but very helpful.

4. CocoaPods

CocoaPods is the de facto dependency manager for iOS and OS X development. If you're not using CocoaPods, then I encourage you to give it a try. This tutorial will get you started in less than ten minutes.

There's also a CocoaPods plugin for Xcode, which makes integrating CocoaPods even easier. The CocoaPods plugin adds a CocoaPods menu item to Xcode's Product menu. If you don't like the command line, then you'll certainly like this plugin.

5. ACCodeSnippetRepository

Like Xcode plugins, managing code snippets isn't trivial in Xcode. Arnaud Coomans shared this opinion and created a nifty plugin that synchronizes your Xcode code snippets with a git repository.

The beauty is that the code snippets you've manually added in Xcode are left untouched. Importing code snippets from a git repository only takes a few clicks. This is also a clever way to back up your code snippets or keep them in a central location if you use multiple machines.

6. GitDiff

A graphical user interface makes working with git less daunting for many developers. While applications like Tower and SourceTree are great, I often want to know what has changed in the file I'm currently working on, in Xcode's code editor. The GitDiff plugin makes this possible and it's great.

It's a subtle enhancement of Xcode's code editor, adding just enough visual information to know what has changed since the last commit.

7. KSImageNamed

Autocompletion is great, especially if you're writing Objective-C. Wouldn't it be great if Xcode autocompleted file names, such as the names of image files?

Kent Sutherland created the KSImageNamed plugin that does exactly that. Not only will it save you time, it will make sure that typos are a thing of the past.

8. Peckham

Adding import statements can be pesky sometimes. If you need to import a header of a pod, for example, then Xcode's autocompletion won't work for you. The Peckham plugin solves this issue.

Press Command-Control-P, type a few letters of the header you're looking for, and select it from the list of options presented by the plugin. It's a great addition to Xcode's autocomplete functionality.

9. FuzzyAutocomplete

Speaking of autocomplete, the majority of iOS and OS X developers have come to rely on Xcode's great autocomplete functionality. However, Xcode's implementation of autocomplete isn't perfect and you don't always get the suggestions you expected or hoped for.

Jack Chen and Leszek Ślażyński have created an alternative in the form of the FuzzyAutocomplete plugin. It leverages the algorithm Xcode uses for its Open Quickly feature, which does an excellent job in terms of pattern matching. It works very, very well.

10. Dash for Xcode

Dash is an amazing piece of software for browsing documentation. I use it every single day. What I like even more is its integration with Xcode, thanks to its Xcode plugin. You probably know that you can Option-Click a symbol in Xcode's editor to go to the documentation. However, I'm not a big fan of Xcode's documentation browser and that's where the Dash plugin comes into play.

The plugin opens Dash instead of Xcode's documentation browser if you Option-Click a symbol. Not only is Dash very fast, it also integrates with CocoaDocs. If you for example Option-Click a method of the AFNetworking library, then Dash will show the documentation of that method. I love this feature.

Conclusion

Xcode's plugin architecture is one of the most undervalued aspects of Apple's popular IDE. It's not simple to create an Xcode plugin without proper documentation, but I encourage you to at least try out the plugins I've listed in this article. There are dozens of other Xcode plugins out there. Which plugins do you use to get your work done? Have you created one yourself?

2014-08-11T17:45:41.000Z2014-08-11T17:45:41.000ZBart Jacobs

Getting Started with Xamarin.Forms: Basics

$
0
0

1. Setting the Stage

Ever since Xamarin came onto the stage several years ago, C# developers have been delighting in being able to create mobile applications that target non-Microsoft platforms. It's with quite a bit of excitement that we can now write apps in a language that is very familiar to us, and be able to distribute them to the big players in the mobile space, iOS and Android.

Since these apps can be written in a single language, it only makes sense to want to write a single code base that would compile into separate apps for the different platforms and ultimately allow us to reach the world of Write Once, Run Everywhere/Anywhere. This sounds good on paper, but it wasn't quite the case.

2. The Problem

The concept of writing an application a single time and being able to run it on several platforms is not a new one. Developers have been attempting to accomplish this for many years with desktop and server applications written in Java or C/C++, and compiled to the specific platforms. Why should mobile apps be any different? The simple answer is, they're not. As mobile app developers, we run into the same major cross-platform issues that others do, the user interface.

When it comes to writing any sort of software that you want to be able to run on different platforms, the easy part is the logic. By easy, I mean the part of the application that doesn't change regardless of the platform you're targeting. No matter what platform you're targeting, you'll still need to get data from services, databases, files, etc. Odds are that this will very rarely change. The part that does change is the UI. This is primarily due to the inherent differences of the various platforms. Each platform will have their own SDK, defining the platform's capabilities as well as their visual components and characteristics.

When looking at today's mobile landscape, you'll quickly find that there are three big players, iOS, Android, and Windows Phone. These three are in constant competition to try to one-up the others to gain more market share. But, for the foreseeable future, these are the platforms that you'll want to be targeting. The reason that cross-platform development on mobile can be difficult is due to the fundamental differences in terms of UI. A button is no longer just a button. A button is a UIButton with XML on iOS, a Button with AXML on Android, and a Button with XAML on Windows Phone.

3. The Workaround

As with most cross-platform frameworks, Xamarin has typically had a similar strategy when it comes to limiting the headache that the UI causes, split out the logic from the user interface.

In the world of C#, this strategy will typically leave you with at least N+1 projects within your solution. You will have at least one project for each of the N platforms you are targeting and you will also need to have at least one project that will contain all the shared code that the application relies on. That way, you can have the platform-specific projects simply reference the shared code project and only have to worry about how to visualize the data. Thanks to some new functionality in the .NET and Mono frameworks, you have a couple of options.

Option 1: Portable Class Libraries

Portable Class Libraries or PCLs came on the scene first. It's easiest to think of PCLs as normal class libraries, just with limited functionality. It's easier to understand this concept with an example. Start by creating a new solution/project and name it PCLDemo and select Class Library (Portable) as your project template.

When you click OK in Visual Studio, you'll see another window show up that looks similar to this:

Depending on the tools you have installed, it may look slightly different. In this screen, you have the ability to target as many or as few platforms as you wish. The rule of thumb here is to only choose the platforms that you absolutely need to target. The reason for this is that the more platforms you wish to target, the fewer features will be included in this library. For an up to date list of features supported by the different platforms, check out the Cross Platform Development with the Portable Class Library page on MSDN.

If you don't select the proper platforms in this dialog, you could run into incompatibility issues later. To see this in action, uncheck the bottom three options:

  • Windows Phone 8.1
  • Xamarin.Android
  • Xamarin.iOS

Now, create a new project of one of the types that you removed support from in the PCL. As an example, you could create a new Xamarin.Android project using any of the supplied templates. Once the project is created, right-click on References and select Add Reference. In the Reference Manager dialog, select Solution > Projects from the filter on the left and check the box next to the PCLDemo project.

When you click OK, you'll see an error like the following:

This error lets you know that the project you're currently in is incompatible with the targets available in the selected PCL. You can work around this by going into the PCL project properties and changing the targets. But remember, the more targets, the fewer the supported features.

Advantages of Portable Class Libraries

Even though there are a few things you need to watch out for when using PCLs, there are some very nice advantages.

  1. non-platform-specific code can be isolated in a separate project(s)
  2. unit testing of shared code is isolated in a separate project(s)
  3. shared code in PCLs can be shared with other applications via a compiled dll

Disadvantages of Portable Class Libraries

When choosing a new technology or platform to use, it also pays to understand the disadvantages that need to be addressed.

  1. feature sets are limited based on the targeted platforms
  2. PCLs can only add references to other PCLs that share the same target platforms
  3. PCLs can't contain any platform-specific code

If PCLs seem too limiting to you as a choice for shared code, there is another option.

Option 2: Shared Projects

In the recent release of Visual Studio 2013 Update 2, Microsoft added support for Shared Projects. Shared Projects are another way to share code between different platforms, in some ways similar to PCLs and in other ways drastically different. Let's start by creating a simple example.

Begin by creating another solution/project in Visual Studio and giving it a name of SharedDemo and selecting Shared Project (Empty) as your template.

If you don't see Shared Project (Empty) as an option, make sure that you have the latest version of Visual Studio 2013 Update 2. If you are using the latest version and still don't see it, you may need to install the Shared Project Reference Manager extension.

Once you click OK, Visual Studio will create a new project for you in the Solution Explorer, but it will look a little different than you're used to.

It seems a little lonely, huh? There's no Properties folder and no References folder. What's going on? That's the beauty and often the source of confusion for most developers. By default, a Shared Project doesn't really contain access to any functionality at all. There's some magic going on behind the scenes in Visual Studio/Xamarin Studio, but you will see that shortly.

Another strange feature of a Shared Project is that you can't actually build it. If you were to right-click the solution or project, you wouldn't see any options for building, running, or debugging this project. To understand why this is, you need to take a step back for a moment.

What's the purpose of building a project? The purpose is to transform your code from text into an actual file that can be used by the system you're running on or another application. That is why you can't actually build a Shared Project, no output file is generated by it. This specialized project has an entirely different purpose.

When you create a Shared Project and write code in it, you can add references to it from other projects as much as you want. There are no platforms to target or rules to follow. This is the first differentiator from PCLs.  Let's continue with an example. Create a new Xamarin.Android and/or Xamarin.iOS project in your solution and name them appropriately, SharedDemo.Android and/or SharedDemo.iOS.

Now that you have a new project, right-click the References folder and select Add Shared Project Reference. If you don't see this as an option, you may need to review adding the Shared Project Reference Manager extension.

From here, click OK and you should see something similar to this:

This is where the magic comes into play. The code contained with a Shared Project will be compiled into any projects that reference it. That is why you can't build them directly, they need something to reference them before they can be built and compiled. The fact that they can be added to any project as a reference is part of the reason they are such good candidates for cross-platform development.

The other reason they are good candidates for cross-platform development is their support for compiler directives. You can place checks for special directives within your Shared Projects so that only specific platforms get certain functionality or that things are handled differently on different platforms. The following directives can be found in platform projects:

  • __MOBILE__ Xamarin.Android and Xamarin.iOS projects
  • __IOS__ Xamarin.iOS projects
  • __ANDROID__ Xamarin.Android projects
  • __ANDROID_xx__  Xamarin.Android projects where xx is replaced by the targeted Android API version
  • WINDOWS_PHONE Windows Phone projects
  • SILVERLIGHT Windows Phone projects

You can use these directives inside #ifdef blocks to check which platform you're running on and use conditional compilation to only include what's needed in each project. This is all done for you by the compiler. Let's see an example.

In your SharedDemo project, add a new class named Recipe and replace the default implementation with the following:

public class Recipe
    {
        public string ShortName { get; set; }
#if __iOS__
        public string LongName { get; set; }
#endif
        public List<string> Ingredients { get; set; }
        public List<string> Directions { get; set; }
    }

This is a bit of a contrived example, but it serves to illustrate a simple point. Since I am referencing this code from a Xamarin.Android project, the Recipe class will only contain 3 properties, ShortName, Ingredients, and Directions. If this code was referenced by a Xamarin.iOS project, it would also contain the LongName property.

You're more likely to use these directives in situations where you run into platform divergence. Common areas of divergence on these mobile platforms have to do with accessing hardware, the file system, etc. You can now place platform code in the Shared Project divided by the directives and Visual Studio will handle the platform-specific compilation to the proper projects. Very nice.

Advantages of Shared Projects

Shared Projects contain some very nice features that assist in the creation of cross-platform projects.

  1. non-platform and platform-specific code can exist in one project
  2. have access to libraries and features of parent project
  3. support directives for separating platform-specific code

Disadvantages of Shared Projects

While Shared Projects have nice features, there are a few not so desirable characteristics.

  1. no dll is created, so code can't be shared in other solutions
  2. only have access to libraries in parent project, so non-platform-specific unit test projects can be difficult
  3. can't reference other projects or libraries

4. Enter Xamarin.Forms

You're now aware of the basic strategies for sharing your app logic. It's time to start looking at your app's user interface. In the most recent release of version 3 of Xamarin, one of the most exciting features is the introduction of Xamarin.Forms. Xamarin.Forms is a library that contains abstractions of typical UI controls that comprise your app's UI. When these controls are used on the specific platforms, they are mapped to render native UI controls so that you get the look and feel of native components.

The basic structure of your cross-platform application doesn't change. You will still be following the N+1 rule as far as projects are concerned, but you'll now be moving your platform-specific UI code from the platform-specific projects into the Shared Projects. Before we get too ahead of ourselves, we need to understand the needs and requirements of not only running, but developing Xamarin.Forms apps.

Requirements

There are a couple of requirements if you want to take full advantage of Xamarin.Forms. To use Xamarin.Forms, your app must be targeting the following platforms:

  • iOS 6.1+
  • Android 4.0+
  • Windows Phone 8

This means that if you plan to target some of the older versions of these platforms, you won't be able to use Xamarin.Forms. In addition to target platform restrictions, there are also a few development system requirements.

OS X

  • Xamarin 5 is required to use Xamarin.Forms on OS X.
  • To develop iOS apps, Xcode and OS X 10.8+ is needed.
  • Windows Phone apps can only be developed on a Windows machine.

Windows

  • You'll need Visual Studio 2012 or newer.
  • To use the PCL version of Xamarin.Forms, you need to use PCL Profile 78, which includes support for .NET Framework 4.5+, Windows Phone 8 or later, Windows 8, Windows Phone Silverlight 8, Windows Store apps (Windows 8), Xamarin.Android, and Xamarin.iOS.
  • It speaks for itself that you'll also need the Windows Phone SDK.
  • To develop iOS apps, you'll need Xcode and a Mac running OS X. This is a requirement for all Xamarin.iOS apps created using a Windows machine.

Once you have everything downloaded and configured, you are ready to get started.

5. Building Blocks

The basic idea behind Xamarin.Forms is simple, you refer to common UI controls in the same way regardless of the platforms that you're targeting. A button is a button is a button. You'll create these controls and give them visual characteristics and functionality. You'll then use a Layout to position the controls on the screen and display everything on a Page. If you're used to using platform-specific terminology to describe the UI components of your apps, getting used to the new terms may take some time. Luckily, there are only a few concepts to understand.

Pages

In Xamarin.Forms, Pages represent the actual screens of your application. With respect to other platforms, a Page is an Activity on Android, a UIViewController on iOS, and a Page on Windows Phone. The Page is the main object that you will be dealing with when you're working with transitions and navigation. Also, a Page contains only a single child, which in most situations is some type of Layout.

Layouts

Layouts are controls used to organize UI components on your Page in a logical way. Within a Layout, you can set characteristics of the UI controls, such as position and size. You can add any number of UI components to a layout including controls and other Layout objects.

Views

In Xamarin.Forms, Views are what you would commonly refer to as controls. Common View objects in Xamarin.Forms are Button, Label, and ListView, to name a few. The Layout class actually inherits from the View class, which means that they can be treated the same way and added to Layout objects.

Cells

Cells are specialized UI components used to customize what would typically be referred to as rows within ListView and UITableView objects. There are pre-built Cell types to add a number of different customizations to your View objects.

6. Creating a Basic Application

To create a basic Xamarin.Forms application, open Visual Studio, select File > New Project, select the Mobile Apps category, and choose the appropriate template. I've chosen the Blank App (Xamarin.Forms Shared) template. This will create a Xamarin.Forms application using the Shared Project template.

After clicking OK, your solution will be created with four projects. As discussed before, you will have three platform-specific projects and one Shared Project. The Shared Project contains the application logic as well as all the Xamarin.Forms code that will be in charge of creating the screens (Page objects) of your application.

If you open the SampleFormsApp project, you will see a single class named App.cs. This is the main file of the project that contains the Page definitions that will ultimately appear on the target platforms. It's a simple class that only contains the following:

public class App
{
	public static Page GetMainPage()
	{
		return new ContentPage
		{
			Content = new Label {
				Text = "Hello, Forms !",
				VerticalOptions = LayoutOptions.CenterAndExpand,
				HorizontalOptions = LayoutOptions.CenterAndExpand,
			},
		};
	}
}

The class App is quite simple in that it only contains a single static method that returns a ContentPage object. A ContentPage object is the most basic, no-frills Page that you can create. It's easiest to think of a ContentPage as a blank canvas that you can do anything you want with. There is very little functionality built into it.

You'll typically find that most Page objects have a Content property that allows you to assign View object to it. In this case, it's a simple Label view that prints "Hello, Forms !" to the screen while giving it some basic formatting for centering it.

To get this ContentPage to load on every platform that we're targeting, there's some custom platform-specific code that needs to be included in each of the platform projects. Let's take a look at the iOS project first. Open the SampleFormsApp.iOS project and take a look at the AppDelegate.cs file. This is the file that contains the wiring into the Xamarin.Forms world.

public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
    Forms.Init();

    window = new UIWindow(UIScreen.MainScreen.Bounds);

    window.RootViewController = App.GetMainPage().CreateViewController();

    window.MakeKeyAndVisible();

    return true;
}

First, we initialize the Xamarin.Forms library with by invoking Forms.Init(). After that, the only custom code is setting the window.RootViewController property to the result of the App.GetMainPage().CreateViewController() call. That line will launch into the Xamarin.Forms world and everything from that point continues to use Xamarin.Forms.

The process for initializing Xamarin.Forms in Android and Windows Phone is very similar. You will call the Init method and set the initial Page to be the result of the App.GetMainPage() method. This is what it looks like in the SampleFormsApp.Android project in the MainActivity.OnCreate method.

protected override void OnCreate(Bundle bundle)
{
    base.OnCreate(bundle);

    Xamarin.Forms.Forms.Init(this, bundle);

    SetPage(App.GetMainPage());
}

And in the SampleFormsApp.WinPhone project in the MainPage constructor of the partial class MainPage:

public MainPage()
{
    InitializeComponent();

    Forms.Init();
    Content = SampleFormsApp.App.GetMainPage().ConvertPageToUIElement(this);
}

Conclusion

You should now have a basic understanding of Xamarin.Forms as well as what you can accomplish using them. The journey into this amazing technology doesn't stop there. You will have another choice ahead of you when using Xamarin.Forms, which has to do with layout. And that is precisely what will be covered in the next tutorial.

2014-08-13T17:45:09.000Z2014-08-13T17:45:09.000ZDerek Jensen

Getting Started with Xamarin.Forms: Basics

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-21564

1. Setting the Stage

Ever since Xamarin came onto the stage several years ago, C# developers have been delighting in being able to create mobile applications that target non-Microsoft platforms. It's with quite a bit of excitement that we can now write apps in a language that is very familiar to us, and be able to distribute them to the big players in the mobile space, iOS and Android.

Since these apps can be written in a single language, it only makes sense to want to write a single code base that would compile into separate apps for the different platforms and ultimately allow us to reach the world of Write Once, Run Everywhere/Anywhere. This sounds good on paper, but it wasn't quite the case.

2. The Problem

The concept of writing an application a single time and being able to run it on several platforms is not a new one. Developers have been attempting to accomplish this for many years with desktop and server applications written in Java or C/C++, and compiled to the specific platforms. Why should mobile apps be any different? The simple answer is, they're not. As mobile app developers, we run into the same major cross-platform issues that others do, the user interface.

When it comes to writing any sort of software that you want to be able to run on different platforms, the easy part is the logic. By easy, I mean the part of the application that doesn't change regardless of the platform you're targeting. No matter what platform you're targeting, you'll still need to get data from services, databases, files, etc. Odds are that this will very rarely change. The part that does change is the UI. This is primarily due to the inherent differences of the various platforms. Each platform will have their own SDK, defining the platform's capabilities as well as their visual components and characteristics.

When looking at today's mobile landscape, you'll quickly find that there are three big players, iOS, Android, and Windows Phone. These three are in constant competition to try to one-up the others to gain more market share. But, for the foreseeable future, these are the platforms that you'll want to be targeting. The reason that cross-platform development on mobile can be difficult is due to the fundamental differences in terms of UI. A button is no longer just a button. A button is a UIButton with XML on iOS, a Button with AXML on Android, and a Button with XAML on Windows Phone.

3. The Workaround

As with most cross-platform frameworks, Xamarin has typically had a similar strategy when it comes to limiting the headache that the UI causes, split out the logic from the user interface.

In the world of C#, this strategy will typically leave you with at least N+1 projects within your solution. You will have at least one project for each of the N platforms you are targeting and you will also need to have at least one project that will contain all the shared code that the application relies on. That way, you can have the platform-specific projects simply reference the shared code project and only have to worry about how to visualize the data. Thanks to some new functionality in the .NET and Mono frameworks, you have a couple of options.

Option 1: Portable Class Libraries

Portable Class Libraries or PCLs came on the scene first. It's easiest to think of PCLs as normal class libraries, just with limited functionality. It's easier to understand this concept with an example. Start by creating a new solution/project and name it PCLDemo and select Class Library (Portable) as your project template.

When you click OK in Visual Studio, you'll see another window show up that looks similar to this:

Depending on the tools you have installed, it may look slightly different. In this screen, you have the ability to target as many or as few platforms as you wish. The rule of thumb here is to only choose the platforms that you absolutely need to target. The reason for this is that the more platforms you wish to target, the fewer features will be included in this library. For an up to date list of features supported by the different platforms, check out the Cross Platform Development with the Portable Class Library page on MSDN.

If you don't select the proper platforms in this dialog, you could run into incompatibility issues later. To see this in action, uncheck the bottom three options:

  • Windows Phone 8.1
  • Xamarin.Android
  • Xamarin.iOS

Now, create a new project of one of the types that you removed support from in the PCL. As an example, you could create a new Xamarin.Android project using any of the supplied templates. Once the project is created, right-click on References and select Add Reference. In the Reference Manager dialog, select Solution > Projects from the filter on the left and check the box next to the PCLDemo project.

When you click OK, you'll see an error like the following:

This error lets you know that the project you're currently in is incompatible with the targets available in the selected PCL. You can work around this by going into the PCL project properties and changing the targets. But remember, the more targets, the fewer the supported features.

Advantages of Portable Class Libraries

Even though there are a few things you need to watch out for when using PCLs, there are some very nice advantages.

  1. non-platform-specific code can be isolated in a separate project(s)
  2. unit testing of shared code is isolated in a separate project(s)
  3. shared code in PCLs can be shared with other applications via a compiled dll

Disadvantages of Portable Class Libraries

When choosing a new technology or platform to use, it also pays to understand the disadvantages that need to be addressed.

  1. feature sets are limited based on the targeted platforms
  2. PCLs can only add references to other PCLs that share the same target platforms
  3. PCLs can't contain any platform-specific code

If PCLs seem too limiting to you as a choice for shared code, there is another option.

Option 2: Shared Projects

In the recent release of Visual Studio 2013 Update 2, Microsoft added support for Shared Projects. Shared Projects are another way to share code between different platforms, in some ways similar to PCLs and in other ways drastically different. Let's start by creating a simple example.

Begin by creating another solution/project in Visual Studio and giving it a name of SharedDemo and selecting Shared Project (Empty) as your template.

If you don't see Shared Project (Empty) as an option, make sure that you have the latest version of Visual Studio 2013 Update 2. If you are using the latest version and still don't see it, you may need to install the Shared Project Reference Manager extension.

Once you click OK, Visual Studio will create a new project for you in the Solution Explorer, but it will look a little different than you're used to.

It seems a little lonely, huh? There's no Properties folder and no References folder. What's going on? That's the beauty and often the source of confusion for most developers. By default, a Shared Project doesn't really contain access to any functionality at all. There's some magic going on behind the scenes in Visual Studio/Xamarin Studio, but you will see that shortly.

Another strange feature of a Shared Project is that you can't actually build it. If you were to right-click the solution or project, you wouldn't see any options for building, running, or debugging this project. To understand why this is, you need to take a step back for a moment.

What's the purpose of building a project? The purpose is to transform your code from text into an actual file that can be used by the system you're running on or another application. That is why you can't actually build a Shared Project, no output file is generated by it. This specialized project has an entirely different purpose.

When you create a Shared Project and write code in it, you can add references to it from other projects as much as you want. There are no platforms to target or rules to follow. This is the first differentiator from PCLs.  Let's continue with an example. Create a new Xamarin.Android and/or Xamarin.iOS project in your solution and name them appropriately, SharedDemo.Android and/or SharedDemo.iOS.

Now that you have a new project, right-click the References folder and select Add Shared Project Reference. If you don't see this as an option, you may need to review adding the Shared Project Reference Manager extension.

From here, click OK and you should see something similar to this:

This is where the magic comes into play. The code contained with a Shared Project will be compiled into any projects that reference it. That is why you can't build them directly, they need something to reference them before they can be built and compiled. The fact that they can be added to any project as a reference is part of the reason they are such good candidates for cross-platform development.

The other reason they are good candidates for cross-platform development is their support for compiler directives. You can place checks for special directives within your Shared Projects so that only specific platforms get certain functionality or that things are handled differently on different platforms. The following directives can be found in platform projects:

  • __MOBILE__ Xamarin.Android and Xamarin.iOS projects
  • __IOS__ Xamarin.iOS projects
  • __ANDROID__ Xamarin.Android projects
  • __ANDROID_xx__  Xamarin.Android projects where xx is replaced by the targeted Android API version
  • WINDOWS_PHONE Windows Phone projects
  • SILVERLIGHT Windows Phone projects

You can use these directives inside #ifdef blocks to check which platform you're running on and use conditional compilation to only include what's needed in each project. This is all done for you by the compiler. Let's see an example.

In your SharedDemo project, add a new class named Recipe and replace the default implementation with the following:

public class Recipe
    {
        public string ShortName { get; set; }
#if __iOS__
        public string LongName { get; set; }
#endif
        public List<string> Ingredients { get; set; }
        public List<string> Directions { get; set; }
    }

This is a bit of a contrived example, but it serves to illustrate a simple point. Since I am referencing this code from a Xamarin.Android project, the Recipe class will only contain 3 properties, ShortName, Ingredients, and Directions. If this code was referenced by a Xamarin.iOS project, it would also contain the LongName property.

You're more likely to use these directives in situations where you run into platform divergence. Common areas of divergence on these mobile platforms have to do with accessing hardware, the file system, etc. You can now place platform code in the Shared Project divided by the directives and Visual Studio will handle the platform-specific compilation to the proper projects. Very nice.

Advantages of Shared Projects

Shared Projects contain some very nice features that assist in the creation of cross-platform projects.

  1. non-platform and platform-specific code can exist in one project
  2. have access to libraries and features of parent project
  3. support directives for separating platform-specific code

Disadvantages of Shared Projects

While Shared Projects have nice features, there are a few not so desirable characteristics.

  1. no dll is created, so code can't be shared in other solutions
  2. only have access to libraries in parent project, so non-platform-specific unit test projects can be difficult
  3. can't reference other projects or libraries

4. Enter Xamarin.Forms

You're now aware of the basic strategies for sharing your app logic. It's time to start looking at your app's user interface. In the most recent release of version 3 of Xamarin, one of the most exciting features is the introduction of Xamarin.Forms. Xamarin.Forms is a library that contains abstractions of typical UI controls that comprise your app's UI. When these controls are used on the specific platforms, they are mapped to render native UI controls so that you get the look and feel of native components.

The basic structure of your cross-platform application doesn't change. You will still be following the N+1 rule as far as projects are concerned, but you'll now be moving your platform-specific UI code from the platform-specific projects into the Shared Projects. Before we get too ahead of ourselves, we need to understand the needs and requirements of not only running, but developing Xamarin.Forms apps.

Requirements

There are a couple of requirements if you want to take full advantage of Xamarin.Forms. To use Xamarin.Forms, your app must be targeting the following platforms:

  • iOS 6.1+
  • Android 4.0+
  • Windows Phone 8

This means that if you plan to target some of the older versions of these platforms, you won't be able to use Xamarin.Forms. In addition to target platform restrictions, there are also a few development system requirements.

OS X

  • Xamarin 5 is required to use Xamarin.Forms on OS X.
  • To develop iOS apps, Xcode and OS X 10.8+ is needed.
  • Windows Phone apps can only be developed on a Windows machine.

Windows

  • You'll need Visual Studio 2012 or newer.
  • To use the PCL version of Xamarin.Forms, you need to use PCL Profile 78, which includes support for .NET Framework 4.5+, Windows Phone 8 or later, Windows 8, Windows Phone Silverlight 8, Windows Store apps (Windows 8), Xamarin.Android, and Xamarin.iOS.
  • It speaks for itself that you'll also need the Windows Phone SDK.
  • To develop iOS apps, you'll need Xcode and a Mac running OS X. This is a requirement for all Xamarin.iOS apps created using a Windows machine.

Once you have everything downloaded and configured, you are ready to get started.

5. Building Blocks

The basic idea behind Xamarin.Forms is simple, you refer to common UI controls in the same way regardless of the platforms that you're targeting. A button is a button is a button. You'll create these controls and give them visual characteristics and functionality. You'll then use a Layout to position the controls on the screen and display everything on a Page. If you're used to using platform-specific terminology to describe the UI components of your apps, getting used to the new terms may take some time. Luckily, there are only a few concepts to understand.

Pages

In Xamarin.Forms, Pages represent the actual screens of your application. With respect to other platforms, a Page is an Activity on Android, a UIViewController on iOS, and a Page on Windows Phone. The Page is the main object that you will be dealing with when you're working with transitions and navigation. Also, a Page contains only a single child, which in most situations is some type of Layout.

Layouts

Layouts are controls used to organize UI components on your Page in a logical way. Within a Layout, you can set characteristics of the UI controls, such as position and size. You can add any number of UI components to a layout including controls and other Layout objects.

Views

In Xamarin.Forms, Views are what you would commonly refer to as controls. Common View objects in Xamarin.Forms are Button, Label, and ListView, to name a few. The Layout class actually inherits from the View class, which means that they can be treated the same way and added to Layout objects.

Cells

Cells are specialized UI components used to customize what would typically be referred to as rows within ListView and UITableView objects. There are pre-built Cell types to add a number of different customizations to your View objects.

6. Creating a Basic Application

To create a basic Xamarin.Forms application, open Visual Studio, select File > New Project, select the Mobile Apps category, and choose the appropriate template. I've chosen the Blank App (Xamarin.Forms Shared) template. This will create a Xamarin.Forms application using the Shared Project template.

After clicking OK, your solution will be created with four projects. As discussed before, you will have three platform-specific projects and one Shared Project. The Shared Project contains the application logic as well as all the Xamarin.Forms code that will be in charge of creating the screens (Page objects) of your application.

If you open the SampleFormsApp project, you will see a single class named App.cs. This is the main file of the project that contains the Page definitions that will ultimately appear on the target platforms. It's a simple class that only contains the following:

public class App
{
	public static Page GetMainPage()
	{
		return new ContentPage
		{
			Content = new Label {
				Text = "Hello, Forms !",
				VerticalOptions = LayoutOptions.CenterAndExpand,
				HorizontalOptions = LayoutOptions.CenterAndExpand,
			},
		};
	}
}

The class App is quite simple in that it only contains a single static method that returns a ContentPage object. A ContentPage object is the most basic, no-frills Page that you can create. It's easiest to think of a ContentPage as a blank canvas that you can do anything you want with. There is very little functionality built into it.

You'll typically find that most Page objects have a Content property that allows you to assign View object to it. In this case, it's a simple Label view that prints "Hello, Forms !" to the screen while giving it some basic formatting for centering it.

To get this ContentPage to load on every platform that we're targeting, there's some custom platform-specific code that needs to be included in each of the platform projects. Let's take a look at the iOS project first. Open the SampleFormsApp.iOS project and take a look at the AppDelegate.cs file. This is the file that contains the wiring into the Xamarin.Forms world.

public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
    Forms.Init();

    window = new UIWindow(UIScreen.MainScreen.Bounds);

    window.RootViewController = App.GetMainPage().CreateViewController();

    window.MakeKeyAndVisible();

    return true;
}

First, we initialize the Xamarin.Forms library with by invoking Forms.Init(). After that, the only custom code is setting the window.RootViewController property to the result of the App.GetMainPage().CreateViewController() call. That line will launch into the Xamarin.Forms world and everything from that point continues to use Xamarin.Forms.

The process for initializing Xamarin.Forms in Android and Windows Phone is very similar. You will call the Init method and set the initial Page to be the result of the App.GetMainPage() method. This is what it looks like in the SampleFormsApp.Android project in the MainActivity.OnCreate method.

protected override void OnCreate(Bundle bundle)
{
    base.OnCreate(bundle);

    Xamarin.Forms.Forms.Init(this, bundle);

    SetPage(App.GetMainPage());
}

And in the SampleFormsApp.WinPhone project in the MainPage constructor of the partial class MainPage:

public MainPage()
{
    InitializeComponent();

    Forms.Init();
    Content = SampleFormsApp.App.GetMainPage().ConvertPageToUIElement(this);
}

Conclusion

You should now have a basic understanding of Xamarin.Forms as well as what you can accomplish using them. The journey into this amazing technology doesn't stop there. You will have another choice ahead of you when using Xamarin.Forms, which has to do with layout. And that is precisely what will be covered in the next tutorial.

2014-08-13T17:45:09.000Z2014-08-13T17:45:09.000ZDerek Jensen

Setting Up Push Notifications on iOS

$
0
0

Introduction

Apple originally introduced push notifications to enable applications to respond to events if the application isn't running in the foreground. However, the operating system and iOS devices have changed significantly during the past few years and applications don't need to rely solely on push notifications to perform tasks in the background.

This doesn't mean that push notifications are no longer useful though. Push notifications are great to notify an application about important events and to keep your application's users engaged. Also, don't forget that an application still isn't allowed to run in the background without restrictions. In other words, the original purpose of push notifications is still valid.

Even the most experienced iOS developers scratch their heads from time to time when they have to deal with application provisioning. Unfortunately, push notifications add to this complexity. With this tutorial, I hope to show you that setting up push notifications shouldn't be a nightmare. Follow along and I promise that you'll be sending push notifications in no time.

1. Prerequisites

You'll need two things if you'd like to follow along with me. The first thing you need is a physical device to receive push notifications, because the iOS Simulator doesn't support push notifications. The second thing you need is a paid iOS developer account. Only paid accounts can provision applications to run on a physical device.

2. Project Setup

The goal of this tutorial is to build an application that is set up to receive push notifications. Open Xcode and create a new project based on the Single View Application template.

Name the project Push, enter a company identifier and class prefix, and set Devices to iPhone.

3. Registration

Even though I won't discuss the nitty-gritty backend infrastructure of push notifications, it's important that you know and understand what your application needs to do to receive push notifications and why it does this.

Open TSPAppDelegate.m and update the application:didFinishLaunchingWithOptions: as shown below. We call registerForRemoteNotificationTypes: on the application object, passing in the notification types that we're interested in. The operating system now knows that the application is interested in receiving push notifications.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Register for Remote Notifications
    [application registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound)];
    return YES;
}

The operating system contacts Apple's servers and obtains a device token to uniquely identify the device the application is running on. This device token is used by your server infrastructure to send push notifications. It does this by sending the device token along with the actual push notification to Apple's servers. Apple's servers are in charge of distributing the push notifications to the appropriate devices.

Note that the device token differs for each application and it can even change over time for the same application. Apple therefore recommends to ask for a device token every time the application is launched and send the device token to your backend to make sure the device token is up to date.

If you're using a service like Parse or Urban Airship, then this is something you don't need to worry about. In that case, you only need to send the backend the device token iOS hands you.

The methods that tell your application whether registering for remote notifications is successful or not are application:didRegisterForRemoteNotificationsWithDeviceToken: and application:didFailToRegisterForRemoteNotificationsWithError: respectively. For now, implement these methods as shown below.

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    NSLog(@"Did Register for Remote Notifications with Device Token (%@)", deviceToken);
}
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
    NSLog(@"Did Fail to Register for Remote Notifications");
    NSLog(@"%@, %@", error, error.localizedDescription);
}

Both methods are declared by the UIApplicationDelegate protocol. This protocol also declares another method, application:didReceiveRemoteNotification:, which is invoked when the application receives a remote notification. It's up to you to handle any incoming push notifications. The application:didReceiveRemoteNotification: method hands you the payload of the push notification as an NSDictionary object. Your application needs to decide how it should respond to the push notification.

If you run your application, then the application:didFailToRegisterForRemoteNotificationsWithError: method will be invoked. This isn't surprising since we haven't finished setting up our application for push notifications. As a reminder, remote notifications are not supported by the iOS Simulator. You'll need a physical device to complete this tutorial.

4. SSL Certificate

To complete the next step, you need to sign into your iOS developer account at Apple's iOS Dev Center. Choose Identifiers from the iOS Apps sections.

Click the plus button in the top right and enter an App ID Description. This helps you identify the App ID later.

You can leave the App ID Prefix as is, but the App ID Suffix needs to be set to Explicit App ID, instead of Wildcard App ID. If you want an application to receive remote notifications, then you need to use an Explicit App ID, such as com.tutsplus.push, instead of com.tutsplus.*.

In the section App Services, enable Push Notifications. Click Continue to submit the form and click Submit to create the App ID.

From the list of App IDs, select the one you just created and click the Edit button below it. Scroll down until you see the section that covers push notifications. You should see two buttons labeled Create Certificate... as shown below.

As I mentioned earlier, your backend communicates with Apple's servers to send remote notifications to your application. Your backend sends remote notifications to your application via Apple's servers. For this reason, Apple needs to know that only your servers can connect with their servers. You don't want someone else to send remote notifications to your application.

Apple therefore requires you to create an SSL certificate. Many developers cringe at the words "certificates" and "provisioning", but it's really not that difficult. Follow along and you'll be ready in less than two minutes.

Open Keychain Access on your development machine and select Certificate Assistant > Request a Certificate From a Certificate Authority... from the Keychain Access menu. Double-check that no key is selected in Keychain Access when you select this option.

Enter an email address and a Common Name to identify the certificate later. Leave the CA Email field empty and select Saved to disk. Click Continue and save the certificate signing request to your hard drive.

You have created a few things by completing this step. You've created a certificate signing request as well as a public and private key. The keys should be visible in Keychain Access as shown below.

Head back to the iOS Dev Center and click the Create Certificate... button that we saw earlier. Apple tells you which steps you need to take to create the certificate signing request, but we've already completed those. Click Continue, upload the certificate signing request by clicking the Choose File... button, and hit Generate to generate the SSL certificate.

As Apple instructs, download the certificate and double-click it to install it in Keychain Access. Double-check that the certificate is added to Keychain Access and linked to the correct private key.

The next step, application provisioning, is something that trips up many developers. Let me walk you through it.

5. Application Provisioning

Before we can test our push notifications setup, we need to create a provisioning profile for our application. In the iOS Dev Center, select Development in the Provisioning Profiles section. Click the plus button in the top right and select iOS App Development under the Development section.

Click Continue and select your App ID from the list. Select the certificates you want to include in the provisioning profile and click Continue. Because we're creating a provisioning profile for development, we also need to specify which devices need to be included in the provisioning profile. Make sure your test device is included. Give the provisioning profile a sensible name and click Generate.

Download the provisioning profile and drag it in Xcode to add it. Update your target's build settings in Xcode to use the new provisioning profile. Build and run your application to make sure that everything works as expected.

If you run into issues, then double-check that the bundle identifier of your application matches that of the App ID. Note that a bundle identifier is case sensitive.

If you've followed the steps outlined in this tutorial, your application should prompt you with the following message.

If you tap OK, your application will ask the operating system for a device token. If this is successful, the application:didRegisterForRemoteNotificationsWithDeviceToken: method of the UIApplicationDelegate protocol is invoked, handing you the device token. Because we added a log statement to this method, the device token should also be logged to the console in Xcode.

Push[2182:60b] Did Register for Remote Notifications with Device Token (<131cec1a 64cf8f4c 80009196 6157311d c774df92 056c74c2 e5538e52 db4848f1>)

6. Sending Push Notifications

To test if any push notifications you send arrive, you need to have a backend in place that your application can send the device token to. That backend can then connect with Apple's servers to send push notifications.

I won't cover this aspect of push notifications in this tutorial, but this is the easy part of push notifications, especially if you're using a service like Parse or Urban Airship.

You can also use Houston, a Ruby gem developed by Mattt Thompson, which makes sending push notifications very easy.

Conclusion

I hope this tutorial has shown you that push notifications aren't as difficult to set up as most developers think. It's true that it takes a bit of fiddling with keys and certificates, but once you understand the moving parts, then it's not that difficult to understand and set up.

The truth is that the hard part is creating keys and certificates. Handling push notifications in your iOS application is very easy and straightforward.

2014-08-15T16:05:15.588Z2014-08-15T16:05:15.588ZBart Jacobs

Windows Phone 8: Platform Overview

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/mobile-20387

Developing mobile applications for Microsoft's Windows Phone platform is a straightforward process with many tools available to developers. In fact, the mobile team at Microsoft did a great job with the Windows Phone platform by taking a completely unique approach in several aspects. This article is the first installment of a series on getting started with Windows Phone development. In this tutorial, I cover the platform's most compelling features, common development techniques as well as third party tools you can use for developing Windows Phone applications.


About the Series

This tutorial is the first installment of a series covering Windows Phone development. In this tutorial, you'll learn about the Windows Phone platform, a general overview as well as the platform's core features. As the series moves forward, you will also learn about application structure and other essential aspects of the platform to enable you to build simple and useful applications.

Network interaction, interface design, and data binding are some of the topics we'll cover. At the end of this series, you should be able to create a basic, functional Windows Phone application, have a good grasp of the Windows Phone platform and its capabilities, and know quite a bit about several third party tools and online resources.


A Bit of History

I'd like to start this series with a brief overview of the platform's history. Windows Phone 8 is the latest public release of the platform and succeeds versions 7.1 and 7.8, commonly referred to as Windows Phone 7. The Windows Phone platform is Microsoft's attempt to revolutionize the mobile space and it's the successor to the Windows Mobile platform.

While Windows Mobile was unable to compete with the current market leaders, iOS and Android, Windows Phone has what it takes to get a foothold in the mobile space and change it for the better.


Why Windows Phone?

The mobile space is a multibillion dollar industry with, at the time of writing, two dominant players, Apple with iOS and Google with Android. Even though Windows Phone isn't in the same league with Apple and Google, the release of Windows Phone 8 has significantly helped to increase the Windows Phone market share.

Windows Phone is considered the third horse in the mobile race and many think of Microsoft as a serious competitor, especially with the acquisition of Nokia's mobile division. The question remains why you should consider developing mobile applications for the Windows Phone ecosystem.

First, Microsoft has made it very easy to port Windows Phone applications to its Windows 8 operating system. The two operating systems share a lot of common libraries and it's perfectly possible to develop an application that targets both Windows Phone and Windows 8 using a single code base.

Porting applications from Windows Phone to Windows 8, and vice versa, is another option to consider. This option is particularly attractive to game developers as they can reuse components written for either of the Windows platforms.

Second, the tools for developing Windows Phone applications are great and so is the Windows Phone community. The development tools of the Windows Phone platform are arguably among the best tested and most robust available to developers.

Many developers already have experience with the toolchain for developing Windows Phone applications. Visual Studio is the preferred IDE (Integrated Development Environment) for Windows Phone development and it's a joy to use. It has built-in support for version control, code analysis, TDD (Test Driven Development), and even UML (Unified Modeling Language) diagram generation.

The SDK to develop Windows Phone applications is free to download and registering for a developer account isn't expensive.


Developing for Windows Phone

Developing mobile applications for the Windows Phone platform comes with a certain degree of flexibility. You can, for example, create Windows Phone applications using a number of programming languages, which I will talk about shortly.

Developers with a background in C++, C#, Silverlight, JavaScript, ASP.NET, or even Visual Basic (or VBA) will find it easy to get started with Windows Phone development.

Even developers coming from Java or other mobile platforms, such as Android, will be surprised by the soft learning curve. Let's take a quick look at the options you have with regards to developing mobile applications for the Windows Phone platform.

Silverlight

The first and most popular approach is the Silverlight framework. Silverlight alongside Visual Basic or most commonly C#, is the preferred way to develop Windows Phone applications.

When using this approach, user interface elements are represented in XAML, a flavor of XML created by Microsoft and used in .Net technologies like Windows Presentation Foundation (WPF) and Silverlight. Compared to, for example, web applications, you can think of XAML as the HTML equivalent and Visual Basic or C# as the JavaScript counterpart.

Most of the resources for Windows Phone development as well as Microsoft's official documentation showcase this approach and it's also the path that we will be taking in the rest of this series.

PhoneGap

Another popular approach is to use PhoneGap, a free framework for creating cross-platform applications using HTML5, CSS, and JavaScript. PhoneGap, or the open-source Apache Cordova, is a set of APIs that gives developers easy access to native device capabilities, such as the device's sensors and camera, through JavaScript.

With PhoneGap, developers with a web development background can create Windows Phone applications without the need to write native code. The most important advantage of PhoneGap, however, is that the framework is platform agnostic. This means that you can use one code base to write mobile applications for multiple platforms, such as Windows Phone, iOS, and Android.

XNA Framework

Microsoft's XNA (XNA's Not Acronymed) framework can also be leveraged to create Windows Phone applications. However, it's important to know that XNA is aimed at game development. Since game development isn't the primary focus of this series, we won't be exploring XNA in much detail. If you'd like to know more about XNA, I encourage you to read Nick Ohrn's tutorial about XNA on Tuts+.

C++

The last option you have is writing native C++. This approach is commonly used by game developers who are looking for performance or are already using other resources written in C++.

A lot of game developers choose for C++ because of the portability of the language to other platforms. These applications make heavy use of Direct3D, the graphical component of Microsoft's DirectX API, which requires C++. If game development is your main focus, then this is an option to consider.


Development Tools

As I mentioned earlier, the tools for developing Windows Phone applications are robust and free. The IDE (Integrated Development Environment) used to develop Windows Phone applications is Visual Studio. The Express edition is free and ships with the Windows Phone 8 SDK. The latter also includes an emulator that supports the three screen resolutions available to Windows Phone devices.

Another tool worth mentioning is Blend for Visual Studio, a user interface design tool for creating graphical interfaces for applications. Blend makes the design process of Windows Phone applications much easier and it integrates nicely with Visual Studio. We won't cover Blend in this series though.


Platform Features

Windows Phone 8 has every feature you expect from a modern mobile platform and more, such as NFC (Near Field Communication), Wallet, Storage, Camera, Maps, Push Notifications, and, one of its most notable features, Live Tiles.

Windows Phone 8 Homepage With Pinned Live Tiles

Another unique feature of Windows Phone is its design language. The Panorama and Pivot layout patterns are among the most commonly used design patterns on Windows Phone. I encourage you to take some time to familiarize yourself with the Windows Phone design guidelines to make sure that the applications you develop seamlessly blend in on the platform.



Resources

There are a few things I'd like to mention that can help you get started with Windows Phone development. The first is a website named CodePlex, a platform for hosting open source software, managed by Microsoft.

CodePlex hosts many libraries and tools that can save you time when developing Windows Phone applications. Signing up for CodePlex is free and I suggest you create an account to start exploring what CodePlex has to offer. A number of well-known projects are hosted on CodePlex, such as Coding4Fun, Json.NET, and HTML Agility Pack.

I also recommend browsing Microsoft's official documentation and code samples on the Windows Phone Dev Center. Feel free to explore the links below to learn more about Windows Phone development.


Conclusion

In this article, I've given you a brief introduction to the Windows Phone 8 platform. We learned about the platform's history, took a closer look at the options you have when developing Windows Phone applications, and explored which tools you can use to develop applications for Microsoft's mobile platform.

In the next installment of this series, the fun really begins when we take a deep dive and create our very first Windows Phone application. I hope to see you there.

2014-08-20T17:00:13.000Z2014-08-20T17:00:13.000ZSani Yusuf

An Introduction to Android Transitions

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-21640

Introduction

The Android transitions framework allows you to configure the appearance of changes in your app's user interface. You can animate changes in an app screen, defining each phase as a scene and controlling the way in which the transition changes the app appearance from one scene to another.

In this tutorial, we will build a simple app with an animated transition in it. This will involve preparing the layout and drawable files in XML, then configuring and applying the transition in Java. We will define two scenes in which the same view items are arranged differently on the screen. As we use a transition, Android will automatically animate the change from one scene to another.

1. Create the App

Step 1

Start by creating a new app in your chosen IDE. You need a minimum SDK of 19 for the transitions classes, so you'll need to take additional steps if you plan on supporting older versions.

Give the app a main Activity and layout file, choosing the name start_layout.xml for the layout. We will be adding another layout file later, using the transition to change from one to the other. The following images show the process in Android Studio.

Step 2

Let's now prepare some drawable shapes to use in the transition. We will use four circle shapes with different colored gradient fills. In your app's drawables resource directory, start by creating a new file named shape1.xml. Enter the following shape:

<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:dither="true"
    android:shape="oval" ><gradient
        android:endColor="#66ff0000"
        android:gradientRadius="150"
        android:startColor="#ffffcc00"
        android:type="radial"
        android:useLevel="false" /><size
        android:height="100dp"
        android:width="100dp" /></shape>

The shape is a circle with a radial gradient fill. All four of the shapes will be the same except for the colors used within them. You may wish to create different versions of the drawables for different device densities. Add shape2.xml next:

<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:dither="true"
    android:shape="oval" ><gradient
        android:endColor="#66ffcc00"
        android:gradientRadius="150"
        android:startColor="#ff00ff00"
        android:type="radial"
        android:useLevel="false" /><size
        android:height="100dp"
        android:width="100dp" /></shape>

Now add shape3.xml:

<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:dither="true"
    android:shape="oval" ><gradient
        android:endColor="#6600ff00"
        android:gradientRadius="150"
        android:startColor="#ff0000ff"
        android:type="radial"
        android:useLevel="false" /><size
        android:height="100dp"
        android:width="100dp" /></shape>

Finally add shape4.xml:

<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:dither="true"
    android:shape="oval" ><gradient
        android:endColor="#660000ff"
        android:gradientRadius="150"
        android:startColor="#ffff0000"
        android:type="radial"
        android:useLevel="false" /><size
        android:height="100dp"
        android:width="100dp" /></shape>

We will use these shapes as ImageButtons in the two layout scenes.

2. Create the Layout Scenes

Step 1

Let's define the two scenes we will transition between as XML layouts. Start with the main layout file you added when you created the app, start_layout.xml. Open it and switch to the XML editing tab. Use a RelativeLayout as shown below:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ff000000"
    android:id="@+id/base"
    tools:context=".TransitionsActivity"></RelativeLayout>

We add a background color and ID for the layout. The ID is essential to ensure that Android transitions between your scenes, we will be using the same ID in the second scene. When you transition between two scenes, Android will animate the changes as long as each view has the same ID in both scenes, otherwise it will treat the views as different and simply fade them in or out when the transition occurs.

Inside the RelativeLayout, add an ImageButton for each shape we created:

<ImageButton
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/btn1"
    android:src="@drawable/shape1"
    android:background="#00000000"
    android:contentDescription="shape"
    android:layout_alignParentLeft="true"
    android:layout_alignParentTop="true"
    android:onClick="changeScene"/><ImageButton
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/btn2"
    android:src="@drawable/shape2"
    android:background="#00000000"
    android:contentDescription="shape"
    android:layout_alignParentRight="true"
    android:layout_alignParentTop="true"
    android:onClick="changeScene"/><ImageButton
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/btn3"
    android:src="@drawable/shape3"
    android:background="#00000000"
    android:contentDescription="shape"
    android:layout_alignParentLeft="true"
    android:layout_alignParentBottom="true"
    android:onClick="changeScene"/><ImageButton
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/btn4"
    android:src="@drawable/shape4"
    android:background="#00000000"
    android:contentDescription="shape"
    android:layout_alignParentRight="true"
    android:layout_alignParentBottom="true"
    android:onClick="changeScene"/>

Notice that each shape button has an ID, which will be the same in the second layout we create, and an onClick attribute. We will include this method in the main Activity later and will start the transition when the user clicks any of the shapes.

You will see a preview of the layout in your IDE, although in some cases the gradient and/or transparency will not be displayed until you actually run the app on a device or the emulator. The shapes are arranged to sit in each corner of the screen as shown below.

Step 2

The first layout we created will represent the start of the transition. Let's now create a second layout file for the scene the transition will change to. Add a new file in your app layout resources directory, naming it end_layout.xml. Switch to the text editing tab and enter the following:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ff000000"
    android:id="@+id/base"
    tools:context=".TransitionsActivity"><ImageButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/btn1"
        android:src="@drawable/shape1"
        android:background="#00000000"
        android:contentDescription="shape"
        android:layout_alignParentRight="true"
        android:layout_alignParentBottom="true"
        android:onClick="changeScene"/><ImageButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/btn2"
        android:src="@drawable/shape2"
        android:background="#00000000"
        android:contentDescription="shape"
        android:layout_alignParentLeft="true"
        android:layout_alignParentBottom="true"
        android:onClick="changeScene"/><ImageButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/btn3"
        android:src="@drawable/shape3"
        android:background="#00000000"
        android:contentDescription="shape"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:onClick="changeScene"/><ImageButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/btn4"
        android:src="@drawable/shape4"
        android:background="#00000000"
        android:contentDescription="shape"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:onClick="changeScene"/></RelativeLayout>

Take a moment to look at the layout code. It is identical to the first layout except for the positions of the shape buttons. Each shape is in the opposite corner from its position in the first layout. The transition will therefore swap the shapes, moving their positions diagonally across the screen.

3. Transition Between Scenes

Step 1

We have the two layouts defined, let's now use a transition to move between them. Open your app's main Activity class. You will need the following import statements:

import android.transition.AutoTransition;
import android.transition.Scene;
import android.transition.Transition;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.RelativeLayout;
import android.transition.TransitionManager;

Inside the Activity class declaration, before the onCreate method, add the following instance variables we will use to apply the transition:

//scenes to transition
private Scene scene1, scene2;
//transition to move between scenes
private Transition transition;
//flag to swap between scenes
private boolean start;

Step 2

Now let's prepare for the transition, which will begin when the user clicks a shape. In onCreate, after the existing code your IDE has entered, add the following:

//get the layout ID
RelativeLayout baseLayout = (RelativeLayout)findViewById(R.id.base);

//first scene
ViewGroup startViews = (ViewGroup)getLayoutInflater()
    .inflate(R.layout.start_layout, baseLayout, false);

//second scene
ViewGroup endViews = (ViewGroup)getLayoutInflater()
    .inflate(R.layout.end_layout, baseLayout, false);

First we define the base scene, which is the ID we gave the containing layout in both scene layout files. Next we define the two scenes we are transitioning between, specifying their layout file names and the containing base scene. This will tell Android we want to transition the views within the two scenes, treating any view with the same ID in both scenes as the same object, so that it animates the change from one scene to the other.

Next, we define the two scenes we want to transition between, still in onCreate:

//create the two scenes
scene1 = new Scene(baseLayout, startViews);
scene2 = new Scene(baseLayout, endViews);

We pass the base layout and relevant scene layouts to each constructor. Now we can refer to these scenes when defining the transition.

Step 3

Let's get the transition prepared, still in onCreate:

//create transition, set properties
transition = new AutoTransition();
transition.setDuration(5000);
transition.setInterpolator(new AccelerateDecelerateInterpolator());

//initialize flag
start=true;

Android provides a range of transition types depending on how you want the changes in your scenes to be animated. In this case, we choose an AutoTransition, so Android will calculate how to make the change based on the properties that are altered between scenes. See the Transitions reference for more options.

We set a duration and interpolator for the transition. You can optionally also set a start delay for the change. Finally, we initialize the boolean flag to true. For simplicity we will use this to swap between the two scenes whenever the user clicks a shape, but this is just to demonstrate the functionality involved.

Step 4

Remember that we added an onClick attribute to the shape buttons when we created the layout XML. Let's add that method to the Activity now:

public void changeScene(View v){

    //check flag
    if(start) {
        TransitionManager.go(scene2, transition);
        start=false;
    }
    else {
        TransitionManager.go(scene1, transition);
        start=true;
    }
}

We use the TransitionManager to transition from the current scene to the other scene, with the boolean flag keeping track of which one we are on. We specify the Transition object we created to tailor how the change unfolds.

You should now be able to run your app and see the transition whenever you click a shape. Each time you click, the transition should move the shapes slowly to the opposite corners, then swap them back when you click again.

Conclusion

In this tutorial we have really only begun to explore what you can do with the Android transitions framework. To develop your transitions further, check out the additional methods in the TransitionManager class, such as beginDelayedTransition and transitionTo. You can also use a TransitionSet to combine multiple transitions, for example, to configure fading and moving effects. Depending on the complexity of your transitions, you may also benefit from the TransitionValues class, which provides a reference to data values relevant to the transition. For more on what you can do with scenes, check out the Scene class as well.

2014-08-24T23:32:54.131Z2014-08-24T23:32:54.131ZSue Smith

Adding Blur Effects on iOS

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/cms-21488

Introduction

With iOS 7, we saw a shift in Apple's design paradigm for mobile devices. Not only did they adopt the so-called flat design, Apple also added a few elements to this pattern themselves. One of these additions is the use of blurred-translucent backgrounds to convey the notion of depth and context. Take Control Center for instance, it blurs the contents of the view behind it as it gets pulled up. This gives the user the sense that it is positioned above other content on the screen and deserves focus. It does so without making the user lose track of where she is in the app.

Even though blur and translucency are used throughout the operating system on iOS 7, the iOS SDK doesn't provide us with any APIs to achieve a similar effect. In this tutorial, I'll walk you through a few methods to create blurred views by creating the sample app shown below.

Our sample app will have a view at the bottom, which can be revealed by pulling it up. The view is translucent and blurs the content that's below it in the view hierarchy, similar to Control Center on iOS 7.

1. Project Setup

Overview

The app that we're going to build will display a photo along with the photo's name and author, displayed in a white circle. There will also be a small rectangular view at the bottom of the screen that blurs the photo and that can be pulled up to display additional information about the photo.

I'm going to assume that you already know how to work with basic user interface elements, such as views, image views, and scroll views. In this tutorial, we'll focus on the view hierarchy and the views that we need to create the blur effect.

Take a look at the above image. It pulls apart the view hierarchy for creating the blur effect we're after. The key components are:

  • Background View: This view displays the photo and credits. This is the view that we're going to blur.
  • Blurred Image: This view contains a blurred version of the contents of the background view.
  • View Mask: The view mask is an opaque view that we'll use to mask the blurred image.
  • Scroll View: The scroll view is the view that contains additional information about the photo. The scroll view's offset is used to increase or decrease the mask view's height. This will result in the blurred image to reveal itself in response to scrolling of the scroll view.

Resources

All the images, frameworks and other files necessary for this tutorial are included in the source files of this tutorial. Clone the repository from GitHub or download the source files to follow along.

2. Creating the User Interface

1. Overview

Open RootViewController.m in Xcode and take a look at its loadView method. You can get a bird's-eye view of how the user interface is laid out by looking at the implementation of this method. There are three main subviews in our application:

  • Header View: Shows the application's name
  • Content View: Displays the photo and credits
  • Scroll View: Includes additional information on a scrollable blurred view

Instead of crowding the loadView method with initializing and configuring the subviews, helper methods are used to do the heavy lifting:

// content view
[self.view addSubview:[self createContentView]];
// header view
[self.view addSubview:[self createHeaderView]];
// scroll view
[self.view addSubview:[self createScrollView]];

2. Creating the Header View

The header view contains a translucent rectangle and a text label with the application's name.

- (UIView *)createHeaderView
{
    UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 60)];
    headerView.backgroundColor = [UIColor colorWithRed:229/255.0 green:39/255.0 blue:34/255.0 alpha:0.6];
    UILabel *title = [[UILabel alloc] initWithFrame:CGRectMake(0, 20, self.view.frame.size.width, 40)];
    title.text = @"Dynamic Blur Demo";
    ...
    [headerView addSubview:title];
    return headerView;
}

3. Creating the Content View

The content view displays the photo and it also includes the photo credits in a white circle.

- (UIView *)createContentView
{
    UIView *contentView = [[UIView alloc] initWithFrame:self.view.frame];
    // Background image
    UIImageView *contentImage = [[UIImageView alloc] initWithFrame:contentView.frame];
    contentImage.image = [UIImage imageNamed:@"demo-bg"];
    [contentView addSubview:contentImage];
    // Photo credits
    UIView *creditsViewContainer = [[UIView alloc] initWithFrame:CGRectMake(self.view.frame.size.width/2 - 65, 335, 130, 130)];
    metaViewContainer.backgroundColor = [UIColor whiteColor];
    metaViewContainer.layer.cornerRadius = 65;
    [contentView addSubview:creditsViewContainer];
    UILabel *photoTitle = [[UILabel alloc] initWithFrame:CGRectMake(0, 54, 130, 18)];
    photoTitle.text = @"Peach Garden";
    ...
    [metaViewContainer addSubview:photoTitle];
    UILabel *photographer = [[UILabel alloc] initWithFrame:CGRectMake(0, 72, 130, 9)];
    photographer.text = @"by Cas Cornelissen";
    ...
    [metaViewContainer addSubview:photographer];
    return contentView;
}

4. Creating the Scroll View

The scroll view contains additional information about the photo and a blurred version of the photo. The scroll view is about twice the length of the screen, with the bottom half containing the text view and image view. By enabling paging on the scroll view, the scroll view's contents will snap to the top or the bottom of the view, depending on the scroll view's offset.

- (UIView *)createScrollView
{
    UIView *containerView = [[UIView alloc] initWithFrame:self.view.frame];
    blurredBgImage = [[UIImageView  alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 568)];
    [blurredBgImage setContentMode:UIViewContentModeScaleToFill];
    [containerView addSubview:blurredBgImage];
    UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:self.view.frame];
    scrollView.contentSize = CGSizeMake(self.view.frame.size.width, self.view.frame.size.height*2 - 110);
    scrollView.pagingEnabled = YES;
    ...
    [containerView addSubview:scrollView];
    UIView *slideContentView = [[UIView alloc] initWithFrame:CGRectMake(0, 518, self.view.frame.size.width, 508)];
    slideContentView.backgroundColor = [UIColor clearColor];
    [scrollView addSubview:slideContentView];
    UILabel *slideUpLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 6, self.view.frame.size.width, 50)];
    slideUpLabel.text = @"Photo information";
    ...
    [slideContentView addSubview:slideUpLabel];
    UIImageView *slideUpImage = [[UIImageView alloc] initWithFrame:CGRectMake(self.view.frame.size.width/2 - 12, 4, 24, 22.5)];
    slideUpImage.image = [UIImage imageNamed:@"up-arrow.png"];
    [slideContentView addSubview:slideUpImage];
    UITextView *detailsText = [[UITextView alloc] initWithFrame:CGRectMake(25, 100, 270, 350)];
    detailsText.text = @"Lorem ipsum ... laborum";
    ...
    [slideContentView addSubview:detailsText];
    return containerView;
}

3. Taking a Snapshot

To blur a view, we first need to take a snapshot of its contents and have it ready in the form of an image. we can then blur the image and use it as the background of another view. Let's first see how we can take a snapshot of the contents of a UIView object.

In iOS 7, Apple added a new method to UIView for taking snapshots of a view's contents, drawViewHierarchyInRect:afterScreenUpdates:. This method takes a snapshot of the view's contents, including any subviews it contains.

Let's define a method in the ViewController class that accepts a UIView object and returns a UIImage, a snapshot of the view's contents.

- (UIImage *)takeSnapshotOfView:(UIView *)view
{
    UIGraphicsBeginImageContext(CGSizeMake(view.frame.size.width, view.frame.size.height));
    [view drawViewHierarchyInRect:CGRectMake(0, 0, view.frame.size.width, view.frame.size.height) afterScreenUpdates:YES];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}

Step 1: Begin a New Image Context

An image context is a bitmap-based graphics context that you can use to draw and manipulate images. UIView's new method drawViewHierarchyInRect:afterScreenUpdates: rasterizes the UIView and draws its contents into the current image context.

This means that before we call this method, we first need to create a new image context by invoking UIGraphicsBeginImageContext, passing in the required size for the image context.

Step 2: Take Snapshot

With the image context set up, we can call the view's drawViewHierarchyInRect:afterScreenUpdates: method. The second argument specifies whether the snapshot should include the view's current contents or must include any recent changes before taking the snapshot.

Step 3: Create Image from Image Context

We can get the contents of the image context, the snapshot of the view, by invoking UIGraphicsGetImageFromCurrentImageContext. This function returns a UIImage object.

Step 4: End Image Context

After creating the snapshot, we remove the graphics context from the stack by invoking UIGraphicsEndImageContext.

4. Blurring the Snapshot

Once you have the snapshot, we can blur it using a number of techniques. In this tutorial, I will cover three techniques:

  • blurring with the Core Image framework
  • blurring using Brad Larson's GPUImage framework
  • blurring using Apple's UIImage+ImageEffects category

Option 1: Core Image

Core Image is an image processing framework developed and maintained by Apple. It uses a GPU or CPU rendering path to process images in near real-time.

Core Image provides us with a variety of filters that can be used to perform operations ranging from modifying an image's hue or saturation to face detection.

CIGaussianBlur is one of the filters included in the Core Image framework and can be used to blur images. Blurring an image with Core Image is fairly easy as you can see below.

- (UIImage *)blurWithCoreImage:(UIImage *)sourceImage
{
    CIImage *inputImage = [CIImage imageWithCGImage:sourceImage.CGImage];
    // Apply Affine-Clamp filter to stretch the image so that it does not
    // look shrunken when gaussian blur is applied
    CGAffineTransform transform = CGAffineTransformIdentity;
    CIFilter *clampFilter = [CIFilter filterWithName:@"CIAffineClamp"];
    [clampFilter setValue:inputImage forKey:@"inputImage"];
    [clampFilter setValue:[NSValue valueWithBytes:&transform objCType:@encode(CGAffineTransform)] forKey:@"inputTransform"];
    // Apply gaussian blur filter with radius of 30
    CIFilter *gaussianBlurFilter = [CIFilter filterWithName: @"CIGaussianBlur"];
    [gaussianBlurFilter setValue:clampFilter.outputImage forKey: @"inputImage"];
    [gaussianBlurFilter setValue:@30 forKey:@"inputRadius"];
    CIContext *context = [CIContext contextWithOptions:nil];
    CGImageRef cgImage = [context createCGImage:gaussianBlurFilter.outputImage fromRect:[inputImage extent]];
    // Set up output context.
    UIGraphicsBeginImageContext(self.view.frame.size);
    CGContextRef outputContext = UIGraphicsGetCurrentContext();
    // Invert image coordinates
    CGContextScaleCTM(outputContext, 1.0, -1.0);
    CGContextTranslateCTM(outputContext, 0, -self.view.frame.size.height);
    // Draw base image.
    CGContextDrawImage(outputContext, self.view.frame, cgImage);
    // Apply white tint
    CGContextSaveGState(outputContext);
    CGContextSetFillColorWithColor(outputContext, [UIColor colorWithWhite:1 alpha:0.2].CGColor);
    CGContextFillRect(outputContext, self.view.frame);
    CGContextRestoreGState(outputContext);
    // Output image is ready.
    UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return outputImage;
}

Let's break the above code block down:

  • We first create a CIImage object from the UIImage object. When working with the Core Image framework, images are represented by CIImage objects.
  • Depending on the blur radius, applying a gaussian blur to an image will slightly shrink the image. To work around this issue, we stretch the image a little bit by applying another filter, CIAffineClamp, before applying the gaussian blur filter.
  • We then take the output and pass it to the CIGaussianBlur filter along with a blur radius of 30.
  • We could take the output, convert it to a CGImage,  and use it in our application. However, we will add a white tint to the image to ensure that the photo's description is clearly legible. To add a white tint, we add a semi-transparent white fill over the image. To do this, we create a new image context and fill it with a white color with an alpha value of 0.2.
  • As we saw earlier, we then get a UIImage object from the image context and dispose of the image context.

Option 2: GPUImage

GPUImage is an open-source iOS framework for image and video processing, created and maintained by Brad Larson. It includes a collection of GPU-accelerated filters that can be applied to images, live camera video, and movies.

The GPUImage framework is included in the source files of this tutorial, but adding the framework to your own projects is very easy:

  1. Start by downloading the framework or cloning the repository from GitHub.
  2. Open a terminal window, navigate to the GPUImage folder, and run the build script build.sh to compile the framework.
  3. Copy the GPUImage.framework from the build folder to your project's folder and then drag-and-drop it into the Project Navigator.
  4. You can then use the GPUImage framework in your project by importing the frameworks headers, #import <GPUImage/GPUImage.h>.

The GPUImage framework includes filters similar to those in the Core Image framework. For our sample application, we are interested in two filters, , GPUImageGaussianBlurFilter and GPUImageiOSBlurFilter.

- (UIImage *)blurWithGPUImage:(UIImage *)sourceImage
{
    // Gaussian Blur
    GPUImageGaussianBlurFilter *blurFilter = [[GPUImageGaussianBlurFilter alloc] init];
    blurFilter.blurRadiusInPixels = 30.0;
    return [blurFilter imageByFilteringImage: sourceImage];
}

As you can see, GPUImage filters are easier to use than those of the Core Image framework. After initializing the filter object, all you have to do is configure the filter and supply it with an image to which the filter needs to be applied. The imageByFilteringImage: method returns a UIImage object.

Instead of the GPUImageGaussianblur class, you could also use the GPUImageiOSblur class like so:

    // iOS Blur
    GPUImageiOSBlurFilter *blurFilter = [[GPUImageiOSBlurFilter alloc] init];
    blurFilter.blurRadiusInPixels = 30.0;

The GPUImageiOSblur class replicates the blur effect you can see in Control Center on iOS 7. So, unlike the Core Image approach, you won't have to write additional code to tint the blurred image.

Option 3: UIImage+ImageEffects

During last year's WWDC, Apple gave a talk on Core Image effects and techniques in which they introduced a category on UIImage called ImageEffects. The ImageEffects category uses Apple's high performance vImage image processing framework, part of the Accelerate framework, to perform the necessary computations. This makes it a fast and easy way to perform blur on iOS.

The category adds the following methods the UIImage class:

  • applyLightEffect
  • applyExtraLightEffect
  • applyDarkEffect
  • applyTintEffectWithColor:
  • applyBlurWithRadius:tintColor:saturationDeltaFactor:maskImage:

These methods can be called directly on an image to achieve the desired blur effect. The applyBlurWithRadius:tintColor:saturationDeltaFactor:maskImage: method accepts a number of arguments that let you fine-tune the blurring operation.

You can download Apple's ImageEffects sample project from Apple's developer website and use it in your projects.

#import "UIImage+ImageEffects.h"

...

- (UIImage *)blurWithImageEffects:(UIImage *)image
{
    return [image applyBlurWithRadius:30 tintColor:[UIColor colorWithWhite:1 alpha:0.2] saturationDeltaFactor:1.5 maskImage:nil];
}

5. Masking the Blurred Image

In the sample app, it appears as if we are dynamically blurring the photograph, but that is not the case. We use a little trick called masking. Instead of continuously taking snapshots and blurring them to create the desired effect, we take only one snapshot, blur it, and use it in combination with a mask.

As shown in the figure at the beginning of this tutorial, we align the blurred view with the background view below it. We then create another view with a height of 50 points and an opaque background, and place it at the bottom of the screen. We use this view to mask the blurred image.

blurredBgImage.layer.mask = bgMask.layer;

We then update the frame of the mask view as the scroll view is being scrolled. To do so, we implement one of the delegate methods of the UIScrollViewDelegate protocol, scrollViewDidScroll:, and update the mask’s frame with respect to the scroll view’s vertical content offset.

-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    bgMask.frame = CGRectMake(bgMask.frame.origin.x,
                              self.view.frame.size.height - 50 - scrollView.contentOffset.y,
                              bgMask.frame.size.width,
                              bgMask.frame.size.height + scrollView.contentOffset.y);
}

By updating the mask, it appears as if we are dynamically blurring the photograph below the scroll view. That's it. You now have a beautiful, blur effect, similar to the one you see in the Control Center on iOS.

6. Performance

With the above techniques in mind, you may be wondering which one is the best in terms of performance. To help you decide, I have ran some tests on an iPhone 5S and 5C. Take a look at the following graphs.

These graphs tell us the following:

  • The GPUImage framework performs the slowest on the iPhone 5C due to its slower GPU. This isn't surprising since the framework relies heavily on the GPU.
  • The ImageEffects category performs best on both devices. It's also interesting to see that the time needed for blurring an image increases with the blur radius.

While blurring images never took longer than 220ms on the iPhone 5S, the iPhone 5C needed up to 1.3s to perform the same task. This clearly shows that blur effects should be used wisely and sparsely.

To reduce the time required for blurring an image, we can reduce the size of the snapshot that we apply the blur filter on. Since we are performing a blur and the finer details of the image won't be visible anyway, we can downsample the image without running into problems. To take a smaller snapshot, we update the implementation of the takeSnapshotOfView: method as follows:

- (UIImage *)takeSnapshotOfView:(UIView *)view
{
    CGFloat reductionFactor = 1.25;
    UIGraphicsBeginImageContext(CGSizeMake(view.frame.size.width/reductionFactor, view.frame.size.height/reductionFactor));
    [view drawViewHierarchyInRect:CGRectMake(0, 0, view.frame.size.width/reductionFactor, view.frame.size.height/reductionFactor) afterScreenUpdates:YES];
    ...
    return image;
}

To further reduce the time required to blur the snapshot, we can use alternative blurring techniques, such as a box blur. Even though the result will be different than that of a gaussian blur, it takes less time to blur an image using a box blur.

Conclusion

Blur is definitely a great addition to user interface design on iOS. However, no matter how gorgeous your application's user interface looks, if it doesn't perform well, blur effects won't enhance your application.

Based on the above performance metrics, we see that blurring is indeed a costly effect. But by optimizing the parameters, such as the blur radius and image size, choosing the right blurring technique, and using a few tricks, we can achieve very interesting effects without compromising the application's performance.

In iOS 8, Apple has introduced UIVisualEffectView, which allows developers to very easily apply blur and vibrancy effects to views. If you can't wait until iOS 8 is officially released, you can test these effects by downloading the beta of Xcode 6.

2014-08-25T17:20:26.000Z2014-08-25T17:20:26.000ZSandeep S Kumar

Windows Phone 8: Creating Your First Application

$
0
0
tag:code.tutsplus.com,2005:PostPresenter/mobile-21175

In this tutorial, you'll create your first Windows Phone 8 application. The aim of this article is to familiarize yourself with some of the building blocks of the Windows Phone 8 SDK. If you haven't read the introduction of this series, then I recommend you do so first. It's important that you have a good understanding of the platform before creating applications for it.

1. Prerequisites

We're going to create a basic Windows Phone 8 application using C#. You need to have Visual Studio installed as well as the Windows Phone 8 SDK. If you don't have Visual Studio installed, then I recommend you install Visual Studio Express 2012, which you can download from Microsoft's Download Center. This will install the necessary software and tools for Windows Phone 8 development.

By installing Visual Studio Express 2012 for Windows Phone 8, you install the following applications and tools:

  • Visual Studio Express 2012
  • .Net Framework
  • Windows Phone 8 SDK
  • Blend For Visual Studio 2012

With the development tools installed, it's time to start creating your very first Windows Phone 8 application.

2. Your First Application

To create a new Windows Phone project, launch Visual Studio Express 2012 and select New Project > Windows Phone App from the File menu. Give the project a name, specify a location to save the project to, and click OK.

Create Project

Make sure to select the Visual C# template from the list of Templates on the left. Visual Studio will also ask you about the version you want to target. We'll be targeting version 8.0.

3. Launch Your Application

We now have a very basic Windows Phone project to work with. Let’s launch the application to see what it actually looks like on the Windows Phone emulator.

First Look

To run your application in the Windows Phone emulator, click the green play button at the top left of the window. This will launch the emulator, install your application, and launch it in the emulator.

The result is a screen similar to the one shown below. You can choose between several emulators in Visual Studio. Feel free to play around with the other emulators, but don't choose the Windows Phone 7 emulator as our project targets Windows Phone 8.

Emu

Conclusion

Creating a Windows Phone 8 project and running it in the emulator is as simple as that. Of course, our Windows Phone 8 application isn't very functional yet with only one screen and no user interaction. In the next tutorial, you'll learn how to add functionality to your Windows Phone 8 application.

2014-08-27T16:25:13.000Z2014-08-27T16:25:13.000ZSani Yusuf
Viewing all 1836 articles
Browse latest View live