Thursday, November 19, 2009
The Need for Mobile Optimization
This is definitely a NEED not a want.Being in a profession of constant change I am always reading someone's blog, tutorial or latest trends in various subsets of the web. Most of the time I just fire up Google Reader and start reading. However, over the past 6 months I have found myself using my iPhone as my "reader" of choice. Partly because of the convenience factor and in addition, I don't have to carry my laptop around everywhere I go. Outside of Google Reader one of the best sources that I have for great articles are from some of the big names in web development that I follow on Twitter. However, the sites and articles that people are linking to are still optimized for a standard browser, not the mobile experience which is HIGHLY annoying. It is not that I am too lazy to wait for the page to load, but the lack of patience that I have for the delay in the page to finish loading due to 30+ stylesheets requested, some ad tracking pixel or any number of other tasks that are processing that have ZERO to do with what I, the user, is trying to accomplish. What I find myself doing more and more is using the mobile app functionality of emailing the link to myself so that I can read it when I do get back to my laptop. Should this mean that companies should have a regular/mobile site? There is no right or wrong answer for that. You have to do research and look at your visitor trends and who your target audience is. I would venture to say that if you are a news organization then the answer would be yes. However, even though currently you might have a low percentage of mobile visitors that number will only increase over time and your site should at the bare minimum be optimized for a mobile browsing experience.
Friday, October 30, 2009
AVAudioRecorder prepareToRecord Silent Error
I was working on the voice record feature for one of my upcoming iPhone apps, but when I would try to start recording the app would crash. During the adventure of debugging I couldn't trace anything back to my code as far as memory leaks, uninitialized properties, missing delegate methods, etc. After about an hour I think I almost as many NSLog entries as I did code. The two biggest troubling aspects where:
- prepareToRecord was the method that was failing
- AVAudioRecorder initialization wasn't throwing any errors
Monday, October 26, 2009
Zend Framework Dynamic Site - In Production
Back in April I wrote a blog post discussing my concept of having a dynamic site using the Zend Framework. In addition, I posted an some example code of how everything works. I am a firm believer that one should practice what they preach and two different sites are now in production using the framework that I wrote and so far it works beautifully. I had to make a few changes to the route to allow for module exceptions. Towards the end of the project there was a request to have a search functionality and also custom forms. Normally this wouldn't be an issue what so ever, but the way that the custom route is setup all requests are send to the default module/index controller/index action. I modified the route to ignore any request that started with search or forms and route those requests to the search or forms module. The regex is easily modified to allow for other exceptions. Custom Regex:
<route>^(?!\bsearch|forms\b)(\w+-?[\w-?]*\/?)(.*)?</route>I also setup the ability to add in meta keywords and meta description tags in the content.xml file. Finally, both sites use the EXACT same doc root and dynamic site framework. Since both sites use the same layouts, just different menus and different background images, I didn't want to duplicate a lot of code. So in the setup page display plugin I am able to transverse the content mapping file based upon not only the request, but the url host name to display the proper layout.
<route>^(?!\bsearch|forms\b)(\w+-?[\w-?]*\/?)(.*)?</route>I also setup the ability to add in meta keywords and meta description tags in the content.xml file. Finally, both sites use the EXACT same doc root and dynamic site framework. Since both sites use the same layouts, just different menus and different background images, I didn't want to duplicate a lot of code. So in the setup page display plugin I am able to transverse the content mapping file based upon not only the request, but the url host name to display the proper layout.
Thursday, October 8, 2009
SlideView Contribution
One of my favorite iPhone related sites to read is iPhone Developer Tips. The tutorials are outstanding and most importantly "real world" useful. Back in August there was a blog posted showing how to implement a "slideable" message that can be presented to a user. After reading through it I decided to modify how it was used to make it a little more extensible for an iPhone project that I am working. After I got everything working correctly and they way I wanted to I decided to contact the site owner, John, with all of my source code in case he wanted to use it. After a little more tweaking to my code he posted my changes, as well as another developer, Greg's code in a new post. This is a small example of the importance of using open source software, as well as, the importance for developers to use the knowledge and skills of other developers to make the good....GREAT. Sliding Views On and Off Screen – Part 2 – Reader Contributions
Monday, September 28, 2009
Best Practices That Work
Tonight I got an email from a friend that my site was down. Sometimes, if Apache has been running for a long time on my vhost then for some reason the process id gets corrupted. I don't know if that has to do with the VPS or what. I never had that problem when I had my dedicated server. It happens so infrequently I rarely even notice. However, my usual task of just restarting Apache didn't work. I got an error message that the main site's docroot didn't exist. That was very strange and very disturbing. I got on the phone with the sysadmins at my hosting company and couldn't really find the culprit and they didn't have the automated backup of the site. The good news, as I was told, was that they could recreate the directory structure within one minute and get Apache up and running. SWEET! However, what about my site?! Though they offer backups for the VPS they are not guaranteed. I was not panicking because I keep all site changes backed up in subversion on a completed different host. Once the directory structure was put back in place all I had to do was check the latest copy of my site and I was backup and running. It was good to see and know that using best practices does ACTUALLY work. Imagine that.
Tuesday, September 22, 2009
Using NSNotificationCenter with UINavigation Controllers
When presenting an app to user with a large list of information, most developers will add in the ability to search the list inside of the table view. To further increase usability it is a good practice to include different filters. For example, a scope button that allows the user to filter by name, address, phone number, etc. Implementing these features is pretty straight forward. However, one of the filter options that was needed for a particular app that I am working on was to filter by department. The complexity to this problem came in the fact that the search term couldn't be the department name, but the code. Obviously, most users don't know the corresponding codes for a given department. So I needed a way to present a list of "friendly" department names to the user to pick from, and once a given department was chosen then the corresponding department code would be populate the search bar field. The first attempt was to use a UIPickerView. Unfortunately, this wasn't the best solution mainly because you can't use key/value pairs with the UIPickerView. Well...not in a very straight forward manner. My second solution attempt was to use a modalViewController and then pass the selected object back to the parent controller. Everything worked out just fine, but the parent object property wasn't being updated. To solve this problem there are a couple of schools of thought.
// Parent UIViewControlller- (void)viewWillAppear:(BOOL)animated { [[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(refreshSearchBarControllerWithDepartmentCode:)
name:@"DepartmentCodeNotification"
object:nil];
[super viewWillAppear:animated];
}
- (void) refreshSearchBarControllerWithDepartmentCode:(NSNotification *)notification { NSString *key;
NSString *trimmedSearchString; for (key in [notification userInfo]) {
trimmedSearchString = [[[notification userInfo] valueForKey:key] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
self.searchDisplayController.searchBar.text = trimmedSearchString; [self.searchDisplayController.searchBar becomeFirstResponder];
[self.searchDisplayController.searchResultsTableView reloadData];
}- (void)searchBar:(UISearchBar *)searchBar selectedScopeButtonIndexDidChange:(NSInteger)selectedScope {
if (selectedScope == DEPARTMENT_SCOPE_TITLE_INDEX && [[self.searchDisplayController.searchBar text] length] <= 2) {
DepartmentsViewController *dvController = [[DepartmentsViewController alloc] initWithNibName:@"DepartmentsView" bundle:[NSBundle mainBundle]]; [self presentModalViewController:dvController animated:YES]; [dvController release];
} else if ([[self.searchDisplayController.searchBar text] length] >= 2) {
NSString *trimmedSearchString = [[self.searchDisplayController.searchBar text] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; [self getEmployees:trimmedSearchString method:[[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:selectedScope]]; [self.searchDisplayController.searchResultsTableView reloadData];
}
} //Child UIViewController
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { NSString *code = [self.tableView cellForRowAtIndexPath:indexPath].detailTextLabel.text;
NSString *description = [self.tableView cellForRowAtIndexPath:indexPath].textLabel.text;
NSDictionary *searchDepartmentCode = [NSDictionary dictionaryWithObjectsAndKeys: code, description, nil]; [[NSNotificationCenter defaultCenter] postNotificationName:@"DepartmentCodeNotification"
object:nil
userInfo:searchDepartmentCode]; [self dismissModalViewControllerAnimated:YES];
} END RESULT:
After a user selects the appropriate department, the child controller is dismissed and the search bar text is updated with appropriate department code.
- Set the parent controller as the delegate and setup a new protocol that the child controller implements.
- Use the NSNotificationCenter which uses the Observer Pattern to update another object based upon some action/method.
// Parent UIViewControlller- (void)viewWillAppear:(BOOL)animated { [[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(refreshSearchBarControllerWithDepartmentCode:)
name:@"DepartmentCodeNotification"
object:nil];
[super viewWillAppear:animated];
}
- (void) refreshSearchBarControllerWithDepartmentCode:(NSNotification *)notification { NSString *key;
NSString *trimmedSearchString; for (key in [notification userInfo]) {
trimmedSearchString = [[[notification userInfo] valueForKey:key] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
self.searchDisplayController.searchBar.text = trimmedSearchString; [self.searchDisplayController.searchBar becomeFirstResponder];
[self.searchDisplayController.searchResultsTableView reloadData];
}- (void)searchBar:(UISearchBar *)searchBar selectedScopeButtonIndexDidChange:(NSInteger)selectedScope {
if (selectedScope == DEPARTMENT_SCOPE_TITLE_INDEX && [[self.searchDisplayController.searchBar text] length] <= 2) {
DepartmentsViewController *dvController = [[DepartmentsViewController alloc] initWithNibName:@"DepartmentsView" bundle:[NSBundle mainBundle]]; [self presentModalViewController:dvController animated:YES]; [dvController release];
} else if ([[self.searchDisplayController.searchBar text] length] >= 2) {
NSString *trimmedSearchString = [[self.searchDisplayController.searchBar text] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; [self getEmployees:trimmedSearchString method:[[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:selectedScope]]; [self.searchDisplayController.searchResultsTableView reloadData];
}
} //Child UIViewController
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { NSString *code = [self.tableView cellForRowAtIndexPath:indexPath].detailTextLabel.text;
NSString *description = [self.tableView cellForRowAtIndexPath:indexPath].textLabel.text;
NSDictionary *searchDepartmentCode = [NSDictionary dictionaryWithObjectsAndKeys: code, description, nil]; [[NSNotificationCenter defaultCenter] postNotificationName:@"DepartmentCodeNotification"
object:nil
userInfo:searchDepartmentCode]; [self dismissModalViewControllerAnimated:YES];
} END RESULT:
After a user selects the appropriate department, the child controller is dismissed and the search bar text is updated with appropriate department code.
Thursday, September 10, 2009
Microsoft and Enhanced Experience
I read a very interesting article yesterday that ranked the usability between Apple's website and Microsoft's website. Granted, I am a little biased toward Apple, but I do feel that the author did a great job in their comparison. *spoiler: Apple won. To add to the critique the Microsoft website does something that is a HUGE pet peeve of mine.
If a company claims to be in the "web" business then they need to create websites that look the same in all browsers. Microsoft has a HORRIBLE reputation on releasing browsers that are not standards compliant, but are constantly giving non-IE users who visit their websites a second rate experience. Case in point...their own website. If you go their website with anything other than Internet Explorer, the visitor is presented with this ANNOYING alert in the upper left hand corner that is asks if you want to "Upgrade your Internet experience". After few seconds it does minimize, but if you don't click the "Don't show me this EVER again link" the next page you navigate to will show it. The fact is that I do want to upgrade my internet experience, but not by installing Silverlight, or IE7 or IE8 for that matter. All of the before mentioned pieces of software are horrible, lack innovation, and do nothing but dumb down the web. I want to upgrade my internet experience by not being harassed by Microsoft.
Subscribe to:
Posts (Atom)
