lunes 9 de mayo de 2011

My preferred bookmarklets for the iPhone/iPad's Safari

As you probably know you can extend the functionality of Safari in the iPhone and iPad using Bookmarklets, and there are bookmarklets for everything. Here is a list of my preferred ones, starting with adding Find functionality to the Safari.

Note : To create the bookmarklet save (for instance) this page as a bookmark, then edit the name and change the link with the JavaScript code (from the iPhone/iPad you can "Select all" inside the code box)

Find : Search text in the current web page

Readability : Specially useful in the iPhone, converts the page in a format that can be easily read

Save to delicious : Save the current page in delicious.com

Read it late : For the Read It Late app

Subscribe in Google Reader : if you use Google Reader you can add a new feed of the current page using this bookmarklet... quite cool.

Post with Twitter : post the current page using the Twitter app

View Source : to view the source code of the web page

sábado 19 de marzo de 2011

include LocalNotifications and support iOS 3.x

First you need a function to detect if the current iOS support local notifications:

static int hasLocalNotifications = 0; //0-undefined 1-YES 2-NO

+(BOOL)hasLocalNotifications{
if (hasLocalNotifications==0) {
Class myClass = objc_getClass("UILocalNotification");
if(myClass==0){
hasLocalNotifications=2; //NO support for UILocalNotification
return FALSE;
}else {
hasLocalNotifications=1; //There is support for UILocalNotification
return TRUE;
}

}

if(hasLocalNotifications==1)
return YES;
else
return NO;
}



Managing notifications
I think that UILocalNotiications are essentially easy to manage. The problem is when you have to remove or change one existing notification.

You can access the list of your application notifications through the function NSArray* localNotificationsList=[application scheduledLocalNotifications];. Initially I identified my notifications comparing fireDate and the body. But there is an easiest way using userInfo. You can store an ID linked with your information in the database in this property.
You still have to go over all the notifications, but I think this way you can find your unique notification even having two with the same date and body.


//search the local notification using the ID
for(id localNotification in localNotificationsList){
NSNumber *id = [ [localNotification userInfo] objectForKey:@"ID"];
if ([id longLongValue]==self.ID ) {
[application cancelLocalNotification:localNotification];
return;
}
}


A final clarification, I use as ID a long long int, because it is the key in the database of the associated element.

sábado 25 de diciembre de 2010

Structure of an iPhone application

The separation among the View and the Model.

In general when you read examples of source code of iPhone applications the logic of the application and the database access is usually included directly in the delegate of the view (which basically is a View element) so there is no clear separation among the View and the Model (considering the MVC paradigm).

I present here my approximation to have a real separation between the view, the data structures used by the view, and the model (including the application logic and the data management of the database); and how to communicate these two worlds.

The visual elements

Apple imposes a structure on the view governed by the UIViewControllers (see "View Controller Programming Guide for iOS")

UIViews are the graphical entities that are used by the system to display the elements on the screens.

UIViews provide the general behaviour of the View that can be customized using the callback functions of the delegate.

On the other side, UIVIewControllers provide a data structure that is well known by the system. You can combine different UIViewControllers in the way defined by the previous guide to create a coherent behavior of the application. For instance, a TabBar with different Navigation Bars each one with UiTableViews and with different buttons in the navigation bar, all these combinations of visual elements are well defined and governed by the UIViewControllers, so you as programmer only have to focus on the missing pieces of your application and not on how to control the behaviour of each UIView.

Each UIViewController has each own way to discover the visual elements (for instance, the buttons in the navigation bar for a specific view), for this reason it is so important to read the guidelines provided by apple.

The application logic

The application logic is the set of functions that make operations over the application's data: uses the database and transforms the data.

This part, the application logic, is where you should use unit testing, as one of the ways to guarantee the quality of your application.

For unit testing I'd recommend WiteBox. It provides the traditional interface with the green and red bar to see if all you tests has been executed without problems.

How to communicate the View with the Model?

My recommendation is to create few well known singleton classes that act as interface with the model... So, all communication about the application data is done through these interfaces.




For instance, a Model class to access the settings. Or a "ContactManager" for an application that manages contacts... Here it depends a lot on your Application, but the main data elements should have one of these interface classes.

One important detail is that these main classes are general abstractions of concepts in your application (tasks, projects, context, notes, accounts, contacts, people, what ever) but could be different than the tables and the schema used in your database.
At this level you use the data abstractions that best fits the application's interface and the user at the end.

In summary, all changes in the model are communicated though these classes (ContactManager in the figure) that operate over the data, changing it, storing, deleting, etc.

The data between the model and the view

Views use data structures to represent the information: a table requires a data structure with sections and rows for each section. One instance of this class used by the table, is created and managed by the Model. So, for one side the table retrieves the data instance through the model, and the model updates the information in this instance each time it receives changes from the View.

Imaging a contacts application where you can group your contacts on different groups. An you have a table that shows the list of contacts in one specific group. If you change the name of one of your contacts in that view. You should inform the Model that this contact has changed.

Once the Model has received this information it will update the database with the new contact update, for instance you can remove the link of this contact with a group, or change the name or add the contact to a new group. All these operations are done by the model.

How to communicate the changes in the Model to the Views

One basic rule is that the model doesn't know anything about the Views. So, how to communicate the changes to the Views?. My approach is to use notifications (NSNotification).

Each view knows which are the changes in the model they have to subscribe. If you are presenting the contacts, you subscribe to any change in the contacts.

The model will update also the data structures used by the view to show the information. So when a View receives the notification it manages the right information inside the data structures of the view.



Types of Notifications

Usually you only need one notification, for instance to inform that a contact has changed. But in some cases, like deletions, you need to send two notifications:
CONTACT_WILL_DESAPPEAR and CONTACT_DID_DESAPPEAR
one notification to inform that something is going to change and another one to inform that has already changed.
This allow the view to have information about the object that is going to be removed or changed and then act on the view accordingly, for instance storing the position of the row in a UITableView that is going to be removed.
One note, as part of the notification you can include the data that is going to or has changed.

Conclusions

This is the approach I use in my applications, the key concept is the use of notifications to communicate changes in the Model, this way there is a clear separation between the Model and the Views. In fact, the model doesn't know anything about the views, and only the views affected by the changes (and in memory at that time) are informed, so the view can update the content in the screen.

martes 7 de diciembre de 2010

Migrate SQLite database schema

... in my view, one of the most boring tasks part of the development of an application. I have had to do it recently and I want to share with you the way I did it.
One of the main problems changing the database schema is the small support SQLite has (it only allows to add new columns, and change the table name, no remove columns, no change the name of existing columns), so here is my approach:

First, you have to keep track of the database version. Just a table with the entry "1.0".

Second thing to remember is that the client could jump versions. So your code should be ready to migrate since the first version to the last version.

if( dbVersion isEqualToString:@"1.0") {
[self migrateDBv1_tov2];
dbVersion=@"2.0";
}
if( dbVersion isEqualToString:@"2.0"){
...
}
... etc etc


Third, here is a copy of the SQL I used to include a new column , and create one new table (ActiveTask) from another original table (Task).

ALTER TABLE Settings ADD context default 0;
This adds a new column to the table with default value 0.

CREATE TABLE ActiveTask (ActiveTaskID INTEGER PRIMARY KEY, description, duration, completed, running, init_run_time, order, context);
INSERT INTO ActiveTask SELECT TaskID, description, duration, completed, running, init_run_time, order, 0 as context from Task where completed=0;

It is possible to create and do the select at the same time but then you cannot specify the name of the table's primary key (which was essential in my case), so I followed this two step approach, first creating the table and later inserting by selecting the content of another table.

In the select statement you can create new columns with a constant value using: " 0 as context " <value as column_name>

Take care of the column order, sometimes this is important. In this case the select statement should have the same column order that the creation statement. But the order could also be important in your code.

And to remove the old "Task" table:
DROP TABLE Task;

And finally, don't forget to covert a fresh new install, without any database to migrate :)

sábado 2 de octubre de 2010

Write code in the iPhone

It could look like strange to code in the iPhone, but the reality is that I really need it.

The key problem is the support of the “Tab” key. Initially I use spaces but it's not the best option. In fact, I haven't fount a good solution right now.

Pocket Monkey looks attractive but it seems like you need a FTP server to transfer files.

Today I have tested PlainText (free and aesthetic app). PlainText allows to insert "Tabs" writing 4 spaces (after enabling TextExpander in the configuration, but in fact there is no need to buy TextExpander.. I don’t have it). It synchronizes with Dropbox in both directions.

An automatic completion of the tabs at the beginning of the line would be great, but PlainText is a good enough solution until I write my own application ;)

jueves 17 de junio de 2010

Storing an ordered list in a database

if you store a ordered list in a database you have to store the order together with each entry, so the simple approach is simply record the position:

<text> | <order>
data1, 1
data2, 2
data3, 3


The problem is that in the worse case when you move the last entry to the first position, you have to change all the entries in the table


date1, 2
date2, 3
date3, 1


It is evident that as the number of entries grows this operation is very expensive. I have used a technique that in most of the case only require to change the entry you are moving, and from time to time reorder completely all entries in the table (to reset the index).

In this method you define a GAP, an initial distance among entries (for instance 10), and when you move an element you set the index in the middle of the two adjacent elements. This way you only update one row in the database with the new index.

In the next example, date3 has been move to the first position but date1 and 2 keep the original index:
date1, 10
date2, 20
date3, 5


I use a "double" with this technique, the problem is that we reach a limit dividing by 2 where we get the same value. To solve this problem I define a minimum value (0.001 for instance), when the difference between consecutive indexes in less than this number we reset all entries with the GAP multiples.


/* reorder the task inside the array (the task is already in the position) */
-(void)reorderInArray:(NSArray)tasks atIndex:(NSUInteger)index{
NSUInteger count=[tasks count];

//is the only element
if (count==1) {
self.orden.double_ = GAP;
return;
}

//is the last element
if(index==count-1){
//get the previous element
Task task = (Task)[tasks objectAtIndex:index-1];
self.orden.double_ = task.orden.double_ + GAP;
return;
}

//is the first element
if(index==0){
//get the next element
Task task = (Task)[tasks objectAtIndex:1];
self.orden.double_ = task.orden.double_ / 2;

if(self.orden.double_<0.001) //reset all indexes
recalculateTasksOrders(tasks);
return;
}

//is an intermediate element
Task task1 = (Task)[tasks objectAtIndex:index-1];
Task task2 = (Task*)[tasks objectAtIndex:index+1];
self.orden.double_ = (task1.orden.double_ + task2.orden.double)/2;

if(self.orden.double-task1.orden.double_<0.001) //reset all indexes
recalculateTasksOrders(tasks);

}


The problem of this technique is the complete reorder from time to time, so probably is not good for a huge amount of elements. Any other idea is welcomed.

domingo 28 de marzo de 2010

Memory management in Objective-C

This is without doubt one of the more complex topics in objective-c.

One basic tutorial can be found here: "Learn Objective-C"

And a more formal documentation from Apple can be found here: "Memory Management Programming Guide for Cocoa".

The fundamental rule as described in the guide is: "You take ownership of an object if you create it using a method whose name begins with “alloc” or “new” or contains “copy” (for example, alloc, newObject, or mutableCopy), or if you send it a retain message. You are responsible for relinquishing ownership of objects you own using release or autorelease. Any other time you receive an object, you must not release it."

stringWithFormat is a class method that returns an NSString* , this function returns an string with the specified format, but this string is autoreleased by the method, so you don't have to release it again (if you are using this string only inside the scope of your method), or retain it for future use.

The "autorelease" says that will eventually release the object in some moment in the future (but when?). In the iPhone this is done inside the UIKit when you finish your code and enter in the iPhone internal management control loop. When you autorelease a object is still valid in the scope of your function until you return the control to the UIKit (usually at the end of a delegate function).

But the problem is to know when the object returned by a method has been already autoreleased or not.

One, I would say, essential tool when you have memory problems (get a “EXC_BAD_ACCESS” signal and you don't know why) is to activate NSZombies in Instruments, read the following article "iPhone Memory Debugging with NSZombie and Instruments" (from MARKJNET) that describes this with detail.

Besides this, you can also see the retain counter of an object inside the console with this command:

p (int) [object retainCount]