ACUNU ANALYTICS WHEN SECONDS MATTER... WE PROVIDE IMMEDIATE BUSINESS INSIGHT
PREDICTABLE FAST QUERIES
LOW-LATENCY ANSWERS
Even as data volumes grow
Sub-second from source to insight
HISTORICAL, FRESH DATA
POWERFUL ANALYTICS
Combined for deeper insight
Qualitative and quantitive
Benefits:
RICH VISUALIZATION SCALABILITY, DISTRIBUTION, AND AVAILABILITY
Easy to assemble dashboards and APIs
Round the world and into the peta-scale
Acunu Analytics on Cassandra delivers instant answers from event streams, making it simple to build analytic applications and live dashboards that deliver fresh insight from live data.
There is no lag introduced by batching up events on arrival nor by indexing loaded data before it is available to queries. Results with millisecond latency.
Our unique approach of pre-building the cubes, on ingest, that satisfy the queries, means predictable, very short query times that are not dependent on data volumes.
Read about our customers’ success and hear them talk in our webinars at www.acunu.com
www.acunu.com | @acunu contact@acunu.com | US office: +1 866-487-2650 | UK office: +44 203-1760143
Big data goes in. Business insight comes out. Our software turns your massive streams of machine data into business insights by making sense of website clickstreams, mobile devices, applications and other technologies that drive your business. It’s what our market-leading customers call real-time Operational Intelligence. Over half of the Fortune 100™ use Splunk software and have the business results to prove it. In days or weeks, not months or years.
www.splunk.com/goto/listen
www.splunk.com © 2013 Splunk Inc. All Rights Reserved. Fortune 100 is a trademark of the FORTUNE magazine division of Time Inc.
Editor’s Note
Dear Readers, next SDJ Open Magazine is released and available for all our O urmembers after free registration!
We know that iOS development is of your high interest right now and that’s why we’ve decided to choose some “the best of” and share them with all of you. In this issue you will find one of the two excellent articles written by coworkers Demetrios Kaligaris and Jacob Kennedy that have been working together on different projects for almost 20 years. We’re presenting here ‘iOS App Development Methodology – S2C2’, describing special methodology thanks to which it is possible to optimize iOS app client development. Furthermore, there are two contributions prepared by our special Editor in Chief Doug Panchyshyn. You will find one of his instructions about delegation pattern in ‘Deeper Delegation’. We’re more than delighted to present his great motto: “It has been said that the delegation pattern is simple. It is kind of like saying that skating is simple, but, try imagining it if you have never seen anyone skate before. More so, try doing it if you have never seen or done it before. It’s abstract. Skating or riding a bicycle, like many other things, becomes simpler with practice.” That’s exactly what we’re trying to do to make your life easier! We’re also adding a complementary ‘Securing Your Core Data’ by Ronan O’Ciosoig. Thanks to our Beginner’s Guide to NoSQL written by Sufyan bin Uzayr You will learn how to start with your NoSQL projects very easily. For all those, interested in further development we have one of two articles written by Damian Czernous, who decided to share his experience and knowledge with you . His Immutability in Life will help you understand all processes better and will definitely encourage you to start your own tests. We hope that skills and knowledge of all those excellent experts will encourage you to start your own projects or will help you improve yours. Enjoy your reading! Enjoy reading! SDJ team
team Editor in Chief: Anna Lakomy & Doug Panchyshyn Advisory Board: Raul Mesa, David Schneider, Laszlo Acs Special thanks to Raul Mesa Special thanks to our Beta testers and Proofreaders who helped us with this issue. Our magazine would not exist without your assistance and expertise. Publisher: Paweł Marciniak Managing Director: Ewa Dudzic Production Director: Andrzej Kuca andrzej.kuca@sdjournal.org Art. Director: Ireneusz Pogroszewski ireneusz.pogroszewski@sdjournal.org DTP: Ireneusz Pogroszewski Marketing Director: Ewa Dudzic Publisher: Hakin9 Media SK 02-676 Warsaw, Poland Postepu 17D Phone: 1 917 338 3631 http://en.sdjournal.org/ Whilst every effort has been made to ensure the highest quality of the magazine, the editors make no warranty, expressed or implied, concerning the results of the content’s usage. All trademarks presented in the magazine were used for informative purposes only. All rights to trademarks presented in the magazine are reserved by the companies which own them.
DISCLAIMER! The techniques described in our magazine may be used in private, local networks only. The editors hold no responsibility for the misuse of the techniques presented or any data loss.
4
OPEN 03/2013
Contents
Getting started
06 A Beginner’s Guide to NoSQL Sufyan bin Uzayr
Let’s say you’ve decided to set up a website or an application. You’ll obviously need something to manage the data. Yes, that’s right, a database. So, what is it going to be? MySQL, MS-SQL, Oracle or PostgreSQL? After all, nothing can be as amazing as a good old RDBMS that employs SQL to manage the data.
Getting involved
10 I mmutability in Life Damian Czernous
Making an object immutable is always a good choice. Objects are used in many ways, but immutable objects have limitations. Let’s focus on value beans and find reasonable compromise for them.
16
A Little Bit of Practice
iOS App Development Methodology – S2C2 Jacob Kennedy
22 Deeper Delegation Doug Panchyshyn
32 Securing your Core Data Ronan O Ciosoig
en.sdjournal.org
5
Getting started
A Beginner’s Guide to NoSQL This article aims to explore the basic ideas and principles about noSQL databases. noSQL caters to database admins, programmers, coders, web devs, etc.
L
et’s say you’ve decided to set up a website or an application. You’ll obviously need something to manage the data. Yes, that’s right, a database. So, what is it going to be? MySQL, MS-SQL, Oracle or PostgreSQL? After all, nothing can be as amazing as a good old RDBMS that employs SQL to manage the data. Well, allow me to introduce to you an entirely unique and unconventional Database model – NoSQL. Just like every other fine article out there, we too shall begin ith...eh....disclaimers! NoSQL stands for not-only-SQL. The idea here is not to oppose SQL, but instead provide an alternative in
Thrift
REST
languageSpecific API
Map-Reduce
Get/Put Statements
Multiple Ways of Accessing NoSQL Databases Figure 1. Ways of Accessing NoSQL Database
6
terms of storage of data. Yet, for the obvious reason that most users are well versed with SQL, many NoSQL databases strive to provide an SQLlike query interface.
Why NoSQL?
That’s a valid question, indeed. Well, here are the reasons: • Managing Large Chunks of Data: NoSQL databases can easily handle numerous read/write cycles, several users and amounts of data ranging in petabytes. • Schema? Nah, not needed: Most NoSQL databases are devoid of schema and therefore very flexible. They provide great choices when it comes to constructing a schema and foster easy mapping of objects into them. Terms such as normalization and complex joins are, well, not needed! • Programmer-friendly: NoSQL databases provide simple APIs in every major programming language and therefore there is no need for complex ORM frameworks. And just in case APIs are not available for a particular programming language, data can still be accessed over HTTP via a simple RESTful API, using XML and/or JSON. • Availability: Most distributed NoSQL databases provide easy replication of data and failure of one node does not affect the availability of data in a major way. • Scalability: NoSQL databases do not require a dedicated high performance server. Actually, they can easily be run on a cluster of commodity hardware and scaling out is just as simple as adding a new node. • Low Latency: Unless you are running a cluster of a trillion data servers (or something like that, give
OPEN 03/2013
A Beginner's Guide to NoSQL
or take a few million of them), NoSQL can help you achieve extremely low latency. Of course, latency in itself depends on the amount of data that can be successfully loaded into memory.
5. Object-oriented 6. Key-value Stores 7. Triple Stores
Document stores
SQL ideology
Gone are the days when data organization used to be as minimal as simple rows and columns. Today, data is more often than not represented in the form of XML or JSON (we’re talking about the Web, basically). The reason for favoring XML or JSON is because both of them are extremely portable, compact and standardized. Bluntly put, it makes little sense to map XML or JSON documents into a relational model. Instead, a wiser decision would be to utilize the document stores already available. Why? Again, simply because NoSQL databases are schema-less, and there exists no predefined for an XML or JSON document and as a result, each document is independent of the other. The database can be employed in CRM, web-related data, realtime data, etc. Some of the most well known implementation models are MongoDB, CouchDB and RavenDB. In fact, MongoDB has been used by websites such as bit.ly and Sourceforge.
Basically, NoSQL drops the traditional SQL ideology in favor of CAP Theorem or Brewer’s Theorem, formulated by Eric Brewer in 2000. the theorem talks about three basic principles of Consistency, Availability and Partition Tolerance (abbreviated as CAP), adding that a distributed database can at the most satisfy only two of these. NoSQL databases implement the theorem by employing Eventual Consistency, which is a more relaxed form of consistency that performs the task over a sufficient period of time. This in turn improves availability and scalability to a great extent. This paradigm is often termed as BASE – implying Basically Available, Soft state, Eventual Consistency.
NoSQL Data Models
Some of the major and most prominent differentiations among NoSQL databases are as follows:
Hierarchical Databases
1. Document Stores 2. Hierarchical 3. Network 4. Column-oriented a
en.sdjournal.org
These databases store data in the form of hierarchical relevance, that is, tree or parent-child relationship. In terms of relational models, this can be termed as d
v
e
r
t
i
s
e
m
e
n
t
7
Getting started
1:N relationship. Basically, geospatial databases can be used in a hierarchical form to store location information which is essentially hierarchical, though algorithms may vary. Geotagging and geolocation are in vogue of late. It is in such uses that a geospatial database becomes very relevant, and can be used in Geographical Information System. Major examples of the same include PostGIS, Oracle Spatial, etc. Also, some of the most well known implementations of hierarchical databases are the Windows Registry by Microsoft and the IMS Database by IBM.
Graph Network Databases
Graph databases are the most popular form of network database that are used to store data that can be represented in the form of a Graph. Basically, data stored by graph databases can grow exponentially and thus, graph databases are ideal for storing data that changes frequently. Cutting the theoretical part, graph database has perhaps the most awesome example in the likes of FlockDB, developed by Twitter to implement a graph of who follows whom. FlockDB uses the Gizzard Framework to query a database up to 10,000 times per second. A general technique to query a graph is to begin from an arbitrary or specified start node and follow it by traversing the graph in a depth-first or breadth-first fashion, as per the relationships that obey the given criterion. Most graph databases allow the developer to use simple APIs for accomplishing the task. For instance, you can make queries such as: “Does Jonny Nitro read Data Center Magazine?” Some of the most popular graph databases include, apart from FlockDB, HyperGraphDB and Neo4j.
Column-oriented Databases
Column-oriented databases came into existence after Google’s research paper on its BigTable distributed storage system, which is used internally along with the Google file system. Some of the popular implementations are Hadoop Hbase, Apache Cassandra, HyperTable, etc. Such databases are implemented more like threedimensional arrays, the first dimension being the row identifier, the second being a combination of column family plus column identifier and the third being the timestamp. Column-oriented databases are employed by Facebook, Reddit, Digg, etc.
Object-oriented Databases
Whether or not object-oriented databases are purely NoSQL databases is debatable, yet they are more often than not considered to be so because such databases too depart from traditional RDBMS based data models. Such databases allow the storage of data in the form of objects, thereby making it highly transparent. Some
8
of the most popular ones include db4o, NEO, Versant, etc. Object-oriented databases are generally used in research purposes or web-scale production.
Key-value stores
Key-value stores are (arguably) based on Amazon’s Dynamo Research Paper and Distributed hash Tables. Such data models are extremely simplified and generally contain only one set of global key value pairs with each value having a unique key associated to it. The database, therefore, is highly scalable and does not store data relationally. Some popular implementations include Project Voldemort (open-sourced by LinkedIn), Redis, Tokyo Cabinet, etc.
Triple stores
Triple stores save data in the form of subject-predicateobject with the predicate being the linking factor between subject and object. As such, Triple Scores too are variants of network databases. For instance, let’s say “Jonny Nitro reads Data Center Magazine.” In this case, Jonny Nitro is the subject, while Data Center Magazine is the object, and the term ‘reads’ acts as the predicate linking the subject with the object. Quite obviously, mapping such semantic queries into SQL will prove difficult, and therefore NoSQL offers a viable alternative. Some of the major implementations of Triple Stores are Sesame, Jena, Virtuoso, AllegroGraph, etc.
Summary
So, what now? Well, you’ve just been introduced to NoSQL. However, does this mean that you should make the switch to it from SQL? Perhaps. Or perhaps not. The answer varies from situation to situation. If you find SQL queries way too much to cope with, chances are you’ll find NoSQL equally difficult. However, if you’re looking for a more flexible alternative and do not mind getting your hands dirty, you should definitely give NoSQL a spin! The choice, obviously, is yours! Happy data managing to you!
Sufyan bin Uzayr Sufyan bin Uzayr is a 20-year old Freelance writer, graphic artist and photographer based in India. Sufyan has been extensively involved in the field of graphic design and web development, and he has also developed apps for the mobile platform. Currently writing for two print magazines and six blogs, Sufyan is also the Editor-in-Chief of Brave New World, a contemporary electronic journal. Visit Sufyan’s website at www.sufyan.co.nr or his e-journal at www.bravenewworld.in You may also mail him at sufyan@live.in.
OPEN 03/2013
Getting involved
Immutability in Life Making an object immutable is always a good choice. Objects are used in many ways, but immutable objects have limitations. Let’s focus on value beans and find reasonable compromise for them.
T
he immutability of the object is a subject of a few JSRs. In JSR 310 Data and Time API Early Draft Review 2 (12 September, 2012; http://jcp.org) we may read that javax.time and javax.time.format classes will be finally immutable and deployed together with Java 8. An annotation @Immutable (https://code. google.com/p/jsr-305/source/browse/trunk/ri/src/main/ java/javax/annotation/concurrent/Immutable.java) was proposed in an inactive (last update 2006) JSR 305 Annotations for Software Defect Detection. Currently only @NotNull annotation is considered and has a different purpose from that one in JSR 303 Bean Validation. On the net we may find lots of information on the definition and implementation of immutable objects. In most cases it sounds pretty straightforward. If you make a class and all its instance variables final then you gain immutability. The reason to make an object immutable is to keep a system safe. Safe, but how? Another useful feature of the object is an ability to be compared against a different one. We may decide between by reference or by value comparison. In practice when we construct value beans usually we compare them by value. In order to do that we play with Object’s hashcode() and equals(Object) methods (http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html).
Comparable by value
A typical usage scenario is to create a key for a hash table e.g. WeaponMapKey that will represent stored value e.g. Verdict in Rock Paper Scissors’s Arbiter class (Listing 1). In short, a hashcode for an object was introduced to support benefits of hash tables (e.g. searching operation) and should be as close as possible to the unique
10
value. A default implementation converts object’s internal address to an integer value, so equals(Object) by default compares these numbers, so compares by reference. To compare by value we need to change the behaviour of these methods. It’s more flexible to get from map by key value rather than by key reference (see judge(...) method), hence we decide to override both methods. A fairly acceptable algorithm for hashing mechanism is based on object’s states. The Eclipse environment uses such by default. If we try to put mutable value beans with overridden hashcode() and equals(Object) methods into the hash table we are asking for trouble. A mutable object may change a state, which results in a new hashcode value. See example junit test (https://github.com/damianczernous/blog/blob/master/hash/src/test/java/com/ blogspot/damianczernous/hash/map/GivenHashMap. java), where WeaponMapKey stays mutable. One possible solution is to use a different (object’s states free) hashing algorithm, which is hard to implement. Another way is to make an object simply immutable and keep a system safe. The immutability brings more safety to the software than that, but with this paper we will stick only to this one. In sum, if we want to compare value beans by value then we need them immutable. Generally, whenever possible, we prefer immutable objects because they are safe (e.g. thread safe). On the contrary, there are situations where mutable versions are needed. In such cases it seems to be a good idea to instruct everyone around about the nature of those objects.
Usability of “simple” immutable construction
It’s not possible to extend the final class, because it is final. We can’t code setter methods, because instance
OPEN 03/2013
variables are final too. What left is constructor to set variables (no-argument constructor is redundant) and getter methods. It’s enough for simple value beans. In systems that use ORM support things may complicate, because persistent value beans (called entities) sometimes have to follow Java Bean convention. Additionally, inheritance might be helpful. In such cases discussed, construction is very limiting. Let’s consider the Bakery application; find other ways to free from bounds and stay consistent with immutable concept. The application code you may find in Github (https://github.com/ damianczernous/blog/tree/master/bakery) repository.
Immutable objects
Sometimes we want to benefit from inheritance when playing with value beans. James Gosling explained this more then a decade ago in a recorded conversation “James Gosling on Java”, published in JavaWorld 2001 (http://www.artima.com/intv/gosling313.html) (see Listing 2). The Bread class plays a role of immutable object. A final class level modifier was replaced with method level one. This still prevents any sub-classes from overriding these methods, which would result in changing its states (see WeaponMapKey class for reference). The private final instance variables were replaced with default ones to support mutable version. Both classes Bread and MutableBread exist in com.blogspot.damianczernous. bakery.model package, therefore still it’s not possible to change the state from outside of the package where model’s clients reside such as BakeryPresenter (see show() method in Github repository). This construction also supports data encapsulation (it’s not possible directly to change object’s states outside model package) although class encapsulation can be seen as violated. An alternative solution is to provide default setters and override them with a public accessor in mutable version (Listing 3). It’s the mutable object’s responsibility to provide a way of changing its states, so setters belong to it. Without setters immutable version it seems to be more readable and more responsibility focused (free of redundant information).
The JPA aspect
The JPA entities have to follow Java Bean convention when property access is used. In the case of immutable objects, a default constructor is completely redundant, but has to be provided to work with such frameworks. In JSR 317 Java Persistence 2.0 Final Release (10 December, 2009) page 22, we may read that both setters and getters have to be provided with public or protected accessors. A hibernate implementation of the JSR specification (which is used in this example), supports default accessor as well.
en.sdjournal.org
Getting involved
Listing 1. The Arbiter class uses the immutable WeaponMapKey by value
* @param against
* @return {@link Verdict} for toEvaluate {@link
public final class WeaponMapKey {
public Verdict judge( Weapon toEvaluate, Weapon
private final Weapon weapon1; private final Weapon weapon2;
{
public WeaponMapKey( Weapon weapon1, Weapon weapon2 )
{
this.weapon2 = weapon2;
Listing 2. The immutability of the Bread class is guaranteed by package access level package com.blogspot.damianczernous.bakery.model;
{
public class Bread
// e.g. generated by eclipse
public boolean equals( Object obj ) {
// e.b. generated by eclipse
}
{
double taxRate; String name;
@Override
GrainType grainType; public Bread( double taxRate, String name, {
public class Arbiter /**
GrainType grainType )
super();
this.taxRate = taxRate; this.name = name;
this.grainType = grainType;
* {@link WeaponMapKey}.weapon1 - toEvaluate,
}
*/
public final double getTaxRate()
{@link WeaponMapKey}.weapon2 - against.
private static final Map EVALUATION_MAP = new HashMap<>();
static {
EVALUATION_MAP.put( new WeaponMapKey( Weapon.
ROCK, Weapon.ROCK ), Verdict.TIE );
EVALUATION_MAP.put( new WeaponMapKey( Weapon.
ROCK, Weapon.PAPER ), Verdict.LOSS );
EVALUATION_MAP.put( new WeaponMapKey( Weapon.
ROCK, Weapon.SCISSORS ), Verdict.
...
}
WIN );
/**
* Judges which {@link Weapon} is stronger. *
* @param toEvaluate
12
toEvaluate, against ) );
}
@Override
}
{
return EVALUATION_MAP.get( new WeaponMapKey(
}
public int hashCode()
}
against )
super();
this.weapon1 = weapon1; }
Weapon}.
*/
{ }
return taxRate;
public final String getName() { }
return name;
public final GrainType getGrainType() { }
return grainType;
@Override
public int hashCode() { }
// e.g. generated by eclispe
OPEN 03/2013
Immutability in life
void setTaxRate( double taxRate )
@Override
{
public boolean equals( Object obj ) {
}
}
}
// e.g. generated by eclipse
void setName( String name ) {
package com.blogspot.damianczernous.bakery.model;
}
public class MutableBread extends Bread {
}
{
this( 0.0d, null, null );
}
}
{ }
}
super.taxRate = taxRate;
super.name = name;
public void setGrainType( GrainType grainType ) {
}
}
super.grainType = grainType;
}
this.topping = topping;
...
public class MutableBun extends Bun {
public MutableBun() { }
this( 0.0d, null, null, null );
public MutableBun( double taxRate, String name, { }
Filling filling, Topping topping )
super( taxRate, name, filling, topping );
@Override
Listing 3. The immutable Bun object follows Java Bean convention
public void setTaxRate( double taxRate ) { }
public class Bun {
}
super( taxRate, name, grainType );
public void setName( String name ) {
{
GrainType grainType )
public void setTaxRate( double taxRate )
this.filling = filling;
void setTopping( Topping topping )
public MutableBread( double taxRate, String name, {
this.name = name;
void setFilling( Filling filling )
public MutableBread() {
this.taxRate = taxRate;
private double taxRate; private String name;
private Filling filling;
super.setTaxRate( taxRate );
@Override
public void setName( String name ) {
super.setName( name );
private Topping topping;
}
public Bun( double taxRate, String name, Filling
@Override
{
{
}
filling, Topping topping )
...
en.sdjournal.org
public void setFilling( Filling filling )
}
super.setFilling( filling );
13
Getting involved
In some solutions we may notice interfaces for beans with getter methods only. This is another way of following Java Bean convention and immutability in the same class. Java Bean class consists of both setter and getter public final methods and also implements mentioned interface. The intention is to use this interface outside the model package. Unfortunately, nothing will insist on model’s client to use bean’s interface instead of its implementation. On the other hand, when field access is used, we do not need to follow Java Bean standard.
@Override
public void setTopping( Topping topping ) {
}
super.setTopping( topping );
}
Listing 4. The Bakery class maintains immutability of the ArrayList @Entity
public class Bakery extends BaseEntity {
String name; @ElementCollection List breads;
The Bakery class consists of breads, flavored breads and buns. All are collections of mutable java.util. ArrayList that belongs to external library (rt.jar of the JRE). In such cases we may drive immutable wrapper class that will expose only retrieval methods (e.g. getters) and use it instead. The shortcut solution is to use a mutable object in an immutable way inside an immutable object (e.g. the constructor of the Bakery class uses copy constructor of the ArrayList to get a new reference or the getBreads() method returns Collections.unmodifiableList()) (see Listing 4). The class is keeping values, because it’s a value bean, and maintaining immutability, because it’s an immutable object. The mutability or immutability of the object looks easier when it is a choice of design rather than a subject for method implementation. Therefore, immutable objects should be associated with the objects of the same kind. The JPA (also other ORMs) supports e.g. JRE collections with @ElementCollection annotation, and java. util.Date with @Temporal annotation. If we decide to wrap these classes we will lose those features. To not get crazy, we may accept this as an exception to the preferred approach when we work with JRE components. Besides, JRE is the fundamental Java environment. We may also expect some JSR changes in the future.
Summary
@ElementCollection
List flavoredBreads; @ElementCollection List buns;
public Bakery( String name, List breads, List {
Associations
flavoredBreads, List buns )
super();
this.name = name;
this.breads = new ArrayList( breads ); this.flavoredBreads = new ArrayList<>(
A construction mentioned by James Gosling can be seen as a most loose implementation form. From the practical point of view, entities connected with property access are rare subjects of hash tables. In such occasions we may decide to go for default setter methods. Making objects immutable isn’t the only good advice to take. It can be completely fine to work with mutable and comparable by reference or value objects. It all depends on a use case, although it’s hard to imagine a situation where immutability can’t be provided in one of the described methods.
flavoredBreads );
}
this.buns = new ArrayList<>( buns );
public final List getBreads() {
} }
14
...
return Collections.unmodifiableList( breads );
Damian Czernous Damian Czernous has been working as a Software Development Engineer and a Technical Coach in Nokia Siemens Networks company for the past seven years and is also involved in developing database and Web-based applications, intended primarily for improving auto configuration of the mobile network.
OPEN 03/2013
A Little Bit of Practice
iOS App Development Methodology – S2C2 This article describes an iOS App development methodology called S2C2. The intent of this methodology is to optimize iOS app client development by means of a standardized approach. You will require Xcode to follow along with the sample app creation.
S
2C2 is a play on the abbreviation SSCC. This simple abbreviation covers the scope of the four-step app development methodology: Start It, Stub It, Connect It, and Complete It. These four steps take you through the development of an iOS app. Here is a quick summary of the steps:
• Start It: Beginning the project, selecting templates, and creating project files. • Stub It: Stubbing properties/methods in the .h/.m files in XCode to prepare for work in Interface Builder. • Connect It: Creating the UI and connecting stubbed properties/methods with Interface Builder. • Complete It: Completing the .m code for the stubbed methods in XCode. Once these core steps are applied and repeated as desired, you simply build & run, and you are done!
S2C2 Methodology Step by Step Example
The objective of this step by step example is to create the quintessential Hello World app on an iOS device. This app has a single View Controller containing a Text Field and a Label. The Text Field will allow you to capture user input via the keyboard, and the Label will be used to display the text entry result. In order to achieve these objectives, we will build an application that does the following: • Create and expose a View Controller/View to house our UI Controls • Expose a Text Field that allows user to type something via a keyboard • Display what the user has entered in a Label
16
The following controls will be used to create the app: • Controllers • UIViewController • Input/Display Controls • UITextField • UILabel
Start It
For iOS development, there are two primary facets to the IDE, the XCode IDE for coding and Interface Builder for UI Development. An important concept in iOS development is connecting the objects between the Xcode class files (.h/.m) & Interface Builder files (.xib). Both sides (.h/.m & .xib) must be bridged for connectivity to one another. This ensures that the correct properties/methods are associated/referenced during code execution of the .m file. We will demonstrate these connections with a UITextField, and a UILabel.
Create the Project
To get started – open Xcode, create a new Project (File/ New Project): • Type: Window-based Application • Name: SDKtoday101 Technically, at this point, you’ve just created your first iOS app! Really – it’s that simple. Select Build & Run to test the app in the simulator for yourself. Ok, so it runs, but admittedly, it doesn’t really do anything – so lets continue with the example. In order to write code to interact with properties/methods in Xcode, we have to connect them from the UI to the code.
OPEN 03/2013
iOS App Development Methodology – S2C2
Before we can do that, we need to define the properties/methods. For this project, we will create a new View Controller class. To do this, select File/Add File, and choose the following options:
Editing a class file
• Cocoa Touch Class Template • Select UIViewController subclass
Before we dive into the code, let’s take a moment to look at how we find the controller we need to modify. In the Xcode Groups & Files pane, find the SDK101ViewController.h file, and click on it. The file will now be selected in the File Name pane and you can start modifying it via the code pane.
Set the name/options:
SDK101ViewController.h
• Name • SDK101ViewController.m • Options • UITableViewController subclass: No • With XIB for user interface: Yes • Also create .h: Yes This concludes Step 1 – Start it.
Stub It
In this section we will work exclusively in the Xcode IDE. The objective is to define or stub the properties & methods in the code files (.h/.m). This work is done in preparation to connect them to the XIB file (.xib) via Interface Builder. Listing 1. Objects & methods in the .h @interface SDK101ViewController : UIViewController <UITextFieldDelegate> {
// define text field & label
UILabel *sdkLabel;
}
UITextField *sdkTextField;
// define text field & label properties
@property (nonatomic, retain) IBOutlet UITextField *sdkTextField;
@property (nonatomic, retain) IBOutlet UILabel *sdkLabel;
// define methods to dismiss keyboard & update label - (IBAction)textFieldDoneEditing:(id)sender; - (void)updateLabel; @end
Listing 2. Synthesize properties & stub the methods @synthesize sdkTextField; @synthesize sdkLabel;
Listing 3. Memory tidying - (void)viewDidUnload {
The header file will contain definitions for any properties we’ll need, and in this case, a couple helper methods. First, define the objects & methods in the .h file: Listing 1.
SDK101ViewController.m
Next, synthesize the Text Field & Label properties & stub the methods: Listing 2. Also – as a best practice – it is a good idea at this time to add code that keeps memory tidy: Listing 3. There is one more step to complete in Xcode before we dive into Interface Builder – we need to expose our View Controller so that when we run the application in the simulator – we can see it. To do that, we need to edit the existing Application Delegate.
}
self.sdkTextField = nil; self.sdkLabel = nil;
- (void)dealloc {
// tidy up
[sdkTextField release]; [sdkLabel release]; }
[super dealloc];
Listing 4. Stub View Controller @interface SDKtoday101AppDelegate : NSObject
<UIApplicationDelegate> {
// declare window & view controller
SDK101ViewController *sdk101ViewController;
}
UIWindow *window;
// declare window & view controller properties
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet
SDK101ViewController
*sdk101ViewController;
// tidy up
en.sdjournal.org
17
A Little Bit of Practice
SDKtoday101AppDelegate.h
Much like in the View Controller’s .h file, the app delegate .h file will define any objects we need. In our case, the goal is to expose the view Controller, so we need to update this file to make sure there is a definition for our View Controller to expose it. The code looks like this: Listing 4.
SDKtoday101AppDelegate.m
Finally, we will go to the implementation to add the code that exposes the view. Here is the code to synthesize the View Controller, and expose the view in the window when the application finishes launching. We also add code to dispose the view and clean up the memory when the application is ending (Listing 5). That’s it, we’ve stubbed everything we need before we build the UI & perform our connections in Interface Builder. Listing 5. App Delegate
Connect It
Now that we have defined anchors for the controls, we can wire them up with Interface Builder (IB). When we defined the properties/methods, we used a special identifier that tells Interface Builder we want to be able to connect them to controls we drag and drop in the interface. Here is the key code to re-enforce how this works: Listing 6. Notice the keyword IBOutlet – that is the magic. If you remove it – connections Interface Builder can get confusing in rapid fashion. It is difficult to connect something via the IB Connections Inspector if it doesn’t exist to connect to! Another important note – when coding, before you go into Interface Builder, it is critical to build the project. This will help with two things: • It will ensure all your files are saved to that Interface Builder can find the control definitions • It will help you ward off any typing mistakes or missing punctuation before you proceed
#import “SDKtoday101AppDelegate.h” #import “SDK101ViewController.h”
This way – when you’re done in IB – you’re ready to build & run.
@implementation SDKtoday101AppDelegate
SDK101ViewController
@synthesize window;
@synthesize sdk101ViewController; - (void)applicationDidFinishLaunching:(UIApplication
// expose view
*)application {
[window addSubview:sdk101ViewController.view]; [window makeKeyAndVisible]; }
- (void)dealloc {
// tidy up
[sdk101ViewController release]; [window release]; [super dealloc];
}
To get started in Interface Builder simply double click the SDK101ViewController.xib file. Add the UI Controls In Interface Builder add the Text Field & Label by dragging them from the library window to the view. Connect the UI Controls To make a connection in IB, simply drag from the Connections Inspector outlet to the appropriate control. First, set focus on the File’s Owner then press command + 2 to bring up the connections inspector. In our case, we have two outlets to connect, a Text Field & Label. Have a look at the screenshot, below, what you should note is the IBOutlets you defined earlier, then the drag/drop to the control: Figure 1.
@end
Listing 6. IBOutlet Stubs // define text field & label properties
@property (nonatomic, retain) IBOutlet UITextField *sdkTextField;
@property (nonatomic, retain) IBOutlet UILabel *sdkLabel;
Figure 1. IBOutlet Connection
18
OPEN 03/2013
iOS App Development Methodology – S2C2
The final step is to wire up the new textFieldDoneEditing IB method to the Did End On Exit event for the Text Field control. This is slightly different than the IBOutlet because in this situation we are mapping an IBAction. This method will release the keyboard when we’re done typing! To make this connection, do the following: • Highlight File’s Owner • Find the action placeholder for textFieldDoneEditing • Drag & Release it on the UITextField that will be rendering the keyboard for user input • A pop up dialog will appear with the keyboard outlet options, choose Did End On Exit The following screenshot illustrates what this will look like: Figure 2.
Figure 2. IBAction Connection
When you are complete, the Connections Inspector should look like this: Figure 3.
MainWindow
At this point, lets recall briefly when we started this adventure, we chose a windows based application, and we got something called MainWindow.xib as a result. This xib contains our App Delegate, which is responsible for rendering our application, so, next, we need to connect our view controller to the app delegate. There are a few steps we need to perform to complete this final connection: • Add a View Controller • Change the Class of the View Controller to pont to the View Controller we created in Xcode • Connect the View Controller to the App Delegate Add the Controller When adding the View Controller to the window, the process is as simple as when you added the UILabel in the previous section. The first step remains the same, we locate the Control in the Library pane (Cocoa Touch – Controllers), this time we are looking for View Controller. Select the control and drag it to the MainWindow. xib window, and drop it immediately under the Window item. The Figure 4 illustrates what the end result will look like (of course you still have a few more steps to perform before reaching this point): Notice that we updated the View Controller reference to ‚SDK101ViewController’. The steps to do this are defined below: Change View Controller Class • Highlight the row View Controller • Press Command + 4 to bring up the Identity Inspector
Figure 3. Connections Inspector
en.sdjournal.org
Figure 4. MainWindow
19
A Little Bit of Practice
• In the Class dropdown list, find & select SDK101ViewController
lines away from crossing the finish line via the Complete It section!
Connect the Controller Finally, we need to connect our View Controller to the App Delegate so that when the application loads, we can see our view! Highlight the row App Delegate
Complete It
• Press Command + 2 to bring up the Connections Inspector • Find sdkView101Controller in Outlets & drag it to the View Controller row in MainWindow.xib Save everything, then Build & Run your project to see it in action! You should see that your application loads – and looks much better than before – but still doesn’t really do very much. Well, that is not entirely true – it let’s you type in the Text Field with a magical keyboard – but the keyboard feels less magical when you realize you can’t seem to get rid of it. There was also the matter of updating that label. Don’t sweat it; we are just a handful of
As you may recall, in Stub It! we added the method declaration to hide our keyboard after the user is finished typing, and to display the result to the user. Now we need to implement the logic to make that happen. In this section we will: • Add code to enable trapping the keyboard done button • Complete the contents of our shell updateLabel method to write some text to the label
SDK101ViewController
All of our methods are located on the View Controller, so navigate to SDK101ViewController.m and we will complete the code. textFieldDoneEditing Here we will complete the method that we stubbed to capture the Text Field Keyboard Done button tap event. This code hides/dismisses the keyboard (Listing 7).
Listing 7. Hide/Dismiss Keyboard - (IBAction)textFieldDoneEditing:(id)sender {
// hide keyboard on done click
// update the label
[sender resignFirstResponder];
[self updateLabel]; }
Listing 8. Update Label - (void)updateLabel {
// get input
// check if any input was provided
NSString *nameString = sdkTextField.text; if ([nameString length] == 0) {
// no input – default name }
nameString = @”SDKtoday”;
// build message string for label
NSLog(@”SDK101View.updateLabel – set messageString: %@”, messageString);
NSString *messageString = [[NSString alloc] initWithFormat:@”101 \n%@!”, nameString]; self.view.backgroundColor = [UIColor colorWithRed:0.000 green:0.060 blue:0.100 alpha:1.0]; // set label text to message string sdkLabel.text = messageString;
// notice we tidy up message string – but not nameString // this is because they were initialized differently [messageString release];
}
20
OPEN 03/2013
On the Web • • •
http://sdktoday.com/ – SDKtoday App Website http://kengin.ca/ – Jacob’s Corporate Consulting Website http://kallergisconsulting.com/ – Demetree’s Corporate Consulting Website
updateLabel Here we build the message string by concatenating a string message with the text entered in the Text Field. Notice how we formatted the string for display, and then used it to update the Label (Listing 8).
That’s a Wrap!
That wraps up the Complete It section, and the stepby-step example for the S2C2 app development methodology.
Summary
This is a very simple introduction to the S2C2 app development methodology. For additional app examples, video tutorials, and full source code, check out the SDKtoday app in iTunes. SDKtoday was written in collaboration with Dennis Volovic of Dedovo Inc. Once you master these topics and are ready to consider taking your apps to the next level with application server integration – you can check out another project I am collaborating on with Demetree Kallergis. The project/app are called Server also available in the iTunes app store by searching Kallergis Consulting
Jacob Kennedy Jacob Kennedy has 15+ years experience in the IT field ranging from large enterprise to individual consumer clients. He is currently working as an enterprise CRM professional services consultant by day, and entrepreneurial developer on various passion projects during evenings and weekends.
en.sdjournal.org
Deeper Delegation It has been said that the delegation pattern is simple. It is kind of like saying that skating is simple, but, try imagining it if you have never seen anyone skate before. More so, try doing it if you have never seen or done it before. It’s abstract. Skating or riding a bicycle, like many other things, becomes simpler with practice.
S
o, yes, delegation can become simple IF you have behind you the fundamentals such as abstract thinking, an understanding of the steps involved, knowing the proper order things need to be in to utilize delegation, and the right amount of practice. Something else to keep in mind is that the delegation pattern does not only apply to iOS and Objective-C; delegation is an object-oriented design pattern wherein an Object delegates tasks to an associated helper Object. Though the delegation pattern does not belong to Apple, they certainly use it a lot. Many different programming languages can utilize the delegation pattern. (See: http://en.wikipedia.org/wiki/Delegation_pattern). Inside different languages you may find that the term “Interface” is used instead of “Protocol”. Since our focus in this article is on Objective-C we will use the syntax “@protocol” as opposed to “Interface”.
So Many Questions
If you are new to the topic of delegation, particularly when it applies to iOS, you may have wondered about several of the following. What is the difference between the AppDelegate set of files and your class being a delegate or having a protocol? Why is there a need to both specify (define) things in your class definition .h file? Why do I need to define a class name when I define a protocol with a method that instantiates a class? Why must I first do a #import; of something like “MyAmountDelegate.h”, and then specify another reference to it using something like <MyAmountDelegate>, then declare a property of type ID (id) called delegate, and finally implement it into my implementation code, .m file? That seems like so much work! How do I work with segues when delegation is involved? Before I have my current view controller, why must I do something like viewController2.delegate =
22
self? Why do AppDelegate files have methods that have so many weird words in them such as: will, did, should, can, etc.? Why is it so difficult to grasp how one Object is able to talk to another Object? Let’s first try to help you by addressing several things many of my students miss or may even forget when it comes to writing code in C or Objective-C, particularly when it involves delegation.
Things Missing or Forgotten
Before we get into explaining delegation I would like to declare something; that is, I would like to express something with clarity and great emphasis. I want to emphasize something. I repeated the above for good reason as I have noticed a peculiar thing when teaching the topic of delegation. It seems that the students who tend to have trouble grasping the topic of delegation often forget or do not understand the underlying purpose of “declaring” something. For example, why declare a property called “delegate” with a type of id? Think about it, in real life, the simple reason we declare anything is because we expect it to be put to good use by someone, something, and that it takes on a purpose. Otherwise, what’s the point? It is similar when we declare something in C or Objective C. We intend for it to be put to some good use. Keep in mind that when you declare something it should have a purpose. What is the point of declaring something in your .h file if you are not going to use it? Enough said. . . just remember this point since it will help you advance in your understanding of the topic of delegation, particularly with reference to the id type.
An Illustration About Events, Messages and Parts
Let’s use an illustration, keeping in mind the thought that delegation is a pattern that simply helps one Ob-
OPEN 03/2013
Deeper Delegation
ject cooperate with another Object. Take for example, a real life situation. An employer hires an employee because he needs a helper. The employee listens for messages from the employer and handles them. The employer can notify the employee that someone else is about to do something or that they have already done something. By acting on the event that they have the right and ability to change they are a good delegate. In some cases the employee can even change the affects of how a coming event is going to be handled in advance of it happening. The employee provides customize behavior taking into consideration many factors and acts as a central resource in advance of things happening, while it continues to happen, or after things have happened. As a developer, you might liken yourself to a knowledgable consultant hired by a company to write certain policies and procedures. The @protocol inside your code is like the policies that the employees of the company follow. You may begin by grouping the policies (Required and Optional) along the procedures (the methods). If the company is very large and very structured, these are like the different framework that you add into your Xcode project and then you use the frameworks by using parts and pieces from them. As a side note, keep in mind that you are not an employee, but rather you are a third party, that is typing code that helps the Employer-Object work with or collaborate with Employee-Objects. Naturally, most employees would need direction and would otherwise not feel very comfortable performing as a helper without direction on how to function in their respective roles. Similarly, I will walk you through some of the things you (as a consultant or coder) need to take into consideration, pull together, understand and remember when using delegates and protocols. As a coder you understand that in most cases, the employer (the delegating object) is typically a fairly structured organization (a framework object), and not necessarily a single individual. The employee (the delegate object) is typically one that can be customized and controlled to a reasonable degree (a custom controller object). Also, the employer does not want to micro manage its employees and overburden himself or his managers by filling them in with every little detail of the tasks handed off to and handled by the employees. So too, the employer keeps only weak reference to his employee delegates as work gets handed off further down the line. With this now said, here is Apple’s opening paragraph explaining delegation:
Delegation
Delegation is a simple and powerful pattern in which one object in a program acts on behalf of, or in coordination with, another object. The delegating object keeps
en.sdjournal.org
a reference to the other object – the delegate – and at the appropriate time sends a message to it. The message informs the delegate of an event that the delegating object is about to handle or has just handled. The delegate may respond to the message by updating the appearance or state of itself or other objects in the application, and in some cases it can return a value that affects how an impending event is handled. The main value of delegation is that it allows you to easily customize the behavior of several objects in one central object.
Delegation and the Cocoa Frameworks
The delegating object is typically a framework object, and the delegate is typically a custom controller object. In a managed memory environment, the delegating object maintains a weak reference to its delegate; in a garbage-collected environment, the receiver maintains a strong reference to its delegate. Examples of delegation abound in the Foundation, UIKit, AppKit, and other Cocoa and Cocoa Touch frameworks.
Remember: Don’t Forget To Tell Messages Where To Go
When you look at code examples, take note of where the type id is defined. That is, when you see a line in their .h file where the following is: id <DataCollectionDelegate> delegate; be prepared to use it, that is, implement it in a .m implementation file somewhere. Do not forget about it; it has a purpose. The purpose is for delegates to be able to send messages. That’s it. It’s there in your implementation code to let one object work with another object. Where does it send these messages? It sends the messages to where you set the “.delegate”; that is, you are specifying where (what instantiated object) you want the messages to go. One of the most common mistakes made is to forget to tell messages where to go. For instance, [vc2 setDelegate:self]; will send the messages from the vc2 object to you (self) which might be a vc1 object. Normally you want messages to go to “you”. You may also want to take note that [x setDelegate:self]; is the same as x.delegate=self. The point is that if you forget to do this, there will be no errors, no warnings; the messages will go into limbo, or absolutely nowhere. You then become lost trying to figure out what went wrong.
Indicate Which Code Is To Act As a Delegate
You must also specify that some of your code (e.g. your view controller) needs to act as a delegate and use a delegate protocol. You do this by placing the name of the delegate in angled brackets at the end of the @interface line. The following is an example: @interface ViewController : UIViewController <DataCollectionDelegate>
23
Keep in mind that you can add more than one delegate by separating delegate names with commas (not more angled brackets).
Delegation Is Not Inheritance?
Another thing you must understand is that delegation is not inheritance. (See my article in the May Issue of the Software Developers Journal on iOS development.) With inheritance, it’s as if you are forced to buy the whole bicycle just because you want to utilize the functionality of a bicycle wheel. With delegation, on the other hand, you can buy (or utilize) just one bicycle wheel component. Lets talk about putting together a physical project using an literal bicycle wheel.
An Illustration: A Physical Representation of a Framework Component
In this illustration, I will compare a physical device to the UITableView controller component that Apple ships with the iOS SDK. To get started, let’s imagine that you want to come up with an idea for a game wheel that uses a physical bicycle wheel. You also want to turn your idea into a reusable component you call “Multi-Winning Spinning Wheel” and want to sell to people to reuse. The purpose of your component is really just a simple “Prize Wheel” where someone applies the action of spinning the wheel (a Gesture); however, you realize you need something to hold the wheel up. (a UIView). You want the wheel to randomly stop on one or more numbers at the same time for one or more people to
Figure 1. Physical Framework Example
win a prize at the same time. Your wheel has 36 spokes (numberOfRowsInSection) possibly making it able to handle up to 36 prizes. Although you ship this product out, there is some assembly required, some settings to be assigned and some adjustments to be made. Some instructions (a Protocol) needs to be provided as to how this prize wheel can be set up and implemented by the set up person (the Developer or coder). In your Protocol you specify that there are two REQUIRED instructions to set things up or configured (implement). For example the total count of spokes you plan to use, (numberOfRowsInSection) that end up representing the total number of prizes to be won. You will also need to identify the spokes to be used (cellForRowAtIndexPath) once they are stopped upon. However, the wheel will still spin even if the two required implementation settings are not setup. You will still see the spokes moving, but that’s all. Although your wheel is somewhat interesting, in the fact that it spins, it is not really serving the full intended purpose yet. This is much like the UITableView without setting up who’s its delegate is. To use it more effectively, though, some OPTIONAL things are needed to do for your prize wheel component to be more useful. For instance, it would be good to set some values for the labels before you use it, or you might want to add more Card-Stops (numberOfSectionsInTableView). Your Spinning Wheel is shipped with all the items put together: Steel Plate, Bolts, Nuts, Wheel, Card-Stops and instructions (like the @protocol with its list of methods) for setting up and using it (Figure 1). Now compare this to the product Apple ships, the UITableViewController. Here are the REQUIRED and OPTIONAL methods for a UITableView (Listing 1). The following is what each user of your component needs to setup before using it: • Setup the wheel by mounting it on the metal plate so the rotation function works. (Drag the UITableView Component to a UIView, Build and
Listing 1. Required and Optional protocols @required
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section; - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *) indexPath; @optional // Default is 1 if not implemented - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView; - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section;
24
OPEN 03/2013
Deeper Delegation
Run and the Picker View Wheel spins, but it’s not really serving any useful purpose yet.) • Indicate the total number of prizes than can be won in a game by setting the number of spokes to be used. (Implement the UITableView method called numberOfRowsInSection). • Now you want to add the correct number of labels that indicate what prize numbers were won. These are attached to the appropriate number of spokes that were chosen in the wheel framework in step 2. (Implement the titleForRow at index for the total number of rows in step 2) • Indicate how many prizes can be won at a time by setting up magnetic stop-on cards. Place the correct number of playing cards that have a magnetic base onto the metal plate that holds the wheel in place. Now when the wheel is spun, it stops as multiple cards end up sitting between different spokes, thus indicating how many prizes can be one at a time. (Implement numberOfSectionsInTableView for the simultaneous winners.) You’ve just created a reusable framework similar to the UITableViewController.
NOW STOP
Now stop and NOTE this fact. You as a developer have not yet told the Prize Wheel (UITableViewController) to SEND ANY MESSAGES to any other objects. It is only setup and bolted to the metal panel (dragged onto a View). Your wheel has protocol methods to send messages; however, they are not yet setup. It is similar to how a TableView has protocol methods available to set things up further; however, before we can send messages to another object, we need to set those up. We could go on with setting up a data source for the list of prizes to be won but we won’t because this is for illustrative purposes only. Let’s suppose instead that this is setup already. In fact, I will be putting together a separate article on using TableViews with Data Sources in another article on CoreData. I want to bring you to the point of seeing the need to setup objects to send and receive messages, and acting on these (the messages) once the wheel stops and a prize or a number of prizes are selected.
Message Sending
Now you want your Prize Wheel to send a message when the wheel stops spinning and lands on one, two or more labels. After you spin the wheel, there is one last click, and the playing cards are left between spokes marking the locations. Now what do you want to happen? When a prize or more is stopped on (or selected), you have a list of prizes on a sheet of paper that
en.sdjournal.org
match the numbers on the labels. In effect, a message is sent by our wheel as the number(s) are indicated. The wheel, in essence, sends a message when the wheel stops on certain cards. As part of your protocol, one of your procedures (methods) explain that after the wheel stops, a person (delegate) reads out each number which represent what prize(s) have been won. This stop event triggers the helper person, (a delegate helper class) who was listening for the wheel to stop, to handle the messages from this stop event. How they handle it is, they yell out something like, “didSelectRow at Spoke Number 7”, “didSelectRow at Spoke Number 12”, “didSelectRow at Spoke Number 18”. This is similar to the UITableView component in that it has the ability to send out messages that look for the helper class methods that will handle the didSelectRow method. This would be the class that is declared as the TableView delegate. It is this delegate that must handle the behavior for the messages being sent. Now we are talking.
What Happens When An Event Occurs
As a small example, what happens with a UITableView when a cell is touched? When a cell is touch, the UITableView triggers an event. It then looks to see if there is a class object id to send the message to. If there is no pointing reference to an object’s id, the message does not know where to go and in effect it is not sent. The nice thing about delegation is that we can tell it that it’s messages must be sent to our specific class object id. Once it is defined, then our code can receive and handle the notification or message. To do so, there are several things that need to be set up in the class so that its object (each object has an id) can handle the message. When a TableView cell is selected it needs to know which object “id” it should send the message to. Once it knows the object id to send it to, it then looks for the method signature “didSelectRow” that you either typed or copied and pasted into your class code. You get this template like code from inside the UITableView.h file from between its @protocol section. If you did not add the didSelectRow method into your class and it was between an @required section, Xcode will let you know. However, if it was NOT required and it was only between an @optional section, then this event would not get handled by your class. You might say, the touch event was wasted. If, on the other hand, you typed or pasted this “didSelectRow” @protocol method into your class, you can then type additional code inside the body of the “didSelectRow“ method to do something with the message data that was passed to the object id (your class object id) method.
25
See Listing 2 where the “didSelectRow” message contains the row that was selected within the component. Where is where we do something extra with the data such as printing out to the screen the row was selected.
Steps Required
What helps my students most is a thorough explanation of the required steps that must be in place for iOS and delegation to work.
The Order Of Things
The following things need to be understood when creating and/or using delegates. Read this first, and for now, forget about worrying too much about fully understanding it yet; however, use this list as a reference as you go through the section entitled “STEP BY STEP TUTORIAL” to make sure you cover all the areas needed. • See Listing 3 to define a class name inside the definition .h file. Also have a look at the second line of Listing 4. Notice where it defines a type named DataCapture that is used to create an object named controller2. If you don’t create this class, the second line in Listing 4 will not know that there is a type of class called DataCapture and you will get an error. The sample code snippet in Listing 3 below defines a class called DataCapture. • Now you can set up a protocol in the .h file that contains a method that uses the class in step 1 above. Listing 2. Handling a Touch Event - (void)TableView:(UITableView *)TableView
didSelectRow:(NSInteger)row inComponent:(NSInteger) component { /* Display what row was selected */ NSLog(@”Hey, someone selected row %d”, row); } Listing 3. Defining Our Class Name
@class DataCapture;
@protocol DataCaptureDelegate <NSObject>
• In the same .h file define a week nonatomic “id” type naming it “delegate” for your delegator. Later, don’t forget to use the id type defined here. You need to tell it where to send messages so that messages can be sent from one object to another. The sample code snippet in Listing 4 are the rules or Protocol so that other objects can take on this functionality. The objects .h file that defines this protocol is the DELEGATOR, not the Delegate. The object that wants to use this method must say that it agrees to be a delegate as in step 7 further down. • DO NOT FEEL that you must implement the method contained in the protocol you defined in the .h file of step 2 into the .m file. • However, DO FEEL that you may need to implement the method for the object that is utilizing the delegate protocol. • In your delegate .h file code, make sure you #import the file for your @protocol. • An object that agrees to be a delegate must say that it adopts the protocol of the delegator by name. It must place the name of the Delegator between two angled brackets for the object that will act as a delegate for the protocol. For example: <DataCaptureDelegate>. • If you are leaving a current view and you are either doing a Segue or you are using the presentViewController this is where you can use both the method in the protocol created in step 2 and the id type created in step 3. For example, before a new View is pushed onto the navigation controller, set the delegate property to self. Before a new View is pushed onto the navigation controller, with code, set any of the new Views properties to a property that you would like to use when the user selects an item. To simplify message sending we are not yet going to demonstrate how to use TableViews. Instead we are go-
Listing 4. Define Protocol To Pass Data
-(void) passData:(DataCapture *) controller2 didFinishWithDataCollection:(NSString*) data; @end
26
Figure 2. Our Sample App
OPEN 03/2013
Deeper Delegation
ing to create our own, a much simpler delegator and use it in a project, to demonstrate how messages can be passed with Delegation from one view to another.
Some Practice
Now lets go back to my opening comment at the beginning of this article: “It’s been said that the delegation pattern is simple things also become simpler with practice”. Lets try to make things more understandable with a bit of practice. Further in a section below this, you will find a “STEP BY STEP TUTORIAL” where we will practice developing a simple application with two views similar to Figure 2. The view on the right collects data in a “Text Field” and through a delegation message, we update that data to the label in the left view. With these views, when a user taps on the “Forward To Data Collection View”, the current ViewController “DATA PRESENTATION VIEW” requests that it is able to receive a message from the “DATA COLLECTION VIEW”. This can be done by ONE of the following pieces of code in Listing 5 and 6. Keep in mind that this code actually goes into the view controller on the left, the “DATA PRESENTATION VIEW”. Keep this in mind as we proceed with the tutorial shortly. You can use either one the styles of code from Listing 5 or 6 inside the initiating viewController. At this point, if you jump ahead and start typing the above code of Listing 5 and 6 into Xcode, you will get errors. That is because you need other things in place to make delegation work properly. It is important to understand that, when using Delegation, there is an order of how to configure your code. As we proceed through the tutorial for our two views, this is where you should reference the above section in this article entitled The Order Of Things for a better understanding.
Step By Step Tutorial
Open Xcode and create a new “Singe View Application” project and name it “DelegateDataPassing”. Use Storyboards and Automatic Reference Counting. Open the Storyboard and create the views in Figure 2. Drag on two labels at the top of each view labeling them “DATA PRESENTATION VIEW” and “DATA COLLECTION VIEW” respectively. Also, drag one more label onto the first view and label it “Data Goes Here”. Drag a Round Rect Button onto the first view and label it “Forward To Data Collection View”. Drag a Text Field onto the second view. Drag another Round Rect Button onto the second view under the Text Field. Size each component so that it looks like Figure 2 and you can finally add the yellow and green colors to the views to help you visualize a little easier when you
en.sdjournal.org
switch views. Now choose File, New File and select “Objective-C class” to create a new class of type “UIViewController” and name it ViewController2. Go back to Storyboard and click on the second view, (the one on the right). Then to make sure you’ve chosen the View Controller, click on the View Controller icon, as indicated in Figure 3. Then switch to the “Identity Inspector” by clicking it as indicated in Figure 4. Now, using the drop down, change the Class from UIViewController to ViewController2. (Note: that it should be at the bottom of the list) Now the Data CollectionView has it’s very own, independent, controller class. Next, you can make a decision if you want to use a Storyboard Segue to change from one view to another view or use the presentViewController method. You are free to create either a Storyboard segue’s when the user touches the button on the “DATA PRESENTATION VIEW” to move to the “DATA COLLECTION VIEW” or you may choose to use the presentViewController function. I find the presentViewController function requires a little less code for demonstration purposes, so that’s what I’ll use. Listing 5. Setting Delegate to Self Option 1 dataCapture.delegate = self;
Listing 6. Setting Delegate to Self Option 2 [dataCapture setDelegate:self];
Figure 3. Selecting The View Controller
Figure 4. Switching to Identity Inspector
27
However, before I leave you dangling, wondering how to use segues I’ll explain a bit here. If you are using a storyboard segue you first need to create a segue from the goToDataCaptureViewButton. Therefore control drag the Button from the left view to the DataCaptureViewController and choose “Modal”. Then, first click on the segue icon and then open the “Attribute Inspector” for the “DATA COLLECTION VIEW” and then give an Identifier name to the segue and call it “segToDataCapture” as in Figure 5. Now open ViewController2.h and, after the #import <UIKit/UIKit.h> line, declare a class as in step one of the section The Order Of Things. READ the reason why. Don’t just copy and paste; understand why this class needs to be here. The @class should look like the next line. @class DataCapture;
Now we are going to set up our own Protocol so we can better understand Delegation rather than just becoming a delegate to someone else’s Protocol. While still inside the ViewController2.h file, right after the @class line, enter the code in Listing 7. Note that for Listing 6, we are defining a method called passData based on the class we defined earlier. However, we know that it is wrapped inside an @proto-
col, so its purpose is to be implemented by a delegate that agrees to implement and handle things for when it gets triggered. When it gets activated, note that it has two parameters. The first parameter represents the object dataCapture and the second is a parameter that passes a NSString object called data. Watch where this gets used and note the name that we gave the second parameter didFinishWithDataCollection. You might read the function from right to left, in listing 6, this way, “Now that I’m finished with data collection and the class DataCapture, I’ll just send a message to a function in some object that includes a property called data with my method passData.” Huh? “some object”? This is where the next step comes in: Right after the line @interface ViewController2 : UIViewController, enter the code from Listing 8. What does the line in Listing 8 mean? Making the declaration for the id type weak, nonatomic, allows objects to interact with other objects without creating a strong interdependency between them. When Automatic Reference Counting (ARC) releases the object, the objects are more willingly released. The id is a pointer type that can be used to point to any type of object. So, if I instantiate this particular Object called delegate, we know this is based on a class that is related to our DataCaptureDelegate. What we are doing here is declaring a property called delegate with id type to reference whatever DataCaptureDelegate needs to send messages to when it is used. When we later use this in an implementation .m file, we can have it point to the other object we are working with using the thing that represent it, called self.
Is Anyone Listening?
Figure 5. Giving a Segue an Identifier
For instance, we can set things up so that just before we segue over to another Data Capture View, we can, (Remember: before we leave our current view), prepare our object to start listening to our delegator object for when the passData method gets triggered and act on
Listing 7. Setting Our Protocol Message Signature @protocol DataCaptureDelegate <NSObject>
-(void) passData:(DataCapture *)dataCapture didFinishWithDataCollection:(NSString*)data; @end Listing 8. Setting Up The Important id delegate @property (weak, nonatomic) id <DataCaptureDelegate> delegate;
Listing 9. Defining Field in View Two To Capture Data @property (weak, nonatomic) IBOutlet UITextField *viewTwoData;
28
OPEN 03/2013
Deeper Delegation
it. To do this we can use something like [dataCapture setDelegate:self] or we can use dataCapture. delegate = self, which are both equivalent. This very line allows this (self) object to listen to the object, that owns the delegate protocol, for when it is triggered inside the delegator and have a message containing data sent to it (self). Now somehow, in my ViewController2, I want to define where I want to capture my data. So I click on my “DATA PRESENTATION VIEW”, making sure my Assistant Editor is selected. I then control drag from my “Text Field” in the “Data Collection View” to the line just below the previous line we entered in Listing 8. Create the following UITextField named “viewTwoData” as indicated in Listing 9. There is another thing I need to do in my ViewController2.h file. My button that is labeled “Back To First View” needs to have a method that closes the View. HOWEVER, there is something else REALLY IMPORTANT that happens here. Something needs to trigger a MESSAGE to get SENT. THIS IS IT. This button is similar to touching a cell in a UITableView. So, next, to add this code, make sure the Assistant Editor is still selected, and then control drag from the “Back To First View” button to the line just below the one in Listing 9. After you let go select “Action” and name the action “backToView1”.
Figure 6. Make Sure Assistant View Is Open
Now I need to go to my .m implementation file and locate the method named backToView1 that just got automatically created for you. Enter the following code in Listing 10 between the braces. This is where the cool stuff begins!. Remember we said earlier that we needed to implement our @protocol method from inside the delegate object. Well, that’s what we are going to do next. Lets go back to our Storyboard and click on the first view(the one on the left) with the label named “DATA PRESENTATION VIEW”. Then, to make sure you have chosen the View Controller, click on the View Controller icon as in Figure 3. Be certain that the “Assistant View” is open for UIViewController by clicking it as indicated in Figure 6. Be sure the ViewController.h is opened since there are several things we want to do with this file. • Import the ViewController2.h file into the ViewController.h file. Under the line #import <UIKit/UIKit.h> place the line that is in Listing 11. • Indicate that this View agrees to be a delegate of the delegator. To do so, you must place the name of the Delegator between two angled brackets for the object that will act as a delegate for the protocol. For example: <DataCaptureDelegate> placing it at the end of the interface line similar to Listing 12. • Connect the label named “Data Goes Here” as well as the Round Rect Button entitled “Forward To Data Collection View” to our ViewController.h definition file. To do so, click and drag from the label “Data Goes Here” to the ViewController.h file and create a property called viewOneLabel. Next, control drag from the Round Rect Button entitled “Forward To Data Collection View” to our ViewController.h, create an Action item and define its name as “openViewController2”. This automatically created a method in the .m implementation file named “openViewController2”. • Open the ViewController2.h file; then highlight the method after the @protocol that looks like the code in Listing 13.
Listing 10. Passing The Data and Dismissing View 2 [self.delegate passData:sender didFinishWithDataCollection:self.viewTwoData.text];
[self dismissViewControllerAnimated:YES completion:nil];
Listing 11. Importing our ViewController 2 #import “ViewController2.h”
Listing 12. Agreeing To Be A DataCaptureDelegate @interface ViewController : UIViewController <DataCaptureDelegate>
en.sdjournal.org
29
• Open the ViewController.m file again and enter or paste the line of code that is in Listing 13 into it, delete the semicolon and replace it with an opening brace { and a closing brace } so it looks like Listing 14. • This is where you place the code that will update the label property we named “viewOneLabel” located in the “DATA PRESENTATION VIEW”. Between the braces in the passData method, enter the code that is in Listing 15. • This is a very important step. Listing 16 has code entered between the braces for the method that got created. We named this openViewController2 when we control dragged our button into the ViewController.h file. We do something interesting before we segue over to the ViewController2, the DATA COLLECTION VIEW. When we touch up inside the button on our initial ViewController the first line between the braces instantiates it with an instance name vc2. The second executing line is a test to prove that vc2.delegate.description is null by printing a message to the console. The next executing line prepares our current ViewController to be able to listen to the ViewController2 by causing vc2‘s delegate to point to self, that is ViewController. We do this with the line, vc2.delegate = self; Then, the next executing line runs the same test again after making vc2.delegate equal to ViewController. When this is run, it displays that the object name of vc2.delegate.description is in fact ViewCon-
troller and not ViewController2. Now the final executing lines are interesting in that we dismiss our current ViewController object; however, what’s interesting is that the ViewController code itself does not go off into oblivion. Rather, it attaches vc2 to itself (self) acting as the parentViewController to vc2. Then it uses the method presentViewController to display ViewController2. Now vc2 is able to listen when class vc2’s button is touched, and it itself is the delegate responsible for handling all the events fired by the instance of the vc2 class. Also, when the button is pressed on vc2, it executes the code in Listing 14. Since the code in Listing 15 is within the braces of Listing 14, it sets the label we have in our first view controller equal to the data property that got set in our vc2 controller by executing self.viewOneLabel.text = data;. Then, all we need to do is segue back to the first ViewController; it displays our label updated with its new data with Listing 10 and we’re done.
Segue’s versus PresentViewController • One Way Using PresentViewController: Listing 17 • Another Way The Storyboard Segue: Listing 18 Build this code and run it, click the button that takes you to the view to collect data and watch it pass it back to the first view.
Listing 13. Defining Our Protocol Method -(void) passData:(DataCapture *)dataCapture didFinishWithDataCollection:(NSString*)data;
Listing 14. Implementing Our Protocol Method -(void) passData:(DataCapture *)dataCapture didFinishWithDataCollection:(NSString*)data {
Listing 15. Updating The Data In The First View self.viewOneLabel.text = data;
Listing 16. How Messages Gets Passed Around - (IBAction)openViewController2:(id)sender {
ViewController2 *vc2 = [self.storyboard instantiateViewControllerWithIdentifier:@”vc2”]; // Prove that vc2.delegate.descripton is equal to null and not yet to ViewController NSLog(@”\nSelf is: %@”,vc2.delegate.description); vc2.delegate = self;
// Prove that vc2.delegate is now equal to ViewController and not ViewController2 NSLog(@”\nSelf is: %@”,vc2.delegate.description);
[self dismissViewControllerAnimated:YES completion:^{
}
30
}];
[self.parentViewController presentViewController:vc2 animated:YES completion:nil];
OPEN 03/2013
Deeper Delegation
Listing 17. Option For Storyboard presentViewController ViewController2 * dataCapture = [self.storyboard instantiateViewControllerWithIdentifier:@”segToDataCapture”];
dataCapture.delegate = self; [self presentViewController: dataCapture animated:YES completion:nil]; Listing 18. Option For Storyboard prepareForSegue - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:@”segToDataCapture”]) { DataCaptureViewController *dataCapture = [segue destinationViewController]; [dataCapture setDelegate:self]; } }
What Are The AppDelegate.h and .m Files For?
When your app is running, there are some events that happen that are NOT DIRECTLY RELATED TO A SPECIFIC VIEW of yours but these events happen with your whole app. This is where the AppDelegate.h and .m files come into play. They relate to your app as a whole. For instance, the AppDelegate can “help” you to take care of some things, that might need to take place when something happens. If, for instance, someone calls you on an iPhone device, what happens to your app? Also, what happens to your app If someone presses the home button on the iOS device and it takes you to the springboard (or home screen)? The AppDelegate has a number of protocol methods. As an iOS developer, it is important to understand the order or when these methods are invoked. The AppDelegate file contains protocol methods named applicationWillEnterForeground, applicationDidBecomeActive, applicationWillResign Active, applicationDidFinishLaunch and others. As an example, a specific protocol method automatically gets triggered when an application wakes up by switching to another app, or relaunches an app, or starts an app from the springboard (home screen). This method is called applicationWIllEnterForeground. It gets triggered only once after your app moves from a background mode to a foreground mode. Put any code inside this method for code you want to run only once. With an iPhone device, when it rings, the method applicationWillResignActive gets invoked; however when your phone call is finished, the method applicationDidBecomeActive, automatically gets invoked. It also gets called after the applicationWillEnterForeground, just discussed above, gets invoked. Also, if an alert view pops up that is not part of your app, applicationDidBecomeActive gets called after it is done. So applicationDidBecomeActive can get invoked any number of times after the application is launched. It is much dif-
en.sdjournal.org
ferent than applicationWillEnterForeground which gets invoked only once.
One Last Comment On One Big Benefit of Delegation
As mentioned in my Editorial, I did mention, the more functionality you create in a language, the more restrictions apply. However, sometimes the disadvantages of restrictions are good. Someone might think that delegation is a disadvantage because when their classes agree to use required methods, their code become very dependent on their software operating a very specific way. However, when it comes to high quality standards that Apple provides, this is generally seen as very beneficial. The real benefit comes from having a common look and feel with familiar functionality across various systems. Cocoa and iOS use delegation so that our customers continue to become familiar with all our software and they continue to just love to use it.
Doug Panchyshyn The Author has been designing systems, developing software, configuring and administering servers for over 20 years. He has been a Solutions Architect for government organizations including International, Federal, and State Governments in addition to Health Information organizations and numerous Mobile Telecom Companies. Doug is particularly passionate about creative, tenacious, value-driven people, businesses, and organizations and loves to be on the leading edge of great technologies. Doug is often commended for his amazingly creative abilities and open-mindedness. He focuses on the C type languages, including, C, C++, Objective-C, Java, Python, etc., developing Native iOS code for both In-House Enterprise apps and App Store apps, in addition to Micro Controller Automation solutions. http://www.LinkedIn.com/in/dougpan.
31
Securing your Core Data Any application that is data-centric and where its core value is in the data should use some form of additional security measures to protect against theft. This article presents some simple steps you can take to encrypt that data and protect the key used in the encryption process.
A
ppleâ&#x20AC;&#x2122;s mobile operating system has a number of security features to protect against data theft and compromising the device and to make sure applications cannot negatively affect each other (such as sandboxing). For example if a pin code is used, the OS uses hardware encryption to protect the contents of the phone while the screen is locked. The security model is designed primarily to protect the owner against theft of data by a 3rd party rather than that person being the perpetrator of the theft. This means that your application needs more protection than the OS offers by default. For example, if the application uses Core Data with an SQLite backing store, then this file most likely located in the Documents folder of the application sand-
box. If the device is jailbroken, then it is trivial to copy this SQLite file to a desktop and read all the contents. Encrypting the data records of this file will ensure that an attack like this will be significantly harder.
Intended Audience
This article is intended for developers who have a good knowledge of Objective C, and have worked on projects using Core Data.
Overview
The solution presented here takes advantage of the special hardware features of iOS devices to encrypt and decrypt data on the fly when reading and writing to Core
SampleApplication
Encryption
ProductViewController
NSData
Product
Encryption
EncryptedNumberTransformer AppDelegate -saveContext -applicationDocumentsDirectory
SSKeychain SSKeychainQuery
Key
EncryptedStringTransformer
KeyGenerator +key KeychainWrapper
SSKeychain +passwordForService:account: +setPassword:forService:account:
+deviceId +saveDeviceId: +referenceDate +saveReferenceDate:
Figure 1. Class Model
32
OPEN 03/2013
Securing Your Core Data
Data without any perceivable lag for the user interface. Special effort is placed on handling the key for the encryption to make it less vulnerable to attack.
Sample Project Overview
class used on the right hand side is EncryptedStringTransformer. The other two attributes are also set to type transformable, but the name for the transformer is EncryptedNumberTransformer.
The code provided for this example can be found on GitHub at: https://github.com/ronanociosoig/EncryptedCoreData. Building and running the project in the simulator will show the screen in Figure 2. The app consists of a single table view with cells having two values: a name and number. The data loaded is a hypothetical list of products and has three properties: Product name, cost and price. The value shown is the right column is the margin in per cent. Looking at the project files under SampleApplication folder (Figure 3) we see the AppDelegate and ProductViewController. The AppDelegate class manages the loading of Core Data and initialization. Data is loaded from a plist when the app launches for the first time, iterating over an array inserting managed objects. The ProductViewController uses an instance of NSFetchedResultsController to manage the loading of data into the table. Although underlying the CoreData layer is an SQLite file were all the records are encrypted, searching using a predicate etc. all works just as normally does.
Encrypting Values in Core Data
The Mapping Model
- (NSData *)encryptWithKey:(NSString *)key
Next if we take a look under CoreData, and select the mapping model we see that it has one entity defined: Product. Now select the name attribute. This is where we can see something different (see Figure 4). The type for the name attribute is defined as Transformable instead of the usual string type. Note also the name of the
Figure 2. Screen Shot Of Running App
en.sdjournal.org
As we have seen in the entity there are three values, a string and two number (float) formats. Each data type has equivalent transformer. Looking at the code files under Encryption (Figure 5) we see that these transformers are a subclass of Objective-C class NSValueTransformer. Core Data calls this code whenever the attribute is accessed. The transformer subclasses use a category on NSData which add the methods: encryptWithKey and decryptWithKey. This is used as follows: - (id)transformedValue:(id)value { if (value == nil) return nil;
NSData *clearData = [value dataUsingEncoding:NSUTF8S tringEncoding];
}
return [clearData encryptWithKey:@â&#x20AC;?someKeyâ&#x20AC;?];
This in turn calls the transpose method in this category.
{ }
return [self transpose:key forOperation:kCCEncrypt];
Encryption Support in iOS
iOS comes with the Security framework which provides low level access for encrypting and decrypting data, and for reading and writing to and from the keychain. The CommonCrypto architecture provides an API for developers to encrypt data using AES, 3DES and RC4.
Figure3. Screen Shot Project Code Overview
33
Figure 4. Screen Shot Data Model
In addition, all new iOS devices (since iPhone 4) support hardware accelerated encryption for AES and SHA1 hashing. CCCrypt() is the bi-directional AES cypher function where the first parameter defines the the operation â&#x20AC;&#x201C; kCCEncrypt or kCCDecrypt, and it is used in the transpose:forOperation method of the NSData+Encryption class.
The Key
So far so good, but the line of code above shows a hardcoded key. For any encryption method to be secure and protect your data, it is essential that the key should also be secure. Thus it is considered best practice to avoid storing a key where an attacker can get at it, and safer to generate it. To do this, we need something as a starting point for the process. We will use a few bits of data (seeds) and run a series of non-obvious, reusable operations on them to generate a key. Examples of operations include character substitution, re-ordering sequences, and arithmetic operations. Using MD5 hashing is too obvious here and should not be used by it self, but can be used when combined with other operations. In this sam-
ple project three seeds are used: A hardcoded string constant, a timestamp, and a unique identifier string.
The UDID / UUID Debacle
Historically, many applications used the device UDID as a convenient way to uniquely identify each user. Unfortunately, this was also used by some companies as a form of user tracking across applications causing significant concern for privacy violations. Thus Apple deprecated using the UDID in iOS 6, and it is not possible to submit any new applications that access it (existing app can continue for the moment). An alternative to this is to generate a unique identifier type string using the CFUUIDCreate() function. As this function returns a new value each time it is called, calling it once and storing this in the keychain is best practice.
The Keychain
iOS provides a convenient way for storing passwords and other important data in applications in a similar way to OS X â&#x20AC;&#x201C; the Keychain. This data is zoned in such a way that an application cannot access the encrypted data for another application. Note that when a value is stored in the Keychain, if the application that created the value is deleted, the value persists, and only a device reset or OS upgrade will
Figure 5. Screen Shot Encryption Core Data Classes
Seed Seed
Complex nonobvious operation
Generate Key
Seed Figure 6. Key Generation
34
Figure 7. Keychain model layers
OPEN 03/2013
Securing Your Core Data
erase it. The backup and restore process will also restore this data after an OS upgrade. Although this keychain is encrypted, the key for this is stored on the device and is relatively simple to an experienced security researcher to obtain it (taking as little as few minutes). Thus by never storing the key and always generating it on demand, the work required to break the security of the application is significantly increased. The Keychain has a low level C programming interface and is rather cumbersome to deal with, so much so that Apple provides a C wrapper class in the GenericKeychain project in the sample code. There are a number of improvements out there (on GitHub) that use this as a starting point and extend it. (See CocoaControls.com) Here we are using SSKeyChain for the simple reason that it supports ARC. The code used for accessing values stored in the keychain has a number wrapper layers as can be seen in Figure 7.
KeychainWrapper Class
Although the SSKeychain greatly simplifies access to data stored in the keychain, it assumes that it is of a certain format: That of a password, services name and account. The only requirement is to store two values: A date and the unique ID. The wrapper class cleans up the interface to this data.
KeyGenerator Class
This class takes care of all the steps to generate the key. The end result is a key that will always be unique as long as the seeds are the same. Using the generator class the code that was shown above now becomes: return [clearData encryptWithKey:[KeyGenerator key]];
Used in this way the key will be generated each time this method is called.
Testing and Verification
The sample application loads a plist of 14 products and stores them in a Product entity class in Core Data. The loading is performed the first time the application is run. If you need to re-run this process, delete the app, reset the simulator and install and run it again. To verify that the data is encrypted in the SQLite table, run the application in the simulator, and cd to the documents folder (~/Library/Application Support/iPhone Simulator/6.1/Applications/<app identifier>/ Documents/). Open the SQLite file and list the contents
of the table:
> sqlite3 EncryptedCoreDataSample.sqlite > select * from ZPRODUCTS; > .quit to close.
en.sdjournal.org
Performance and Optimization
In the sample code provided a key is generated each time a query is sent to Core Data. Although this works just fine in the simulator, this could significantly drain the battery on a mobile device. At the risk of introducing a security hole, this could be optimized by creating a key cache. The problem with in-memory caching is that an attacker could force a memory dump on the device and obtain the key. On the plus side, the key is generated only once for each time the application starts up and reduces the energy requirements. This presents a tradeoff of the complexity of key generation to the risk associated with creating the cache: the greater the complexity of the key generation – the less likely you will want to generate it each time.
Adding Encryption to Your Project • Add the Security framework to the target. • Add NSData+Encryption into the project. Add EncryptedNumberTransformer and EncryptedStringTransformer if needed. • In the Core Data model change the data types for the instance variables in each entity to “Transformable”. • Set the transformer class name to the appropriate data type. • Add SSKeychain (or some other wrapper code) and adjust the wrapper class as needed. • Always modify the key generator code for each project and use different sequence of steps.
Conclusion
The code for encryption can be used as is, but you may need to add other transformers to support other data types. The code presented for key generation is trivial, and more should be done. This article has addressed a number of potential weaknesses in storing keys and made this much harder for an attacker to gain access to your data. Ultimately the weakness of any code is that it can be decompiled, and so no matter what level of complexity of the manipulations, it can always be broken. Thanks to APress publishing and the authors of Pro Core Data for iOS, Robert Warner andMichael Privat for granting permission to use code referenced in this article.
Ronan O Ciosoig Ronan O Ciosoig is an engineer working in technology for the past 15 years in sectors ranging from digital IC design, embedded systems and mobile software development. For the last 4 years he has been working with Mobile Genius LLC as head of mobile development specializing in iOS applications for enterprise customers. Contact Ronan at ronan@mobilegeniusllc.com.
35