Archive

Archive for the ‘iPhone SDK’ Category

Retain your IB objects in Cocoa Touch

I previously published 2 articles on the fact that you had to retain your objects instantied from Interface Builder. I finally discovered the scientific explanation within an AdMob source file:

Note that top level objects in nibs other than MainWindow.xib in Cocoa Touch are autoreleased, not retained like in OS X. Be sure to use [self retain] in -awakeFromNib when part of a custom nib (as in this example).

Extract from the AdMob SDK source files for iOS.

Automatically restart an app having started a call?

This post will be quite simple. Its goal is to answer this question : is there a way to automatically restart an app which has initiated a call, once this call ended? This question is pretty related to my own apps (I hope you already know them! if not, just check them in the AppStore! most are free!), since these are phone shortcuts (naturally just a little advertising picture below…).

My iPhone shortcut apps

So I recently checked to determine if I may make my apps a little more better, by allowing the user to have them restarting after the call ended. And the answer is… yes… but… this involves doing something which is not really nice in my case. In fact you can do this through using a WebKit view, and having a phone URL displayed in it. Having the user clicking this URL will bring a confirmation alert, if the user goes on the call takes place, and once it finished the app is restarted (you can Google this to find more details, I will not since I did not use this trick, doesn’t match my user experience goal!).

And that’s all! There is no other way, so if you don’t rely on a click on a link to start a call, do not hope to have your app restarting. iOS is not doing this… anymore (I remember it did in its first versions… it’s a shame it’s not customizable).

Have fun!

Close this Number Keypad I shall not see!

  • Did you ever use an iPhone app with a Number Keypad to edit numbers only fields?
  • Did you ever wonder how you could close the keypad, just like you would do with the standard keyboard and its ‘Done’ button?
  • Are you sure you want to know the answer…?

YOU CAN’T! (at least if the application just used the standard Number Keypad provided within iOS SDK)

So, what choice do you have?

  • Generally, the keypad closure is not really necessary, since the edited field is in its own screen, you just let the user go back (generally through the navigation bar) and the keypad is closed automatically.
  • You may imagine other solutions, too…
  • But the one I’ll give you here offers the following result:
Simulateur iPhone
Uploaded with plasq‘s Skitch!

Now that you’ve seen this, you wan’t to know how to do it, don’t you? So here’s the howto! It’s not my own creation, I followed their tutorial and used the graphic files provided, so you can do so! I just poured a little bit of idea I found on another blog to make it a little more better (to me at least).

So this idea is just to use the powerfulness of Cocoa’s categories (extending classes without subclassing), to add a method to the UIView class enabling me to find the firstResponder from a view and resign it. Calling this method on the app’s main window when I want to close the keypad, it will seek and find the firstResponder, resign it, and thus close the keypad! Easier, isn’t it? And the corresponding is below…

#import 

@interface UIView ( RoCHExtensions )
- (UIView *)findAndResignFirstResponder;
@end

@implementation UIView (RoCHExtensions)
- (UIView *)findAndResignFirstResponder {
    if (self.isFirstResponder) {
        [self resignFirstResponder];
		return self;
    }

    for (UIView *subView in self.subviews) {
        UIView *firstResponder = [subView findAndResignFirstResponder];

        if (firstResponder != nil) {
			[firstResponder resignFirstResponder];
			return firstResponder;
        }
    }

    return nil;
}
@end

Your CoreData app is crashing you don’t know why? Check your properties’ names!

In my case, I was using a property named “description”. Causes the apps to crash without displaying anything to help, so beware of your properties’ names!

Ad’hoc distribution and expired certificate

Once a year, your iPhone Developer Distribution certificate will expire. This will involve the not-so-big-but-nonetheless-boring process to create new private keys, request the certificate, install it in xCode, et caetera.

But once this is done… you’re not finished yet! Remember of this friend of your’s you made a special app for you distributed through Ad’hoc? Its provisionning profile for this app is expired too… Now you’ll have to generate a provisionning profile again, with your brand new Distribution certificate, send it to him, and… huh, no, that’s not finished yet: you have to rebuild your application, since it needs to be signed with your new certificate!

(If you don’t rebuild the app, when trying to install with the new provisionning profile, your friend will get a “invalid signer” alert message.)

Wow! Finished all this? This time you’re done… hopefully.

Changing iPhone app name dynamically? Huh, no…

[Edited] That’s possible impossible. (In the simulator, it is. In the real life, the iPhone must be protecting its app bundle’s files. I think I wasn’t patient enough to read the doc on security. And it’s a logical security measure…)

So you can can’t let the user choose the display name of your application (the one shown in his iPhone’s Springboard).

Not more possible for the icon, alas, I already tested some time ago. I suspect the icon to be merged with the gloss and frame layers at installation time, so it won’t reload afterwards… while the bundle’s name will! But since you can’t change it… But if someone does make this happen (out of jailbreaked iPhones I mean), I’d be happy to know!

See you (with things that work)!

Shortest guide to UIScrollView

Want to implement the UIScrollView fast?

  1. Build your scroll view in IB.
  2. Build the content view you wish to scroll.
  3. Link all these things to some class with IBOutlets.
  4. Ask the class (preferably in awakeFromNib) to add your content view as scroll view’s subview.
  5. Last but not least: set your scroll view’s contentSize, or it won’t scroll!
Categories: Cocoa, iPhone SDK Tags: , , , ,

How to add a search bar to your table view, and integrate it in your section indexes?

Assume you have a table view filled with objects. Assume you have sections for these objects, and you have setup the section indexes. Until this point, nothing which cannot be found in SDK’s documentation.

Assume now you want to add a search bar to your table view. What do you do? To answer this question, we will start from source code available to all of us, implementing the required table view with section indexes, we shall use the TableViewSuite’s 3rd example, I have named “3_SimpleIndexedTableView” (you can download the tutorial package there).

From this base, I will indicate the updates necessary to display a search bar in the first row. I will do this the fast way, so it may not be really nice. And I will not implement everything required to do search and display search results, you will have to look at documentation for this (this will essentially consist in connecting the search bar with required objects and delegates, providing content for search results).

So, what do we do to the TableViewSuite’s 3rd example:

  1. We change the numberOfSectionsInTableView: method in order to return one row more (you guess? …the row for the search bar naturally!):
    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    // The number of sections is the same as the number of titles in the collation.
    return [[collation sectionTitles] count] + 1; // CHANGE: add one for the search cell
    }
  2. We update (a little) the tableView:numberOfRowsInSection: and tableView:titleForHeaderInSection: methods in order to have it return good number of rows for the good sections:
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    if (section == 0) return 1; // CHANGE: return one for the search cell
    // The number of time zones in the section is the count of the array associated with the section in the sections array.
    NSArray *timeZonesInSection = [sectionsArray objectAtIndex:section - 1];
    return [timeZonesInSection count];
    }
    - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
    if (section == 0) return nil;
    return [[collation sectionTitles] objectAtIndex:section - 1];

    }
  3. Finally, we update the most important method, I have named tableView:cellForRowAtIndexPath: :
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    // CHANGE: add the search cell
    if ([indexPath indexAtPosition:0] == 0) {
    static NSString *CellIdentifier = @"SearchCell";
    UITableViewCell *searchBarCell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    [searchBarCell addSubview:[[UISearchBar alloc] initWithFrame:searchBarCell.frame]];
    return searchBarCell;
    }

    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    }
    // Get the time zone from the array associated with the section index in the sections array.
    NSArray *timeZonesInSection = [sectionsArray objectAtIndex:indexPath.section - 1];
    // Configure the cell with the time zone's name.
    TimeZoneWrapper *timeZone = [timeZonesInSection objectAtIndex:indexPath.row];
    cell.textLabel.text = timeZone.localeName;
    return cell;
    }
  4. Like I told before, you should then get the searchBarCell connected to the good objects to have it up and working. One last tip, I use the UISearchDisplayController class and connect them both in this way:
    UISearchDisplayController *sdc = [[UISearchDisplayController alloc] initWithSearchBar:sb contentsController:self];
    [sdc setValue:self forKey:@"searchResultsDataSource"];
    [sdc setValue:self forKey:@"searchResultsDelegate"];

Uh oh, I almost forgot to give you the best tip! How to have the “search” tool icon (what’s this tool’s name in English?) in your section indexes? Just follow the guide… (’cause this cannot be found in the doc, but you may find it elsewhere on the net, like I did – however it’s too long ago, I have not kept the source link).

- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
return [[NSArray arrayWithObject:@"{search}"] arrayByAddingObjectsFromArray:[collation sectionIndexTitles]];
}

If you have a problem, you can’t make it work in your code, do not hesitate to ask… I have tried this code changes and it worked for me, but I may have forget something!

[Edited] As requested, please find the xCode project there.

My Custom object instantiated in my XIB file is released… is that normal?

I wrote a NSObject subclass, which I use as a table controller in a dedicated XIB file. This XIB file instantiates this class, which is correctly used until… it is dismissed due to lack of retains!
I did solve the problem simply by retaining it, but I do not see why I have to… Did any of you face the same problem, or did I do something in my code I do not see?

Signing identity problem?

If you face some problems in Xcode when building Code Signed applications (for iPhone), that were not happening before:

  • You can’t build Code-Signed applications anymore? You’ve now got a “Code Sign error”, but you was perfectly able to build 5 minutes ago, and don’t know what did change?
  • Xcode’s Organizer tells you “A valid signing Identity matching this profile could not be found in your keychain”?

You may have a problem with your Keychain Access. Just give a look to the Keychain Access application to make sure the keychain containing your iPhone Developer Program certificates (for me it’s the Session one) is the default one.

This may not solve your problem, in which case I’m very sorry… but it was my problem, and solved it!

Follow

Get every new post delivered to your Inbox.