Channels ▼
RSS

Embedded Systems

Java Meets Objective-C


iPhone: Database Access

Complex applications contain storage of some kind, generally a database. Apple recommends accessing the database via the Cocoa API framework called "Core Data." The Core Data framework directly interfaces with the SQLite database, (which, in our example, is running on your mobile device). Core Data hides the complexity of dealing with SQL. Instead, it provides the very handy NSManagedObject interface, which allows you to directly manipulate an entity object’s instance fields. These fields will automatically be stored in the database. Another convenience of the Core Data Framework is that database table creation (as well as adding relations and constraints to the tables) can all be done within the Core Data User Interface provided by XCode.

[Click image to view at full size]
Figure 3: Core Data stack.

Let’s go back to our social networking app and show how to fetch a friend’s profile from the database. We will use SQLite and the Core Data API, but first we have to slightly modify our FriendProfile class, as in Listing Six:

Listing Six
//FriendProfile.h interface file// MFriendProfile.h
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>

@interface MFriendProfile : NSManagedObject {

}
@property (nonatomic, retain) NSString * name;
@property (nonatomic, retain) NSString * country;
@property (nonatomic, retain) NSString * city;
@property (nonatomic, retain) NSString * phoneNbr;

@end

// MFriendProfile.m
#import "MFriendProfile.h"

@implementation MFriendProfile
@dynamic name;
@dynamic country;
@dynamic city;
@dynamic phoneNbr;

@end

The difference between the FriendProfile class definition here and the one in Listing One is that here, I’ve included the Core Data framework’s header file. Also, our class now extends from NSManagedObject, which gives it all the basic behavior required of a Core Data object. Accessors, used in Core Data’s NSManagedObject class, are created dynamically at runtime. If you want to declare and use properties of the FriendProfile class, but want to avoid warnings about methods missing at compile time, you can use the @dynamic directive, which is shown in the implementation class, instead of @synthesize.

Using the NSManagedObject API is a bit complex, but it becomes intuitive once you understand it. Listing Seven is an example method that fetches a friend’s profile from a database table, called FRIENDPROFILE. The table contains four columns: NAME, COUNTRY, CITY, and PHONE­NBR.

Listing Seven
// DatabaseController.m
#import "DatabaseController.h"
#import <sqlite3.h>
#define kDatabaseName @"SocialNetworking.sqlite"

...

- (NSManagedObject *)getFriendProfileObjectbyName:(NSString *)name {

   managedObjectContext = [self managedObjectContext];	

   //create sort descriptors to specify preferred sort order
   NSSortDescriptor *sortDescriptor = 
      [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES]; 
   NSArray *sortDescriptors = 
      [[NSArray alloc]  initWithObjects:sortDescriptor,nil];

   //specify where clause 
   NSPredicate *predicate = 
      [NSPredicate predicateWithFormat:@"name == %d", name];	

	//fetch our friendís profile from database table 
	NSEntityDescription *entity =
	   [NSEntityDescription entityForName:@"MFRIENDPROFILE" 
	    inManagedObjectContext:managedObjectContext];	

	NSFetchRequest *request = [[NSFetchRequest alloc] init];
	[request setEntity:entity];

	// Set the predicate for the current view
	if (predicate) 
	{
        [request setPredicate:predicate];
    }

	if (sortDescriptors) 
	{
		[request setSortDescriptors:sortDescriptors];
	}

   NSError *error = nil;
   NSMutableArray *results = [[managedObjectContext 
      executeFetchRequest:request error:&error] mutableCopy];   

   if (error)
   {
      NSLog(@"error in getFriendProfileObjectbyName:%@", 
      [error userInfo]);
   }

   [sortDescriptor release]; 
   [sortDescriptors release]; 
   [predicate release];

   if ([results count] > 0) { 
      return [results objectAtIndex:0];
   }
   return nil;
}

Our getFriendProfileObjectbyName method receives the friend’s name as an argument. By using the Core Data API, we specify which table is queried as well as the predicates and sorting requirements. As a result, this SQL statement executes behind the scenes:

SQL>select * from FriendProfile where name = "Albert";

Core Data API contains a lot of boilerplate code to get access to NSManagedObjectContext, NSPersistentStoreCoordinator, and NSManaged­ObjectModel objects (unfortunately, such code exists in this framework). You can easily copy this code from the reference here. Once you fetch the FriendProfile, you can retrieve its properties in this manner:

NSString* name = 		FriendProfile.name;
NSString* country =	FriendProfile.country;
NSString* city = 		FriendProfile.city;
NSString* phoneNbr = 	FriendProfile.phoneNbr;

Overall, Core Data is a useful feature. It allows you to graphically define entities (tables) and relations; and generates corresponding Managed Objects dynamically. Also, there is no need to deal with complex SQL statements. On the negative side, there is a significant amount of "boilerplate" code, which you have to carefully place and test.

Java: Database Access

There are multiple Java persistence frameworks. In my opinion, Hibernate is the Java framework that most closely resembles the Core Data API. Hibernate follows an Object-Relational Mapping (ORM) paradigm. That is, it allows you to persist object data into a relational database by simply setting fields on the object, which is directly mapped to a particular database table. The mapping can be done using either XML files or metadata annotations introduced in Java 5. Listing Eight shows an example of the former.

Listing Eight
<hibernate-mapping>
  <class name="com.vo.FriendProfile" table=" FRIENPROFILE ">
  <property name="name">
     <column name="NAME" />
  </property>

  <property name="country">
    <column name="COUNTRY"/>
  </property>

<property name="city">
    <column name="CITY"/>
  </property>
  <property name="phoneNbr">
    <column name="PHONENBR"/>
  </property>
 </class>
</hibernate-mapping>

In this example, the FriendProfile object from Listing Two is mapped to a database table with the same name, which is a conventional way of dealing with data mapping. Four object fields are directly mapped to four table columns with the same names. This mapping allows Hibernate to generate proper SQL behind the covers.

Another configuration file, called hibernate.cfg.xml, contains database connection configuration details, such as database URL, drivers, login, and password; see Listing Nine.

Listing Nine
public FriendProfile lookupContact(FriendProfile profile){
   String lookupName = profile.getName();		

   //perform database lookup in FRIENDPORFILE table		

   Session session = null;
   Transaction tx = null;
   FriendProfile returnProfile = null;
   List contacts = null;

   try{
      // Read Hibernate configuration file
      SessionFactory sessionFactory = 
	     new Configuration().configure().buildSessionFactory();

      // A specific session object is obtained
      session = sessionFactory.openSession();	

      // A new database transaction is started
      tx = session.beginTransaction();

      // FriendProfile object is fetched from the store
      contacts = session.createCriteria(FriendProfile.class)
                 .add(Restrictions.eq("name", lookupName)).list();

      tx.commit();
   }
   catch(Exception e){
      e.printStackTrace();
   }
   finally{
      try{
         session.flush();
         session.close();
      }catch(Exception hex){}
   }

   returnProfile = 
      contacts==null) ? null : (FriendProfile)contacts.get(0);
   return returnProfile;		
} 

In Listing Nine, we have imported all the necessary Hibernate libraries. Then we created a Hibernate Session and started the transaction. Next, we programmatically retrieved the FriendProfile object by simply issuing a get method on the Session object, and passing the expected object type and query filter — your friend’s name. The same query, which we saw in the Core Data example, will run here as well, and return back a FriendProfile object with all profile fields filled in.

Conclusion

Despite differences in language syntax and underlying runtime platforms, iPhone development with Objective-C and Web Application Development using Java share common traits:

  • Both languages are object-oriented
  • Both languages utilize the same Design Patterns, e.g., MVC
  • Both languages use similar Database Access techniques , e.g., ORM

However, there are things that Java developers have to watch for in Objective-C:

  • Object creation: Java objects are created at runtime using the new keyword. There is no explicit memory allocation that a Java programmer has to worry about. In Objective-C, an object can be created using one of three keywords: alloc, new, or copy. Each one of these, similar to the retain method, increments the retain count of the object. Retain count shows how many pointers to the object exist, and whether it can be reclaimed by the Memory Manager.
  • Object destruction: Java memory management is greatly simplified with garbage collecting. Java objects that reference other objects are organized as an object graph sitting in JVM’s heap memory. The moment an object becomes unreachable (not referenced by other objects in a graph), it becomes a candidate for garbage collection, usually after its reference is set to null, or it falls out of its method scope. Objective-C has a memory manager, not a garbage collector. If you allocate an object using one of the four aforementioned techniques, you must release the object by calling the release method on this object. Calling the release method decreases retain count. When the count reaches zero, the object is sent a dealloc method; at which point, the object can release any additional memory and call dealloc on its super class. Failure to release or auto release an object causes memory leaks and unpredictable behavior in the future.
  • Over-release and premature deallocation: Java programmers are immune to these errors thanks to garbage collection. Objective-C programmers have to remember not to release more than they retain. Over-releasing method calls on already deallocated objects can cause the application to crash.

What is clear from these examples is that Objective-C and Java have many syntactic and semantic elements in common. Moreover, the way in which problems are solved tend to use similar components. If you approach Objective-C with this perspective and bear in mind the differences highlighted in this article (and in the "Additional Differences" section), you’re likely to find the transition fairly smooth.

Additional Differences

iPhone vs. Java comparison:

  1. Objective-C uses the nil keyword to specify that an object reference does not point to any object. This is equivalent to Java’s null. However, the subtle difference is that Objective-C allows you to call methods on nil objects, simply returning nil. Java will throw a NullPointerException that can halt program execution.
  2. Objective-C uses the self keyword to refer to fields and method within the object [self fetchLatestData:dataLocation]; whereas Java would use the this keyword for the same thing.
  3. Objective-C uses distinct data type called id to declare a general type of object. This comes handy when you do not know at compile time what type of object comes back from a method, so we can receive id, and cast it to necessary type:

          - (void) categoryButtonPressed:(id)sender
          {
    		NSUInteger whichButton = ((UIButton*)sender).tag;
          }
    	Java utilizes the Object type for the same thing.
    


  4. The Objective-C method that receives multiple arguments is broken into multiple parts:

    - (NSString*) getListOfFriends: (NSString*) name 
    forCity:(NSString*) city
    withPhoto: (UIImage*) photo
    


    The actual method name is getListOfFriends:forCity:withPhoto: and each argument is specified after the colon. Java simplifies the method signature syntax:

    	
    	public String getListOfFriends (name, city, photo);
    

In Java, a method name must be a single word, followed by a list of arguments separated by commas.

Useful Resources

A Tour of Xcode: http://is.gd/Eo5qMC

Objective-C Programming Language: http://is.gd/SVfpK5

NSManagedObject Class Reference: http://is.gd/akGLFol

Wikipedia Core Data entry: http://en.wikipedia.org/wiki/Core_Data

Memory Management Programming Guide: http://is.gd/3AUZai


— Genadiy Shteyman has a B.S. in Computer Science and M.S. in Management of Information Systems. He is a vice president in the private bank division at a major financial institution.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video