Saturday, December 29, 2012
Every iPhone App Developer should be an App Store Affiliate
Friday, December 28, 2012
Writing iPhone Apps for the Virtual iPhone
We have always been an admirer of the iPhone user interface design. The iPhone iOS has advanced the UI to a new level. While the iPhone OS is written is Objective C, we have recreated the iPhone for the web using HTML, CSS & Javascript. This will provide all people with a chance to use the beautiful and intuitive interface of the iPhone & iPad.
See more at Red Rome Virtual iPhone Coding
Wednesday, January 21, 2009
Developers, developers, developers, developers...
Tuesday, January 20, 2009
It's been a while
Wednesday, December 31, 2008
Another resource
Tuesday, December 30, 2008
Interface Builder 101: An Overview
The first thing we will do is create a new Window based application in Xcode, lets call it "IBPractice." In the project window double click MainWindow.xib to open it with Interface Builder. From the Library drag a UIButton and a UILabel into your Window.
Now click somewhere in the view that is not the label or button. Now in the Inspector click the “i” button.
Now we must move to the Connections tab in the Inspector window.
Select File -> Write Class Files. Be sure to have “Create '.h' file” checked, then save. Then click the check box next to IBPractice and select Add.
It is now time to return to Xcode. In Xcode open MainView.h and replace your @interface line with
@interface MainView : UIView {
Now move to the MainView.m file. Within the brackets of – (IBAction)showText is where we will create our code to make things work. We will tell our program to display “Hello World” within our label. To do this add the following line of code:
And that is all! We have created a very basic interface using Interface Builder. Using what you learned here you should be able to make much more complex interfaces.theLabel.text = @"Hello World";
Monday, December 29, 2008
UITableView Part III
NSString *myTitle;
And:
@property (copy, readwrite) NSString *myTitle;
Just as we have in the past. Also, make sure to synthesize it!
@synthesize myTitle;
Beyond that all we will do for now is make sure viewDidLoad holds:
self.title = myTitle;
That's all for now, since this is just a simple example of this. We'll go back into the RootViewController class. Remember to add this up by the other imports:
#import "SecondLevelController.h"
Now, we'll handle the selection of the row. Remember from before? There was this class for us:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
Well, we'll be using this to handle the selection, so we can add a few lines of basic code. Here's how I have mine setup:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
SecondLevelController *anotherViewController = [[SecondLevelController alloc] initWithStyle:UITableViewStylePlain];
anotherViewController.myTitle = [tableView cellForRowAtIndexPath:indexPath].text;
[self.navigationController pushViewController:anotherViewController animated:YES];
[anotherViewController release];
}
What is being done here is the same row is being deselected as before. This doesn't cancel the selection, or anything, all it does is drops the blue color on the background of the cell.
Then it creates the next view controller, and sets its myTitle property. The reason I did this was to show an example of how we can use indexPath and a property to make sure the next level of our drill down has the unique attribute it needs. Then we push the view controller onto the stack. When you run this you'll see it's how we want it. The title is set with whatever you select in the list.
Here's the source code of up until this part: Download Source Code for UITableView Part III
While I won't go too far into depth I can explain briefly another practical use of this. One method I have used is to keep my entire drill-down navigation in an NSArray.
If I were to have an organization of something such as the NFL we might have something like:
-Divisions
--Teams
---Players
What I would do is have the NSArray hold the divisions which would be stored as an NSDictionary each.
The NSDictionary would have fields such as "Name" (String), "Teams" (Array of type NSDictionary), and "Conference" (String)
The "Teams" are the next level of navigation, which would have the fields such as "Name" (String) and "Players" (Array of type NSDictionary)
This may be difficult to understand with only words, but through the use of the ideas from above you could definitely create a drill-down of your own with your needed implementation.
UITableView Part II
self.title = @"Table Testing!";
So what we have for that section is:
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"Table Testing!";
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
Already we should be seemingly close to our desired effect. Visually it would seem so if you choose to run it now. I ran it in the simulator and it looks like this:
Even though visually it would seem as though we are very close to our goal, that wouldn't happen to be the case just yet as we have almost all of our programming yet to do. For now, we'll hop back to the app delegate so we can create a couple support methods. We'll need to be able to remove items as well as move items to fully show the UITableView editing experience. So that will basically require two methods. I'll call them removeFromList and moveFromOriginal: toNew:. So in the TableViewPraticeAppDelegate.h they will be:
-(void) removeFromList:(NSInteger)index;
-(void) moveFromOriginal:(NSInteger)indexOriginal toNew:(NSInteger)indexNew;
And these can be added before or after the -(void) createArray; Order doesn't matter in these cases.
Here is my implementation for the removal from the list:
-(void) removeFromList:(NSInteger)index {
NSMutableArray *tempArray = [[NSMutableArray alloc] initWithArray:theArray];
[tempArray removeObjectAtIndex:index];
theArray = tempArray;
}
This can be done a great number of ways, but I decided to go with this route. Another fairly simple option would be making theArray an NSMutableArray for ease of use, but I like using an NSArray when possible. What I am doing is creating a new array with the same objects and then removing the object we no longer need from that list and resetting our "theArray" as the correct array.
My implementation for the moving items on the list is very similar:
-(void) moveFromOriginal:(NSInteger)indexOriginal toNew:(NSInteger)indexNew {
NSMutableArray *tempArray = [[NSMutableArray alloc] initWithArray:theArray];
id tempObject = [tempArray objectAtIndex:indexOriginal];
[tempArray removeObjectAtIndex:indexOriginal];
[tempArray insertObject:tempObject atIndex:indexNew];
theArray = tempArray;
}
This will grab the temporary object (i.e. the object which is moving) so we can remove it from the list and then add it back in where we now want it.
That will handle that end of things, so now we just need to edit two methods that already exist in the RootViewController. Towards the bottom you will see commented out:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
Get rid of those comments, and we can use some pre-existing code along with simply calling our methods we just created. Our end result will be this:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
TableViewPracticeAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source
[appDelegate removeFromList:indexPath.row];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:YES];
}
else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
As you can see I have once again called the appDelegate and will be using that to call the removeFromList we just created. Make sure you add the .row after indexPath, otherwise your program will crash and burn like a Zeppelin filled with a highly flammable gas.
We can use a similar approach for moving, once again, here is my class once the comments were removed for that as well:
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath {
TableViewPracticeAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
[appDelegate moveFromOriginal:fromIndexPath.row toNew:toIndexPath.row];
}
So this one will once again use the indexPath.row idea to pass along the actual row number we are in. With both of these methods created the only thing left to do is make sure to remove the comments surrounding:
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
We want all areas to be movable, so we will leave this at straight forward return YES;
Since it's boring to be playing with two rows, I went back and added a bit more to my NSArray I was creating. I made it originally have the objects "Hello", "World", "How", "You?", "Are" and then moved it around to create the sentence I wanted and then removed world to create a simple "Hello How Are You?" sentence. This will give you a much better feeling of playing around with an editable UITableView.
Your editable UITableView should function just fine, no matter what you throw at it. But what you may notice is if you close the application and then launch it again later, the list will be as it was originally. You may not want this to happen, so as I introduced the App Delegate and its purposes and a possible use in the last section, I will introduce NSUserDefaults in this one.
NSUserDefaults can store information for your application beyond just when it is open. So while the app delegate was very useful when dealing with information what was currently running, we can use NSUserDefaults to keep that information safe while we're not running the application.
Note: There are many other methods in storing information, this is only one and you should not live and die by only one method of storing information.
We can do all of these changes within the delegate's .m file. First off, we need to store the information when the application is closing. Find:
- (void)applicationWillTerminate:(UIApplication *)application
Inside of this we can put things we want to happen if the user closes the application. So naturally this would be the easiest way to store the information each time we're done editing our list. We do that by first calling the NSUserDefaults, which is again very easy:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
This will get the NSUserDefaults for us and what's important to know is that this works similar to an NSDictionary, not an NSArray. So we can set things as values for keys, rather than putting in an object at an index. So we can store the array as "lastArray" by putting in:
[defaults setObject:theArray forKey:@"lastArray"];
Seems simple enough, now we just need to check for it when our application is launched. So let's replace this snippet from the applicationDidFinishLaunching:
// Create the array
[self createArray];
With this new section:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if([[defaults objectForKey:@"lastArray"] count] > 0) {
// We already have an array, let's use it
theArray = [defaults objectForKey:@"lastArray"];
} else {
// Create the array
[self createArray];
}
This seems to be an elegant way to check, that way, if the user has either launched this for the first time or if they have deleted everything, it will create the array, otherwise it will use the latest array before the application was closed.
Here's the source code once again: Download UITableView Part II Source Code
Enjoy!
More on the app delegate
#import "TableViewPracticeAppDelegate.h"
And then one simple line and we're there! Where you want to use this be sure to put this line of code:
TableViewPracticeAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
This is again assuming the last post's project/file names, but I assume everyone could easily modify this code to meet their own needs. Since theArray was setup as a property in the app delegate, we were able to call it no problem. If we wanted to get an object called "someItem" all we would need would be
[appDelegate someItem];
Hopefully this clears up any confusion in case anyone was struggling with that particular section of the UITableView Part I.
A UITableView Primer
@interface TableViewPracticeAppDelegate : NSObject
{ UIWindow *window;
UINavigationController *navigationController;
NSArray *theArray;
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet UINavigationController *navigationController;
@property (nonatomic, retain) NSArray *theArray;
-(void) createArray;
@end
Now we have the .h file ready, so let's jump into the .m file. First off, we need to synthesize the array, so do that by adding this after the @implementation line:
@synthesize theArray;
I typically create another class in the delegate to create the array of information which needs to be displayed using my UITableView. I've called mine createArray as you can see above, and it can be void for my particular implementation. We'll keep it simple, something like this:
- (void)createArray {
NSArray *myArray = [[NSArray alloc] initWithObjects:@"Hello", @"World", nil];
theArray = myArray;
}
The delegate looks good, let's move onto the UITableView class (RootViewController)
Now, each method in this will be called automatically, so no need to link anything up per se, because a UITableView class is ready to run with these methods. I'll try and explain each one briefly before showing how we will implement it, they are fairly self explanatory but make sure you understand them and use them properly.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
Return the number of sections in a tableview, since our array is very basic, we can simply return 1.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
This can be used to specify how many rows are in each section, since our UITableView only has one section, we can use this fairly easily as well.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
This still remains fairly simple in a basic implementation, but can be used to change the appearance of the given row in the UITableView. This also exposes us for the first time to "indexPath." Don't be intimidated by this, this can be used greatly to our advantage.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
This can be used to handle if a row is touched. You can choose to implement this or not. In this basic example we will only use this is a very simple form.
There are a few more methods that go into editing a UITableView, but since we aren't going to be implementing that we'll cover it at the time in which it seems more relevant.
Let's get down to the actual implementation inside the UITableView!
Like I mentioned earlier, this is basically all structured around the array and its traits. Knowing that the implementation should be fairly simple. To do this I will use the app delegate to give us the array. We can do that by using this line of code:
TableViewPracticeAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
This is a powerful line of code, and will make it so the number of rows can easily be expressed:
return [[appDelegate theArray] count];
So that whole section will become:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
TableViewPracticeAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
return [[appDelegate theArray] count];
}
Pretty simple, right? With only one section this becomes easy, because we know we can return the count and it will work. For multiple sectioned tables, we would want to create a switch, but this is clearly not needed in our implementation.
For the cellForRowAtIndexPath method we can use the app delegate again. Under the comment that already exists that reads "// Setup the cell" we can put:
TableViewPracticeAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
cell.text = [[appDelegate theArray] objectAtIndex:indexPath.row];
That whole section (For copy and paste purposes) should now read:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
// Set up the cell...
TableViewPracticeAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
cell.text = [[appDelegate theArray] objectAtIndex:indexPath.row];
return cell;
}
Now this should look how we want it, try and run it!
I mentioned earlier that we would only go into the basics of the didSelectRowAtIndexPath. So if we peak at that we can change it to:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath {
// Navigation logic may go here. Create and push another view controller.
// AnotherViewController *anotherViewController = [[AnotherViewController alloc] initWithNibName:@"AnotherView" bundle:nil];
// [self.navigationController pushViewController:anotherViewController];
// [anotherViewController release];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
I left Apple's little comments in there because it will make sense when we try to implement it later. All this will do will deselect the row that was selected, so you will see it selected for a second, then deselect itself with some nice fading animation. Since this is only one level deep this is basically all it will need.
To sum up what is happening in a basic way:
-The UITableView is calling all of those methods automatically
-We're using the indexPath to find out where we are at that particular moment
-We're setting the text of each row using indexPath.row.
In the next posts I'll be sure to cover editing, more on selecting, and other stuff we can do with UITableViews.
Here's the source of this tutorial: Download Tutorial Source Code