V2EX
   Category:
 Programming
Posted in Programming, iPhone on October 1st, 2009 by Xin

If you’re going to create your own iPhone games, with help from a good game engine, your life will be much easier, and you’ll be able to focus on executing your ideas, not the low-level details involving too much math and OpenGL.

cocos2d for iPhone

cocos2d for iPhone

This is an open source 2D game engine imported from its original Python implementation. The API is organized in several easy-to-understand OOP concepts: Director, Scene, Layer and Sprite. It also sports two powerful 2D physics engine: Chipmunk and Box2d. The full feature list can be found here:

http://www.cocos2d-iphone.org/wiki/doku.php/prog_guide:index

OGRE

OGRE iPhone

OGRE is a famous open source 3D game engine, now it being ported to iPhone.

Unity iPhone

Unity is a commercial iPhone game development environment, it has got everything you’ll need for developing a 3D game. The only problem is the licensing price is too high, the combination of Unity Pro and iPhone Advanced could cost you $1499 + $1499. It’s quite a lot.

Unity feature list can be found here:

http://unity3d.com/unity/whats-new/iphone-1.5

Oolong Engine

Oolong Engine is a new open source 3D game engine, it has built-in support for Bullet Physics SDK, which is also open sourced and being supported by AMD recently.

Posted in Mac, Programming on September 1st, 2009 by Xin

After upgraded to Snow Leopard, the first thing I noticed is that my MacPorts installation stopped working. It’s due to the architecture change, since almost everything in Snow Leopard now shifts to 64-bit, old 32-bit MacPorts is no longer working.

My local web development depends on MacPorts, I use MacPorts to install Apache 2.2 and compile my own PHP 5.3 since I need some special PHP modules. When I’m going to compile PHP 5.3 under 10.6, I got this at last stage:

Undefined symbols:
"_res_9_dn_expand", referenced from:
_php_parserr in dns.o
_php_parserr in dns.o
_php_parserr in dns.o
_php_parserr in dns.o
_php_parserr in dns.o
_php_parserr in dns.o
_php_parserr in dns.o
_zif_dns_get_mx in dns.o
"_res_9_search", referenced from:
_zif_dns_check_record in dns.o
_zif_dns_get_record in dns.o
_zif_dns_get_mx in dns.o
"_res_9_init", referenced from:
_zif_dns_check_record in dns.o
_zif_dns_get_record in dns.o
_zif_dns_get_mx in dns.o
"_res_9_dn_skipname", referenced from:
_zif_dns_get_record in dns.o
_zif_dns_get_mx in dns.o
_zif_dns_get_mx in dns.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
make: *** [libs/libphp5.bundle] Error 1

After some Google I found it’s fixed if you add this line in EXTRA_LIBS in Makefile:

-lresolv

I guess it’s a bug in PHP 5.3 branch. And another thing you’ll need to care is to replace your MySQL installation with a 64-bit one. Then everything is with 64-bit super force. :)

Posted in Programming, iPhone on August 13th, 2009 by Xin

cocos2d for iPhone

I’ve been following this open source project for quite a long time, for those who don’t know what it is, it’s a very powerful framework for developing hardware accelerated 2D iPhone games. You can learn more at http://www.cocos2d-iphone.org/.

The latest release even comes with a tile map editor and a decent physics engine known as Box2D.

Posted in iPhone on November 22nd, 2008 by Xin

These days I’ve been working on an easy solution for implementing full text search on iPhone, and finally I got it working.

There is UISearchBar in UIKit, but there isn’t anything easy in iPhone SDK to help you implementing a high performance data structure for indexing and searching. After some Google search, I found that SQLite has a very promising full text search component called FTS3, however, this component exists in SQLite code tree as a plug-in, so it’s not to be found in iPhone’s built-in SQLite support.

To integrate FTS3 plug-in into your iPhone app, you need to build your own SQLite. Fortunately there is a project named The SQLite Amalgamation, it makes the whole SQLite source tree into three files: two .h headers and one .c source file. So you can create a group in your project in Xcode named SQLite, and drag-n-copy these 3 files into this group. So you’re ready to compile your own SQLite for your iPhone app.

Next step is to turn on FTS3 in sqlite3.c, you need to add this line:

#define SQLITE_ENABLE_FTS3 1

Below this line:

#define SQLITE_AMALGAMATION 1

Be aware that sqlite3.c is a very huge file weighing 340K+, it may crash your Xcode. You may want to open it in vim.

Now you can click build and play with your own SQLite 3 with FTS3. For more information on how to use FTS3, please read the official documentation, it’s quite easy:

http://www.sqlite.org/cvstrac/wiki?p=FtsOne

Posted in iPhone on October 22nd, 2008 by Xin

I just encountered this problem and finally got it working. Here are some tips if you’ve experienced the same problem:

  1. Try create a new iPhone project in Xcode, and your distribution provisioning profile will show up in the new project. Then back to the problematic project, you may get lucky.
  2. Enter iPhone Distribution in Code Signing Identity, select Code Signing Provisioning Profile and press delete. Switch to distribution configuration and build, if you got lucky, you’ll be prompted about permission or something Keychain, click Always Allow. After build, you may find distribution provisioning profile showing up.
  3. You’ll need to generate and request different certificates for Developer profile and Distribution profile.
  4. Actually you don’t need to enter the name part in Code Signing Identity, just iPhone Developer and iPhone Distribution is enough for Xcode to locate these profiles.

Since Xcode behaves strange and different from what Apple describes in program portal guide, this could be a bug and I hope it gets fixed in next version of Xcode. I believe that many people were mad about this.

Posted in iPhone on October 7th, 2008 by Xin

Every iPhone native app crashes.

Something really hard to address is, when app is running very smooth in simulator, it crashes much more often in real devices. Especially for apps reading a lot data from Internet.

I really want to find a list of tips about reducing crashes, or should I make my own? And I wish Apple could add more RAM to next generation iPhone.

Posted in iPhone on October 2nd, 2008 by Xin

I just found that Apple has got an excellent list answering most common coding questions like how to tell is code running on iPhone or iPod touch?

http://developer.apple.com/iphone/gettingstarted/docs/gettingstartedfaq.action

I still hope there will be an official place for developers to discuss iPhone coding problems, like they’re doing in Adobe Labs, with forums and wikis. Currently some developers go to discussions.apple.com, which is not the best place IMO, because most people there are regular users, not developers, and discussion categories are defined for regular users too.

Posted in iPhone on September 24th, 2008 by Xin

I made a brief page for the Cydia repository hosting my games and applications, now you can see the version number and modified time of applications in the repository:

http://apt.shinra-core.com/

Of course, this page is designed to be compatible with MobileSafari.

Posted in iPhone on September 22nd, 2008 by Xin

Trimming leading and trail whitespace is common for data parsed from XML or JSON, however, there isn’t an equivalent method like PHP’s trim() in Objective-C, but with categories it’s easy to add functions to existing classes like NSString.

NSString+trim.m implements a class method + (NSString *)trim:(NSString *)original extends NSString to do the same thing as PHP’s trim(). Download the zip, drag NSString+trim.h and NSString+trim.m to your project and use it like this:

#import "NSString+trim.h"

NSString * trimmed = [NSString trim:whatever]; // whatever is NSString from XML or anything that needs to be trimmed

Download: NSString+trim.zip

It works on both iPhone and Mac.

Posted in iPhone on September 20th, 2008 by Xin

I will try to explain several important concepts of UITableView in this post, UITableView was the most confusing component when I was making my first iPhone app, it took me some time to understand it so that I’m really happy to share what I’ve learned with you.

Basics

UITableView is a subclass of UIView, that means you can initialize it and add it to a UIView using addToSubview method just like other UIView subclasses.

Following code will create an empty UITableView and add it to a view named mainView:

UITableView * aTableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 320, 460)];
[mainView addToSubview:aTableView];

Now you’ve got an empty UITableView, but it can do nothing. For populating data and handling taps, you’ll need to set a datasource and a delegate for your UITableView. The object you’ll use for datasource and/or delegate must adopt protocol UITableViewDelegate and/or UITableViewDataSource. You don’t need to use two objects for handling the two protocols, one object is enough unless you have other reasons to use two.

Data Source

You can set an object as datasource like this:

[aTableView setDataSource:anObject];

The object acts as datasource usually needs to implement these methods:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView

This method will tell UITableView how many sections it will have. One example of sections is in Contacts app, contacts with different family names are organized into sections by initials.

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section

This method will tell UITableView what to display in section headers. In Contacts app, initials are displayed in section headers.

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

This method will tell UITableView how many cells it will have per section. If you have only one section, just simple return the total number of cells.

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

This is the most important method in datasource. After UITableView is created and has a datasource, when a cell is visible on screen, UITableView will query datasource for the cell to decide what to draw in the cell.

You have two ways to construct a cell, simple and complex.

Simple way:

This will produce a cell with a single line of text in standard font and size, as you have seen in Contacts app.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
  static NSString *theIdentifier = @"theIdentifier";

  // Try to recover a cell from the table view with the given identifier, this is for performance
  UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:theIdentifier];

  // If no cell is available, create a new one using the given identifier
  if (cell == nil) {
    cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:MyIdentifier] autorelease];
  }

  // Fill the cell
  cell.text = [NSString stringWithString:@"Hello World"];
  return cell;
}

Complex way:

If you want to have images or labels in a cell, first you’ll need to subclass UITableViewCell, then you can draw them into a cell’s contentView. If you want to have customized backgrounds like in Twinkle, you can prepare a UIView and assign it to cell’s backgroundView.

When you have images or other customized content in contentView, you’ll usually need to use different identifiers for cells, this is different from the example in simple way. Unique identifiers usually come from data retrieved from Internet. For example, if you’re populating a UITableView with contents from RSS, you may use article ID as UITableViewCell identifier.

Below is a complete example of customized UITableViewCell, it uses a subclass ArticleCell inherits from UITableViewCell, ArticleCell has two UILabel (title, author) in properties. This example also demonstrated how to use a thread to download image from Internet and assign it to a UIImageView in UITableViewCell, you’ve seen this in two official apps: YouTube and App Store.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
  Aricle * anArticle = [[articles objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];

  NSString * CellIdentifier = [anArticle articleID];
  ArticleCell * cell = (ArticleCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];

  if (cell == nil) {
    cell = [[[ArticleCell alloc] initWithFrame:CGRectMake(0,0,320,84) reuseIdentifier:CellIdentifier] autorelease];
    UIImageView * bgView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 84)];
    UIImage * bgImage;
    if ((indexPath.row % 2) == 0) {
      bgImage = [UIImage imageNamed:@"cell-even.png"];
    } else {
      bgImage = [UIImage imageNamed:@"cell-odd.png"];
    }
    [bgView setImage:bgImage];
    [bgImage release];
    [cell setBackgroundView:bgView];
    [bgView release];
    cell.title.text = [anArticle title];
    cell.author.text = [anArticle author];
    [cell setRating:[anArticle ratingAverage]];
    if (anArticle.imageSmall) {
      [NSThread detachNewThreadSelector:@selector(downloadCover:) toTarget:cell withObject:[anArticle imageSmall]];
    }
    cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
  }
  return cell;
}

As of writing, customized cells do have some performance issues, scroll a list of customized cells is not smooth enough. Hope Apple would fix it in future.

Notice: cellForRowAtIndexPath method only executes when a cell is visible. And it can be executed multiple times when you scroll, so don’t do anything crazy in cellForRowAtIndexPath or it may crash the app easily.

Conclusion:

  • UITableView needs a datasource to guide it to draw cells.
  • Simple cells are filled by set text property.
  • Subclass UITableViewCell if you’re going to do complex drawing.
  • contentView and backgroundView are for complex drawing.
  • Don’t do expensive things in cellForRowAtIndexPath:.

Delegate

You can set an object as delegate like this:

[aTableView setDelegate:anObject];

So, now you know how to draw cells, but how to detect taps? This method in delegate object is for detecting taps:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

And there is another important method implemented by delegate:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

This method will tell UITableView how tall a cell will be. If you go the simple way, you don’t need implement heightForRowAtIndexPath in delegate, a default height will be set automatically.

If each cell holds different text and you want to have variable height, please refer to a post I wrote before:

How to make UITableViewCell have variable height

Now we’ve covered two basic important things in UITableView: datasource and delegate. With knowledge you’ve learned from this post, it’s sufficient for building read only iPhone data clients, and there are more topics like dynamic add/remove and editing, I’ll cover these topics later. If you find any bugs, typos or memory leaks in my code, welcome to tell me in comments, I’ll be very glad to know.