RSS Feed!

Recent Posts

Recent Comments

Archive for the ‘Objective C’ Category

Updating the UISearchBar programmatically

Friday, October 16th, 2009

Today I had to update WelliBUS’s search bar programmatically because I needed to use the street picked up via GPS as my street name.

Until this point implementing the search bar seemed easy:

  • adopt a couple of protocols: UISearchDisplayDelegate and UISearchBarDelegate
  • implement a few callback methods (from the delegates listed above)
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString;
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption;
- (void)searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller;
- (void)searchDisplayControllerDidEndSearch:(UISearchDisplayController *)controller;
  • and implement my own filtering function
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope;

The problem I had on my hands was how to programmatically update the text in the UISearchBar and force the UISearchDisplayDelegate to call the appropriate callback methods.

Turns out it was simpler than expected (despite not being able to find a solution by googling). All that was needed was:

[self.searchDisplayController.searchBar becomeFirstResponder];
self.searchDisplayController.searchBar.text = returnString;

Cheers…

Urban Airship – Push Notifications

Sunday, October 4th, 2009

Today I have finally added Push Notifications to Parcel Trackr.

I decided not to waste time and I went for Urban Airship. I registered, uploaded my push certificate, downloaded the sample and integrated the two systems.

Not everything went smoothly though because when I first ran the application I got a

Failed to register with error: Error Domain=NSCocoaErrorDomain Code=3000 UserInfo=0×120610 “no valid ‘aps-environment’ entitlement string found for application”

I thought my provisioning profile did not include the right entitlement… so I re-downloaded it and tried again. Turns out I was using the wrong provisioning profile.

So if you want to avoid my mistake just make sure that after you’ve configured push services in the iPhone Dev Center you download the updated provisioning profile and then you install it via XCode.

Other things worth checking include: the product name in your build configuration matches the app id and of course, the ultimate solution, clean all targets before building!

Cheers…

iPhone how to: center and horizontal align the contents of a UITextField

Friday, August 7th, 2009

It’s as simple as:

1
2
theTextField.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
theTextField.textAlignment = UITextAlignmentCenter;

Basically this will ensure that no matter how tall your text field is the actual text will be centered both vertically and horizontally.

Cheers…

iPhone build error

Saturday, July 18th, 2009

I had to deal with the same problem twice in the past 2 days so I decided to put together this little post explaining what one needs to do when they see an error message like this:

error: syntax error before ‘AT_NAME’ token
error: syntax error before ‘}’ token
fatal error: method definition not in @implementation context
Build error message

Build error message

Basically, what happens here is that the target for my iPhone application is using the wrong C/C++ Compiler version.

Here’s the fix:
Step 1 double click the target (or right click Get Info) and change the Compiler version to GCC 4.0

Compiler Version changed to 4.0

Compiler Version changed to 4.0

Step 2 add 2 new build setting conditions (one for the simulator and one for the device)

Build Setting Conditions

Build Setting Conditions

Step 3 Set the values to GCC 4.2

Final settings

Final settings

Hit the magic Cmd + B and you should now have a project that builds (or at least no longer complains about the syntax error above.

Cheers…

UITabBarButtonItem did not change its title

Monday, May 18th, 2009

Today I needed to implement the UITableView's edit / delete functionality inside my UITableViewController. That is fairly simple: 

1. in Interface Builder add a UITabBarButtonItem 
2. from the identifier list select "Edit"
3. Associate with the correct file owner
4. Pick selector and
5. In the selector implementation change the title from "Edit" to "Done" and the other way round depending on the tableView.editing property.
(6. the actual delete operation is not covered in this post)  
I assumed that after tapping the tab button the label would change to "Done". Sadly that did not happen. After a bit of debugging I found that the weird behaviour is caused by a set of _barButtonItemFlags. One of these flags is called "isSystemItem". Unfortunately this flag is set by the Interface Builder in step 2 above.
The solution:  
In step 2 above select Custom and the set the Bar Item Title below in the Interface Builder. 
In step 5 make sure you set the title back to "Edit" when coming out from the editing mode.
Even better solution (biased oppinion):
Avoid using IB to create you UIBarButtonItem! Instead just create the button programmatically using initWithTitle:style:target:action  
How do you create your Buttons?
Cheers…

Selecting a contact on the iPhone

Tuesday, May 12th, 2009

Today I had to load a Contact browser in my iPhone application I have to say I was surprised to see how easy it was!

The first thing that I thought about was to… google for it. Sure, I didn't know this side of the API and I imagined I would have to query some address book database and then build a table view using my query results as datasource. And guess what, this can actually be done very easily.
 
Luckily I looked deeper in the SDK API and found that there is a Navigation Controller already available that does everything I need.
Here are the steps I had to follow in order to implement this functionality.

1. Imports
Add the AddressBook and AddressBookUI frameworks to my project (control click the Target and then Get Info and Add Framework)

2. Set up the controller
Create an instance of ABPeoplePickerNavigationController on the control that you want to trigger the contact selection.

3. Set up a delegate
The controller will make a series of callbacks which is why you need to implement a protocol that is the actual delegate for the above controller. The delegate is ABPeoplePickerNavigationControllerDelegate and the callback methods are below:
– (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker;  
Gets called when the user taps the Cancel navigation button. Here you should dismiss the person picker navigation controller. See point 4 below.

- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person;
This is the place where you get access to the actual section therefore you have to make sure you use the person reference to extract the data you need. See point 5 below. If you want the user to get detailed information about the selected user return YES, if you're only after the name and want to limit navigation just return NO.

- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier;
This is where you take action if the user taps various properties such as phone number, email, etc If you are simply after the person's name like I was simply return NO.

4. Loading the controller and dismissing it
You load the ABPeoplePickerNavigationController using your current navigation controller's presentModalViewController method. You implement this wherever you handle the tap / action on the triggering control.
When the user taps cancel you dismiss the people picker controller via the dismissModalViewControllerAnimated method belonging to your controller. You implement this in the peoplePickerNavigationControllerDidCancel method above.

5. Extracting the relevant information
The ABRecordRef pointer gives you access to the contacts details. Here is how you'd extract the contact's first name:
 
  CFStringRef firstName = ABRecordCopyValue(person, kABPersonFirstNameProperty);

Notice the  kABPersonFirstNameProperty constant. There are many more like this one that enable you to get the data you need. Here is the complete list:

kABPersonFirstNameProperty
kABPersonLastNameProperty
kABPersonMiddleNameProperty
kABPersonPrefixProperty
kABPersonSuffixProperty
kABPersonNicknameProperty
kABPersonFirstNamePhoneticProperty
kABPersonLastNamePhoneticProperty
kABPersonMiddleNamePhoneticProperty
kABPersonOrganizationProperty
kABPersonJobTitleProperty
kABPersonDepartmentProperty
kABPersonEmailProperty
kABPersonBirthdayProperty
kABPersonNoteProperty
kABPersonCreationDateProperty
kABPersonModificationDateProperty

Don't let the CFString data type scare you. You can simply cast to a (NSString *) and use it… This is just one of the interchangeable data types, but that will be another post.

Cheers…

UITabBarController and multiple instances of UITableViewController

Wednesday, May 6th, 2009

Here comes another post from the series “note to self”…

Imagine you have a UITabBarController and you wish to have two very similar UITableViewControllers nested within (as different tab items). If the difference between the two TVCs is simply a matter of configuration (e.g. datasource) then you should simply point Interface Builder to the same class. You need not worry, different instances of your TVC will be created for you.
This comes in handy especially when you use different tab items just because your data is organized differently on each of the tabs.
I just thought I’d share this with you since I *hate* seeing duplicate code!
Cheers…
p.s. the more I master the dynamic UI generation the more comfortable I am using the IB. Isn’t this a bit ironic and paradoxical?!

String representation of NSDate

Monday, March 30th, 2009

Confused yet?

Problem: create a NSDate object that represents the time from a remote system by consuming a web service (resource) that returns NSString. Then get the string value of that date.
Response: [NSDate dateWithStringTimeIntervalSince1970: remoteTime]; YEAH RIGHT!!!

Well no! It doesn't work this way you see…
First of all the method we need to call is defines as:  (id)dateWithTimeIntervalSince1970:(NSTimeInterval)seconds
Note that NSTimeInterval is defined as typedef double NSTimeInterval; so getting a double value becomes the next challenge.
Now we have a NSString and we need a double value. Luckily this is quite easy: NSString provides a  - (double)doubleValue instance method.
Now the code in its entirety becomes:

NSString *remoteDate = [[NSDate dateWithTimeIntervalSince1970: [remoteTimeInMillis doubleValue] / 1000] description];

(I am dividing by 1000 because of this post.)
Cheers…
p.s. let me know if you have a better way of doing this

Custom UIView didn't want to render controls

Tuesday, March 3rd, 2009

… from the amazing world of iPhone development …

Today I created a UIView subclass that belongs to my own UIViewController.
In my UIView drawRect method I create a few components:  a UILabel, a UITextField and a UIButton and then I add them all via [self addSubview: component]. 
The application built and ran successfully but I then discovered that with the exception of the UILabel the other components only had their shape "drawn" on the screen but the default labels where not actually displayed.
After a bit of unsuccessful googling and forum digging I decided to move all the code from drawRect to the constructor since nothing really made sense. To my surprise that fixed it. Fortunately I then decided that I cannot allow for all that code to be in the init method so I did some API digging and found three methods that looked promising. I then tried them all and one actually solved my problem.
So behold the scientifically discovered solution to all programmatically defined GUIs: the  UIView's layoutIfNeeded method! Append all your subviews and once you're done just call it.
Cheers…

Note to self

Tuesday, March 3rd, 2009

Always let the controller load its view. Never try to load the view yourself. That's how MVC works. LOL. 

End embarrassing note to self.
Cheers…