Ipphones

  • Subscribe to our RSS feed.
  • Twitter
  • StumbleUpon
  • Reddit
  • Facebook
  • Digg

Saturday, 28 February 2009

360 iDev Conference, T-Minus 18 hours

Posted on 09:25 by Unknown
It's just about eighteen hours until I leave my house for the 360 iDev conference in San Jose. I'm excited about the trip despite the fact that I'm completely snowed under and behind on my work thanks to a few days of feeling lousy (combined with most of my family and the dog also feeling lousy). Fortunately for me, there's either a loophole in Northwest Airline's elite policy or a bug in their ticketing system.

Since I started the iPhone book almost a year ago, I haven't been traveling very much. Before that, I traveled constantly as part of my consulting work, so I used to have the highest level of status on two airlines and in two hotel chains. That is all gone now. Starting with 2009, all my status is either gone, or reduced to Silver level.

It's a good trade-off. I'd rather be home more with my family more and working with technologies I believe in, but when I do travel, I am going to miss the various perks of status, especially those first class upgrades on long cross-country flights.

But, as it turns out, I won't be missing them on this trip. I still had my status with Northwest when I made the reservations for the conference, and as far as the ticketing system is concerned for upgrade purposes, I still have that status, so it upgraded me for all three flights tomorrow (yes, three flights - urgh). Which means I'll actually be able to get work done on the plane as long as my battery holds out. Of course, now I'm really regretting not pre-ordering a new 17" MBP as I had intended, with its claimed eight-hour battery life.

Anyway, if you're planning on going to the conference, say "Hi" if you see me. If you're not planning to go but you're a reasonable distance from the San Jose, I believe there are still tickets available and it looks like it's going to be a great couple of days.
Read More
Posted in conferences | No comments

Friday, 27 February 2009

Mapping Directions from your App

Posted on 12:45 by Unknown
If you want to give your user driving directions by launching the Maps application, it's actually pretty easy. You just create a regular Google Maps URL and use UIApplication to open it up; Your phone will recognize that the URL is for directions and will open Maps.app rather than Safari.app automatically.

The URL format is very easy for directions:

http://maps.google.com/maps?saddr=[source address or coordinates]&daddr=[destination address or coordinates]

Here is an example of taking the coordinates pulled from Core Location, and using that as the starting point for directions:

    NSString *destinationString = @"Cupertino,California";
NSString *url = [NSString stringWithFormat: @"http://maps.google.com/maps?saddr=%f,%f&daddr=%@", newLocation.coordinate.latitude, newLocation.coordinate.longitude, destinationString];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:url]];

Of course, this doing this quits your application and launches Maps.app, so make sure you've got everything saved before you do it.

There is one gotcha if you're using search terms or a physical address instead of coordinates. Maps.app doesn't like spaces. Unlike Safari, Maps.app won't automatically convert spaces to %20 for you. On the other hand, you don't want to use NSString's stringByAddingPercentEscapesUsingEncoding: either, because that method will convert commas, dashes, and certain other characters, which may cause problems when launching Maps.app (and probably will - those commas are important!).

In most cases, you can just remove the spaces by doing this:

    NSString *newAddressPartOfURL = [addressPartOfURL stringByReplacingOccurrencesOfString:@" " withString:@""]

Technically speaking, we're cheating. We should be able to URL-encode the whole address no problem, and it should work. But… it doesn't. This is one of those situations where you need to cheat a little to get things to work properly. I can tell you from first-hand experience that if you URL-encode those commas in your address, you will get a message that Maps.app couldn't find the specified address.
Read More
Posted in Cocoa Touch, Google Maps, iPhone SDK | No comments

Reusable Code in Google Code

Posted on 07:14 by Unknown
As per a reader request, I have created a repository with all of the re-usable code that I've posted here in my blog. You can find the repository over at Google Code.

I'll try and keep this updated with bug fixes and also add any new reusable code to the repository.
Read More
Posted in Code Reuse, Google Code | No comments

Thursday, 26 February 2009

Alert View with Prompt

Posted on 11:02 by Unknown
Here's another generic class for you. This one doesn't require a navigation app - it can be used pretty much anywhere. It's a custom-subclass of UIAlertView that lets the user type in a value. It supports only two buttons - Okay and Cancel - but it handles everything to do with the text field for you. It looks like this:


You use it pretty much the same way you use an alert view. You allocate and initialize it, call show and then release it:

    AlertPrompt *prompt = [AlertPrompt alloc];
prompt = [prompt initWithTitle:@"Test Prompt" message:@"Please enter some text in" delegate:self cancelButtonTitle:@"Cancel" okButtonTitle:@"Okay"];
[prompt show];
[prompt release];

Then, you implement the appropriate UIAlertView callback method, and grab the entered text from the alert view instance. You have to cast the alert view back to an AlertPrompt instance, but other than that, everything is the same as using a standard UIAlertview:

- (void)alertView:(UIAlertView *)alertView willDismissWithButtonIndex:(NSInteger)buttonIndex
{
if (buttonIndex != [alertView cancelButtonIndex])
{
NSString *entered = [(AlertPrompt *)alertView enteredText];
label.text = [NSString stringWithFormat:@"You typed: %@", entered];
}

}


You can download a sample project that shows how it works right here.

Note: to those of you wondering if this violates the HIG, or will cause problems during review - I don't think it should. Apple does this themselves when they prompt you for a WiFi network password, and I have not used any private APIs or functions whatsoever. I just subclassed an existing public class and extended its functionality in a way that's commonly done.

The code for the class follows:

AlertPrompt.h
//
// AlertPrompt.h
// Prompt
//
// Created by Jeff LaMarche on 2/26/09.

#import <Foundation/Foundation.h>

@interface AlertPrompt : UIAlertView
{
UITextField *textField;
}

@property (nonatomic, retain) UITextField *textField;
@property (readonly) NSString *enteredText;
- (id)initWithTitle:(NSString *)title message:(NSString *)message delegate:(id)delegate cancelButtonTitle:(NSString *)cancelButtonTitle okButtonTitle:(NSString *)okButtonTitle;
@end



AlertPrompt.m
//
// AlertPrompt.m
// Prompt
//
// Created by Jeff LaMarche on 2/26/09.

#import "AlertPrompt.h"

@implementation AlertPrompt
@synthesize textField;
@synthesize enteredText;
- (id)initWithTitle:(NSString *)title message:(NSString *)message delegate:(id)delegate cancelButtonTitle:(NSString *)cancelButtonTitle okButtonTitle:(NSString *)okayButtonTitle
{

if (self = [super initWithTitle:title message:message delegate:delegate cancelButtonTitle:cancelButtonTitle otherButtonTitles:okayButtonTitle, nil])
{
UITextField *theTextField = [[UITextField alloc] initWithFrame:CGRectMake(12.0, 45.0, 260.0, 25.0)];
[theTextField setBackgroundColor:[UIColor whiteColor]];
[self addSubview:theTextField];
self.textField = theTextField;
[theTextField release];
CGAffineTransform translate = CGAffineTransformMakeTranslation(0.0, 130.0);
[self setTransform:translate];
}

return self;
}

- (void)show
{
[textField becomeFirstResponder];
[super show];
}

- (NSString *)enteredText
{
return textField.text;
}

- (void)dealloc
{
[textField release];
[super dealloc];
}

@end

Read More
Posted in | No comments

Wednesday, 25 February 2009

Editable Select List

Posted on 06:53 by Unknown
For a project I was working on, we had a text field that the users would tend to enter the same handful of values over and over. In fact, the fact that they had to keep entering the same values over and over was quite frustrating to our testers. But we couldn't provide a set list, because it wouldn't be the same values for all users. They needed the flexibility to add any value they needed, but wanted the convenience to not have to enter ones that they had already entered. On a desktop app, the likely answer would have been a combo-box, or a text field with type-ahead that would allow the user to type only a few characters of the value and then hit tab or return to select it.

The iPhone doesn't have combo-boxes, and type-ahead would be a pain to implement and I had concerns that it might get dinged in the review process (Yes, Apple, your review policies are definitely having a chilling effect). The answer I came up with for handling this situation was to create an editable selection list controller. It works just like the Generic Selection List Controller I posted about a week ago, except that it tacks one item onto the end of the table to allow the user to add a new item to the list:


When you select that last item, it uses the Multiple Text Field Editing Controller to prompt the user for the new value:



At some point, I'd like to refactor this class, and the SelectionListViewcontroller into one class, as there is a lot of common ground between them, but for now, it's a separate class. You must have the TextFieldEditingViewcontroller class in your project also, because it uses that to let the user enter new values.

EditableSelectionListViewController.h
//
// SelectionListViewController.h
//
// Created by Jeff LaMarche on 2/18/09.
// Copyright 2009 Jeff LaMarche Consulting. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "AbstractGenericViewController.h"
#import "TextFieldEditingViewController.h"

@protocol EditableSelectionListViewControllerDelegate <NSObject>
@required
- (void)rowChosen:(NSInteger)row fromArray:(NSMutableArray *)theList;
@end


@interface EditableSelectionListViewController : AbstractGenericViewController <TextFieldEditingViewControllerDelegate>
{
NSMutableArray *list;
NSIndexPath *lastIndexPath;
NSInteger initialSelection;

id <EditableSelectionListViewControllerDelegate> delegate;
}

@property (nonatomic, retain) NSIndexPath *lastIndexPath;
@property (nonatomic, retain) NSArray *list;
@property NSInteger initialSelection;
@property (nonatomic, assign) id <EditableSelectionListViewControllerDelegate> delegate;
@end



EditableSelectionListViewController.m
//
// SelectionListViewController.m
//
// Created by Jeff LaMarche on 2/18/09.
// Copyright 2009 Jeff LaMarche Consulting. All rights reserved.
//

#import "EditableSelectionListViewController.h"


@implementation EditableSelectionListViewController
@synthesize list;
@synthesize lastIndexPath;
@synthesize initialSelection;
@synthesize delegate;
-(IBAction)save
{
[self.delegate rowChosen:[lastIndexPath row] fromArray:list];
[self.navigationController popViewControllerAnimated:YES];
}

#pragma mark -
- (id)initWithStyle:(UITableViewStyle)style
{
initialSelection = -1;
return self;
}

- (void)viewWillAppear:(BOOL)animated
{
// Check to see if user has indicated a row to be selected, and set it
if (initialSelection > - 1 && initialSelection < [list count])
{
NSUInteger newIndex[] = {0, initialSelection};
NSIndexPath *newPath = [[NSIndexPath alloc] initWithIndexes:newIndex length:2];
self.lastIndexPath = newPath;
[newPath release];
}


[super viewWillAppear:animated];
}

- (void)dealloc
{
[list release];
[lastIndexPath release];
[super dealloc];
}

#pragma mark -
#pragma mark Tableview methods
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [list count] + 1;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{

static NSString *SelectionListCellIdentifier = @"SelectionListCellIdentifier";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:SelectionListCellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:SelectionListCellIdentifier] autorelease];
}


NSUInteger row = [indexPath row];
NSUInteger oldRow = [lastIndexPath row];
if (row >= [list count])
{
cell.font = [UIFont boldSystemFontOfSize:19.0];
cell.text = NSLocalizedString(@"Other…", @"Other…");
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}

else
{
cell.font = [UIFont systemFontOfSize:19.0];
cell.text = [list objectAtIndex:row];
cell.accessoryType = (row == oldRow && lastIndexPath != nil) ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;

}


return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
int newRow = [indexPath row];
int oldRow = [lastIndexPath row];

if (newRow < [list count])
{
if (newRow != oldRow)
{
UITableViewCell *newCell = [tableView cellForRowAtIndexPath:indexPath];
newCell.accessoryType = UITableViewCellAccessoryCheckmark;

UITableViewCell *oldCell = [tableView cellForRowAtIndexPath: lastIndexPath];
oldCell.accessoryType = UITableViewCellAccessoryNone;

lastIndexPath = indexPath;
}

}

else
{
TextFieldEditingViewController *controller = [[TextFieldEditingViewController alloc] initWithStyle:UITableViewStyleGrouped];
controller.fieldKeys = [NSArray arrayWithObject:@"newValue"];
controller.fieldNames = [NSArray arrayWithObject:NSLocalizedString(@"New Item", @"New Item")];
controller.fieldValues = [NSArray arrayWithObject:@""];
controller.delegate = self;
[self.navigationController pushViewController:controller animated:YES];
}

[tableView deselectRowAtIndexPath:indexPath animated:YES];
}

#pragma mark -
- (void)selectRow:(NSIndexPath *)theIndexPath
{
//[self.tableView selectRowAtIndexPath:theIndexPath animated:YES scrollPosition:UITableViewScrollPositionBottom];
[self tableView:self.tableView didSelectRowAtIndexPath:theIndexPath];
}

- (void)valuesDidChange:(NSDictionary *)newValues
{
NSString *newVal = [newValues objectForKey:@"newValue"];
[list addObject:newVal];
//[self.tableView reloadData];

[list sortUsingSelector:@selector(compare:)];
NSUInteger theIndices[] = {0, [list indexOfObject:newVal]};
NSIndexPath *theIndexPath = [[NSIndexPath alloc] initWithIndexes:theIndices length:2];
[self performSelector:@selector(selectRow:) withObject:theIndexPath afterDelay:0.05];
// [self tableView:self.tableView didSelectRowAtIndexPath:theIndexPath];
[self.tableView reloadData];
}

@end


Read More
Posted in Code Reuse, Controller Classes, iPhone SDK | No comments
Newer Posts Older Posts Home
Subscribe to: Comments (Atom)

Popular Posts

  • Making OpenGL ES Screenshot
    The Bit-101 Blog has an entry that shows how to take a screenshot when using OpenGL ES . I tested this in my much-delayed particle-generato...
  • Adding CLANG to Your Build Process
    Frasier Spiers has a nifty piece this morning on using Git pre-commit hooks to automatically run the CLANG Static Analyzer. I'm not a G...
  • CLANG Static Analyzer
    If you aren't using the LLVM/Clang Static Analyzer , you really should be. The Clang Project is an attempt to write a front end for the...
  • A Little Help
    I'm having a problem with OpenGL ES, and it's keeping me from finishing my particle engine post. I was hoping someone here could see...
  • WWDC Accommodations
    Staying downtown in San Francisco is very expensive in the summertime. Bu, if you're going to WWDC, you really want to stay downtown. Yo...
  • Xcode File Templates and a Mystery
    One of the things that confuses many newcomers to Xcode is how to set it up so that your company name gets automatically filled in when you ...
  • Brain Surgery?
    Craig Hockenberry has an interesting post on his blog today about the iPhone background processing issue. Craig speaks from personal experi...
  • Book's Almost Done
    I just finished Chapter 16. I'll give it another read-over in the morning then it will go off to my writing partner for his review, then...
  • iPhone Alley
    Looks like Dave and I are going to make an appearance on the iPhone Alley Podcast next week. We're recording on Sunday night, so I woul...
  • Shuffling Arrays
    Ever want to randomize an array of items? It's a task that, for some reason, I've had to do a lot in recent programs. So, I wrote a ...

Categories

  • 3D Models
  • Ad Hoc Distribution
  • ADC
  • Address Book
  • Amazon
  • Anaglyphs
  • App Store
  • Apple
  • Apple DTS
  • Apple Store
  • Application Store
  • articles
  • Award
  • Background Processing
  • Barcodes
  • Beta
  • Blog
  • Blogger
  • Blogging
  • Blogs
  • Blogspot
  • Book project
  • Bug Reporting
  • Captain Obvious
  • Categories
  • Censorship
  • CFFoundation
  • CGAffineTransform
  • Clang Static Analyzer
  • Cocoa
  • Cocoa Touch
  • Code Reuse
  • Code Signing
  • Computer
  • conferences
  • Controller Classes
  • Core Animation
  • Daring Fireball
  • Database
  • Debugging
  • Defect
  • Delegates
  • Design Awards
  • Developer Certifications
  • Discussion Forums
  • Edit Mode
  • employment opportunities
  • Encryption
  • Enterprise
  • Errata
  • free code
  • Free software
  • Full Screen
  • Game Programming
  • Gestures
  • Getting Started
  • goof
  • Google Code
  • Google Maps
  • Gotcha
  • Help
  • HIG
  • HTTP PUT
  • Idiots
  • Idle Timer
  • Images
  • Instruments
  • Interface Builder
  • iPHone
  • iPhone Applications
  • iPhone Dev Center
  • iPhone Developers
  • iPhone OS 3.0
  • iPhone SDK
  • iPhone SDK PNG
  • iPhone Simulator
  • iPhoneSDK
  • iPod
  • Job Opportunities.
  • k
  • Key Value Observing
  • Keynote
  • KVO
  • Landscape Mode
  • Learn Cocoa
  • Learn Cocoa on the Mac
  • libxml
  • Licensing
  • Mac Developers
  • Mac OS X
  • Macworld Expo
  • Microsoft
  • NDA
  • NeHe
  • New Category
  • New Release
  • NSFileHandle
  • NSMutableArray
  • NSMutableURLRequest
  • NSXML
  • Object-Oriented Design
  • Objective-C
  • Open Source
  • OpenGL ES
  • Optimizations
  • Other blogs
  • Paired Arrays
  • Parsing
  • Particle Engine
  • Party
  • PeopleSoft
  • Performance
  • Persistence
  • Pink Screen of Death
  • Piracy
  • Pixar
  • Podcasts
  • Press Release WTF
  • Press Releases WTF
  • private APIs Google
  • Project Template
  • Properties
  • Random Numbers
  • Rant
  • Rejected
  • Resources
  • Responder Chain
  • REST
  • Reverse Engineering
  • Rumors
  • Runtime
  • Sample Code
  • Screencast
  • screenshot
  • Scroll Views
  • snippet
  • Snow Leopard.
  • SOAP
  • Sockets
  • Source
  • Splash Screen
  • SQLite
  • SQLitePersistentObjects
  • Steve Jobs
  • Steve-Note
  • Strings
  • Stupidity
  • Subversion
  • Table Views
  • Taps
  • Template
  • Tip
  • Tips
  • Tririga
  • tutorials
  • Twitter
  • UIAlertView
  • UIColor
  • UIImage
  • UIPickerView
  • UIScrollView
  • UITextField
  • UIView
  • UIWebView
  • Update
  • Utilities
  • UUID
  • Vacation
  • Version Control
  • Web Services
  • Writing
  • WTF
  • WWDC
  • Xcode
  • XML

Blog Archive

  • ▼  2009 (141)
    • ►  May (14)
    • ►  April (30)
    • ►  March (48)
    • ▼  February (26)
      • 360 iDev Conference, T-Minus 18 hours
      • Mapping Directions from your App
      • Reusable Code in Google Code
      • Alert View with Prompt
      • Editable Select List
      • BWToolkit
      • Asynchronous Downloading of Images in a Table View
      • Rogue Amoeba is Hiring
      • Cross Development Hint
      • Making OpenGL ES Screenshot
      • Programmatically Drawing Gloss Gradients
      • All Generic Controllers to Date (Zip File)
      • Generic Selection List Controller
      • Computer Books & the Economy
      • What Are All the Cool Kids Doing These Days?
      • 360 iDev Conferences
      • Strong Encryption for Cocoa / Cocoa Touch
      • CLANG Static Analyzer
      • Long Text Generic Editing Controller
      • Same but Different
      • Accessorizer
      • Gameplay Videos
      • KVO and the iPhone SDK
      • Learn Cocoa
      • SQLitePersistentObjects Update
      • Longer Spinning & Blurring v2.0
    • ►  January (23)
  • ►  2008 (163)
    • ►  December (46)
    • ►  November (25)
    • ►  October (44)
    • ►  September (2)
    • ►  August (5)
    • ►  July (2)
    • ►  June (9)
    • ►  May (2)
    • ►  April (11)
    • ►  March (17)
Powered by Blogger.

About Me

Unknown
View my complete profile