Islam On Demand is now on App Store

Islam On Demand has now a series of great applications on the App Store. All the applications of this series are clones of one application but with different contents. The application plays audio/video lectures. It allows also playing the lecture chapter by chapter. It allows the user to share the application using email or the Facebook.

Here I mention some of the problems we faced during the development of this application.

Technical problems:

1-  UIWindow background image:

The client required to have a background image fixed, and all the screens would be with transparent backgrounds and slide over this background image. In order to do that, we have to set the background of the application's UIWindow, using the following:

UIImage *backgroundImage= [UIImage imageNamed:@"Background-Image-R.png"];
UIColor *background = [[UIColor alloc] initWithPatternImage:backgroundImage];
window.backgroundColor = background;


2- UITableViewCell with buttons:

In some screens that have tables, we wanted to have the cells behave as buttons. I've searched the Internet for a solution for that, but failed. We thought about the following solution:
- Create a subclass of UIButton that has an identifier property; let's call it ButtonWithId.

@interface ButtonWithId : UIButton {
    NSInteger buttonId;
@property  NSInteger buttonId;

- Create a subclass of UITableViewCell that contains two ButtonWithId properties; let's call it CellWithTwoButtons.

@interface CellWithTwoButtons : UITableViewCell {
    IBOutlet ButtonWithId *button1;
    IBOutlet ButtonWithId *button2;
@property (nonatomic, retain) ButtonWithId *button1;
@property (nonatomic, retain) ButtonWithId *button2;

- Create a new Xib file that contains a CellWithTwoButtons object, and under that cell add two ButtonWithId. Each of these buttons would point to a separate action. We will use this Xib file as a custom table cell.
- In the cellForRowAtIndexPath method, set the identifier of the cell buttons to the row number.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"customCellId";
    CellWithTwoButtons *cell = (CellWithTwoButtons*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        [[NSBundle mainBundle] loadNibNamed:@"CellWithTwoButtons" owner:self options:nil];
        cell = tableCell;
        tableCell = nil;    }
    // Configure the cell.
    cell.button1.buttonId = indexPath.row;
    [cell.button1 setTitle:[NSString stringWithFormat:@"%d",indexPath.row] forState:UIControlStateNormal];

    cell.button2.buttonId = indexPath.row;
    [cell.button2 setTitle:[NSString stringWithFormat:@"Row #%d",indexPath.row] forState:UIControlStateNormal];
    return cell;

- Now in the button's action, you can check for the identifier property of the action's sender. So you can recognize which row in the table is pressed, and because each button points to a different action, you can recognize which button in the cell is pressed.

- (IBAction) button1Pressed:(id) sender{
    NSLog(@"Button 1 of row %d ",((ButtonWithId*)sender).buttonId);

After I had finished implementing this solution, I've found this one (I think it's much better):

The reason for still leaving my solution in this blog, is that may be someone find it helpful for solving other problems.


3- Handling xls files:

Our client had a large tables in xls files. These tables contains the data that the iPhone application will uses. He needed to use these xls files as it's in the iPhone project. I've made a search in the Internet for handling xls files in iPhone SDK, but haven't found an easy solution. I've suggested  that the client converts the xls file to csv, which can be easily handled.

- (void) testCSVHandling{
    NSString *path = [[NSBundle mainBundle] bundlePath];   
    NSString *csvContentsFilePath = [path stringByAppendingPathComponent:@"contents.csv"];
    //The contents.csv file is converted from an xls file using OpenOffice, where '|' is the field delimiter, and '^' is the text delimiter.
    NSMutableDictionary *contentsDic = [self dictionaryFromCSVString:[NSString stringWithContentsOfFile:csvContentsFilePath encoding:NSUTF8StringEncoding error:NULL]];

 converts a two columns CSV string to a dictionary, where the 1st column will be the keys, and the 2nd column will be the values.
- (NSMutableDictionary*) dictionaryFromCSVString:(NSString*) csvString{
    NSArray *cellsArray = [self arrayFromCSVString:csvString];
    NSMutableDictionary *dic = [NSMutableDictionary dictionary];
    for (int i=0; i<[cellsArray count]; i++) {
        [dic setObject:[[cellsArray objectAtIndex:i] objectAtIndex:1] forKey:(NSString*)[[cellsArray objectAtIndex:i] objectAtIndex:0]];
    return dic;

 reads the cells of the CSV string, and converts them to a two dimensional array.
- (NSArray*) arrayFromCSVString:(NSString*) csvString{
    NSString *cleanedCSVString = [csvString stringByReplacingOccurrencesOfString:@"^" withString:@""]; //The ^  character was used as the Text delimiter
    NSMutableArray *rows = [[cleanedCSVString componentsSeparatedByString:@"\n"] mutableCopy];

    [rows removeLastObject]; //Openoffice adds an empty line at the end of the file, so I remove it here.
    NSMutableArray *returnedArray = [NSMutableArray array];
    for (NSString *row in rows) {
        [returnedArray addObject:[row componentsSeparatedByString:@"|"]];    //The | character was used as the Field delimiter
    [rows release];
    NSLog(@"cells array:%@",returnedArray);
    return returnedArray;

Nontechnical problems:

Our client was also a graphic designer, so he can recognize that, for example, two buttons are  misaligned with just one pixel!! I was trying to align things appropriately as much as possible with my naked eye, but he kept finding mistakes in my alignments. For that reason I decided to use a ruler. One colleague recommended an application “Free Ruler” that works on Mac OS X. It displays a nice semi transparent ruler. 




Leave a Comment...