Tuesday, December 29, 2009

iPhone dev Stupidity 116: How to find out what mach_msg_trap wait

from stackoverflow:


"Turn out my app is not actually spending 65% of it's time in the mach_msg_trap function. It was a configuration error in Instruments on my part.

The Sampler tool defaults to All Sample Counts, this will measure all threads regardless of their state.

Instead switch to Running Sample Times that will reflect the current actual workload."

Shark has similar options:


Wednesday, December 16, 2009

iPhone dev Stupidity 115: UITableView delete section

When items of a section are deleted, the section is deleted automatically - no need to write section delete code like:


[self.tableView deleteSections: [NSIndexSet indexSetWithIndex: section] withRowAnimation: UITableViewRowAnimationLeft];


Tuesday, December 15, 2009

iPhone dev Stupidity 114: Muliti column order

1. to order by two columns

From here

SELECT * FROM Individual
ORDER BY FirstName, LastName

2. We want to sort files by name - when two files have the same name we sort them by the date time:

NSString * sql = [NSString stringWithFormat: @"SELECT arts.*, tags.name FROM arts, tags WHERE category_id = %d and arts.tag_1 = tags.tag_id and ((tags.name = '%@' and arts.date_touched > '%@') or tags.name > '%@') ORDER BY tags.name LIMIT 1", cur_art.category_id_, cur_name, cur_art.date_touched_, cur_name];



iPhone dev Stupidity 113: Write protection of Resource

In the device, the resource/library folder is read-only. In the simulator, there's no protection for the folder.

Sunday, December 13, 2009

iPhone dev Stupidity 112: SQLite, Last inserted row id

From Widipedia:


Database designers that use a surrogate key as the primary key for every table will run into the occasional scenario where they need to automatically retrieve the database generated primary key from a SQL INSERT statement for use in another SQL statements. Most systems do not allow SQL INSERT statements to return row data. Therefore, it becomes necessary to implement a workaround in such scenarios.

Using a database-specific stored procedure that generates the surrogate key, performs the INSERT operation, and finally returns the generated key. For example, in Microsoft SQL Server, the key is retrieved via the SCOPE_IDENTITY() special function, while in SQLite the function is named last_insert_rowid().

Wednesday, December 09, 2009

iPhone dev Stupidty 111: SQL table order

From here:

"In a relational database... rows have no order! This cannot be stressed enough.  I don't care how you order the rows, SQL Server is under no obligation to return the data in that order.  And frankly, even if you order the data using the clustered techniques mentioned, this only guarantees it when you rebuild it.  After that, SQL Server may split pages, and then you technically don't have a flat structure anymore. "

Monday, November 30, 2009

iPhone dev Stupidity 110: Fine Grained Observing for Text Field

1. Using Key-value Observing to get update for a UITextField editing like this:

[nameField_ addObserver: self forKeyPath: @"text" options: NSKeyValueObservingOptionPrior context: nil];

You will only get the observing method (- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context) called when the edit is done - the text field lost focus.

2. To observe each character input, we need NSNotificationCenter (from apple forum):

[[NSNotificationCenter defaultCenter] addObserver: self  selector: @selector(textFieldTextDidChange:) name: @"UITextFieldTextDidChangeNotification"  object: nil];


where to find out the @"UITextFieldDidChangeNotification" string? It's in the UITextField.h:

UIKIT_EXTERN NSString *const UITextFieldTextDidBeginEditingNotification;


UIKIT_EXTERN NSString *const UITextFieldTextDidEndEditingNotification;


UIKIT_EXTERN NSString *const UITextFieldTextDidChangeNotification;


and sure apple had started iPhone SDK in 2005:


//  UITextField.h


//  UIKit


//


//  Copyright 2005-2009 Apple Inc. All rights reserved.


iPhone dev Stupidity 109: NSAttributedString, NSFormatter for UIT

1. from stackoverflow : NSAttributedString is not on iPhone.

2. from iPhone Dev SDK : You can't plug an NSFormatter onto a UITextField - thus you can't provide a partial string when input in text field:
is not available on iPhone. 





Sunday, November 29, 2009

iPhone dev Stupidity 108: Scrolled UITextField

If a text field get focused during scrolling, the scrolling will stop.

So better to focus it when the scroll animation is done: 
 * for program triggered scroll: - (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
 * for finger dragged scroll: - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView 

Saturday, November 28, 2009

iPhone dev Stupidity 107: LuaFileSystem

Some dependency:





To use LuaFileSystem, we need LuaRocks to install the lfs package.

LuaRocks relies on wget to parse the rock specs (not available on Mac OS X).

lfs will build into a lfs.so. If necessary, you need to copy it to 'require' search paths of lua and add the access rights to your user/usergroup.


iPhone dev Stupidity 106: Protocal for Category, Override


iPhone dev Stupidity 105: Confuse alpha = 0.0 with remove

To avoid flicker when removing a view, you might use an UIView animation to set a alpha = 0.0 and remove the view in the animation stop callback.

Make sure to assert(view.retainCount == 1) before removing. For if you have reference count error (retainCount > 1) and the view will not get removed - but you can't see it since the alpha has set to 0.0.

Of course, you can set the alpa = 0.5 in debug mode to "see" if it's removed finally.

Wednesday, November 25, 2009

iPhone dev Stupidity 104: Update Navigation Bar

from apple help doc:

When the user changes the top-level view controller, whether by pushing or popping a view controller or changing the contents of the navigation stack directly, the navigation controller updates the navigation bar accordingly. Specifically, the navigation controller updates the bar button items displayed in each of the three navigation bar positions: left, middle, and right. Bar button items are instances of the UIBarButtonItem class. You can create items with custom content or create standard system items depending on your needs. For more information about how to create bar button items, seeUIBarButtonItem Class Reference.

Check the doc for detailed rules for the left, middle and right view updating.


A UINavigationBar object uses a stack to manage navigation items (instances of UINavigationItem) that represent a state of the navigation bar. You change the navigation bar by pushing navigation items using the pushNavigationItem:animated: method or popping navigation items using thepopNavigationItemAnimated: method. Methods with an animated: argument allow you to animate the changes to the display.


and some error:

2009-11-26 07:45:11.742 Flip[404:20b] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Cannot call pushNavigationItem:animated: directly on a UINavigationBar managed by a controller.'


Monday, November 23, 2009

iPhone dev Stupidity 102: Do you have to release IBOutlet?

from stackoverflow:

Your IBOutlets are probably @properties. If they are, and you have retain as an attribute, then you do need to release in -dealloc

A best practice: 

self.myoutlet = nil; in dealloc

This works for both the retained and assigned IBOutlet. The retained will release and the assigned will do nothing.


iPhone dev Stupidity 103: NSZombie and Memory leaks

from here:

NSZombieEnabled creates leaks ON PURPOSE so you can track down calls to objects that are released prematurely. When you run with NSZombieEnabled, objects are never dealloced. When it's time to dealloc the object, NSZombieEnabled tells the runtime to turn the object into an instance of NSZombie. Any attempt to message an NSZombie will result in a runtime exception. Always remember to remove the NSZombieEnabled flag before sending an app into production! Due to the fact that dealloc is overridden, your app will never free any memory - it will just grow and grow. It's for testing and debugging only.


iPhone dev Stupidity 101: How to draw text vertically?

1. Drawing NSString in unusual direction : limited to ascii string and have effect like this:

    use CGContextShowText(ctxt, tbuf.c_str(), tbuf.length()); and CGAffineTransform 

2. CGFontGetGlyphsForUnichars

   to draw unichar we need this function to get glyph out of a unichar. Then core graphic has a set of function for showing glyph like this one:


void CGContextShowGlyphsAtPoint (
CGContextRef c,
CGFloat x,
CGFloat y,
const
CGGlyph glyphs[],
size_t count
);


but CGFontGetGlyphsForUnichars is a private API for iPhone. So we got:

3. A replacement for CGFontGetGlyphsForUnichars

on github

-----

4. bonus: draw gradient filled UILabel.

also uses: extern void CGFontGetGlyphsForUnichars(CGFontRef, const UniChar[], const CGGlyph[], size_t);


iPhone dev Stupidity 100: viewDidUnload

From apple doc:

Called when the controller’s view is released from memory.

- (void)viewDidUnload

Discussion

This method is called as a counterpart to the viewDidLoad method. It is called during low-memory conditions when the view controller needs to release its view and any objects associated with that view to free up memory.


iPhone dev Stupidity 99: Start/End of a scrolling (with drag)

Since UITableView is a subclass of UIScrollView, a scroll begins from:

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView


ends at:

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView


Wednesday, November 11, 2009

iPhone dev Stupidity 98: Bar place holder for view

Set the top and bottom bar for the view, if it meat to be in a navigation controller with toolbar at the bottom:



Thus you can get the right view size without calculating (by sub the bar height - 44).

Monday, November 02, 2009

iPhone dev Stupidity 97: SVN Locked

try: svn cleanup project folder and sub folders

some times you need to feed svn with some fake files which it fails to find.

iPhone dev Stupidity 96: XCode command line

man xcodebuild

iPhone dev Stupidity 95: Non freed memory

If the Object Alloc looks like this, there must be some memory you forget to free but hold a reference.


iPhone dev Stupidity 94: Delete content of scrollview when scroll

If you delete the content view of a UIScrollView in:

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView


later there's still some animation work need to be done by cocoa, and the error will happen (note that ScrollerHeartbeatCallback):



A Hack to solve - delayed remove:

// !!! a hack


// directly remove container from superview, later there's some heart beat callback for smoothing the scrolling


// which will still trying to use the old scroller, and when fails to find, there'll be a BAD ACCESS failure


// here we just delay the remove.


container.alpha = 0.0;


[container performSelector: @selector(removeFromSuperview) withObject: nil afterDelay: 0.1];


iPhone dev Stupidity 93: Nested UIScrollView

UIScrollView can be nested to form kind of 2D scroller - you can scroll the row by row and each row itself holds a horizontal scroll view.

In the scroll delegate you need to respond differently for the inner and outer scroller.

Wednesday, October 28, 2009

iPhone dev Stupidity 92: get content view of UIScrollView

Either by index into subviews:

UIView * content = [[scrollView subviews] objectAtIndex:0];

or by tagging:

UIView * content = [scrollView viewWithTag: CONTENT_VIEW_TAG];

it seems that tag 0 is the scrollview itself.

iPhone dev Stupidity 91: Image Refelection

To create an UIImage refelection, check the sample code "The Elements" from apple.

method concerned:

- (UIImage *)reflectedImageRepresentationWithHeight:(NSUInteger)height;

CGImageRef AEViewCreateGradientImage (int pixelsWide, int pixelsHigh);



iPhone dev Stupidity 90: SMS Balloon

Using [UIImage stretchableImageWithLeftCapWidth:topCapHeight:] to create the SMS balloon:


UIImage * img = [UIImage imageNamed: @"balloon.png"];


g_balloon_ = [[img stretchableImageWithLeftCapWidth: img.size.width/2 topCapHeight: img.size.height/2] retain];


assert(g_balloon_.leftCapWidth == (int)(img.size.width/2));


and the image looks like:



Tuesday, October 27, 2009

iPhone dev Stupidity 89: SMS send

1. send to number:

openURL: @"sms:number"

2. open a new sms for editing:

openURL: @"sms:?"



Monday, October 26, 2009

iPhone dev Stupidity 88: SQL reverse ordering

Using DESC:

SELECT #fieldlist# FROM EmailData 
ORDER BY DateSent DESC

iPhone dev Stupidity 87: Timezone & Date formatter

1. Use timezone in SQLite

SELECT datetime('now', 'timezone')

2. How to set the date format (from cocoachina)


With code samples and locale.


Sunday, October 25, 2009

iPhone dev Stupidity 86: Upgrade - how to import old data

1. How the upgrade works

"Upgrades replace the app bundle, but anything else in your sandbox (like the Documents folder, caches, preferences, etc) are preserved in place."


"I think the short answer is yes, the only sensible option are webservices. There is no iTunes sync plugin that you can use so your options are all network based.

Other than webservices, you might also like to consider a client-side program that your iPhone app finds and connects to using Bonjour. The obvious disadvantage here is that you have to write client apps (preferably two, one for Windows the other for Mac) and educate your users on how to download and install them. Also you're forcing your users to sync using WiFi."


"I think testing with AdHoc versions that is dragged dropped in iTunes is a similar upgrade situation.

That's how I tested upgrading our Chess game, so it keeps old and current games on the device.

As for the files/DB I suggest they should contain some version number."


Using IPC (openURL with Base64 encoding) to send data from Lite to the paid app.

5. Some details on iPhone IPC





Saturday, October 24, 2009

iPhone dev Stupidity 85: change animation style of UIViewControll

From here:


IViewController * controller = [[[MyViewController alloc] init] autorelease];
UIViewAnimationTransition trans = UIViewAnimationTransitionCurlUp;
[UIView beginAnimations: nil context: nil];
[UIView setAnimationTransition: trans forView: [self window] cache: YES];
[navController presentModalViewController: controller animated: NO];
[UIView commitAnimations];

iPhone dev Stupidity 84: Use symbolic break point to detect chang

Though the implementation of UIKit is not open source, you can insert a break point at any function entry.

Example:

To detect where the navigation bar style changes, you can insert a break point:

10  breakpoint     keep y   0x309323fd <-[UINavigationBar setBarStyle:]+6>


via gdb:

b setBarStyle:

then choose from the list for UINavigationBar.

Wednesday, October 21, 2009

iPhone dev Stupidity 83: you can't hijack the "back" button

From here and apple doc on backBarButtonItem: 

When this item is the back item of the navigation bar—when it is the next item below the top item—it may be represented as a back button on the navigation bar. Use this property to specify the back button. The target and action of the back bar button item you set should be nil. The default value is a bar button item displaying the navigation item’s title.



iPhone dev Stupidity 82: change the title of "back" button in nav

From stackoverflow: you gonna change it in parent view controller - the one just under the stack.

// set the category


// .. get parent


NSArray * viewControllerArray = [self.navigationController viewControllers];


int parentViewControllerIndex = [viewControllerArray count] - 2;


UIViewController * parent_vc = [viewControllerArray objectAtIndex: parentViewControllerIndex];



// .. if the category changed


if(![parent_vc.navigationItem.backBarButtonItem.title isEqualToString: cat_name]){


 // update the back button title


 UIBarButtonItem *newBackButton = [[UIBarButtonItem alloc] initWithTitle: cat_name style: UIBarButtonItemStyleBordered target: nil action: nil];


 parent_vc.navigationItem.backBarButtonItem = newBackButton;


 [newBackButton release];

}


iPhone dev Stupidity 81: SQLite3 Cursor?

DECLARE CURSOR c1
FOR
SELECT * FROM arts

will cause an error.

Seems not supported yet - that's why there's PL\SQL


SQLite3 doc on Scrolling Cursor:
* You can use sqlite3_step to simulate a forward cursor


Rule Number 1: Do not leave queries open waiting for the user input. Run a query to fill up the screen with as much information as it will hold then reset() or finalize() the query statment. Get in, grab your data, then get out. Later on, when the user decides to scroll up or down (which will usually be eons of time later from the point of view of your CPU), run another query to refresh the screen with new data.

Rule Number 2: Do not try to implement a scrolling window using LIMIT and OFFSET. Doing so will become sluggish as the user scrolls down toward the bottom of the list.

Tuesday, October 20, 2009

iPhone dev Stupidity 80: SQLite3 counting rows

From here:

SQLite does not keep count of rows in a table. So when you execute
SELECT COUNT(*) FROM table;
what SQLite does is step through table row by row and count them.
Only way to get the total number of rows in a table faster is to keep
track of it yourself. This can easily be done using insert/delete
triggers that will increment/decrement row count in a separate table.

If you just cares the row number, try: SELECT COUNT(0) FROM TABLE

it's more efficient.


and in code, you can get the count directly:

        NSString * sql = [NSString stringWithFormat: @"SELECT count(0) from %@ WHERE %@ = %d", table, colName, val];


sqlite3_stmt *compiledStatement;


if(sqlite3_prepare_v2(database_, [sql UTF8String], -1, &compiledStatement, NULL) == SQLITE_OK) {


int count = 0;


if(sqlite3_step(compiledStatement) == SQLITE_ROW){


count = sqlite3_column_int(compiledStatement, 0);


}



sqlite3_finalize(compiledStatement);



return count;


}


Wednesday, October 14, 2009

Hello Clojure

Tuesday, October 13, 2009

iPhone dev Stupidity 79: How to track double free

The starting point is from stackoverflow.


It doesn't work for me - when turning the zombie object on, there'll be an exception thrown (instead of print an error log in the console).

For me, the solution are:
1. Device | debug - to print the double freed address
2. Organizer - to view the console message from debug app in iPhone
3. Instrument - Object Allocation

In the organizer, you can find out which 0x######## is double freed. Then you can find that address in the Instrument window, and then the call stack.

Sunday, October 11, 2009

iPhone dev Stupidity 78: Learned from iPhone developer Meeting

iPhone Talk 1

-----------

1. Sample code for App Store style table

2. - (UIImage *)stretchableImageWithLeftCapWidth:(NSInteger)leftCapWidth topCapHeight:(NSInteger)topCapHeight

3. User generated content must rated as 17+

4. error 101 usually means low memory warning

5. XCode 3.2 -> Settings -> General -> Accessiblity Inspetor: for UI debug

7. Social networking/Forum need to provide Apple a functional account for review

8. tableView:titleForDeleteConfirmationButtonForRowAtIndexPath:
Changes the default title of the delete-confirmation button.

Make sure the title is not too long to cover the table cell content - If it's SDK's bug, do not count on it.

9. If using system icon lead to user confusion, do NOT use it

READ the HIG word by word.

10. Serch Bar:
1) tableHeaderView as a searchBar
2) delegate

11. Clear Release Note:
- which screen, what changes
- if not sure, release as "bug fix"

12. Q/A:
1) localization: use less IB. Take care of label length.
2) Cocoa cookbook: non offical API - on your own risk
3) Ad hoc deploy: iTunes will change .app -> .ipa to send. (Packing may change the app code sign)
4) Use UIDevice to get the SDK version number.

Talk 2 : iPhone Data Managment

------------------

1. SQLite
1) Sample code: SQLiteBooks
2) copy sqlite.db from resource to writable folder (Document) - for safty.
3) Shrink the db file size: sqlite > vacuum
4) Document folder is resevered when upgrade
5) >50MB file, copy failed
. - (BOOL)createSymbolicLinkAtPath:(NSString *)path pathContent:(NSString *)otherPath
. seperate db fields - leave big & read only one in resouce, only copy the small & editable fields to document folder.
6) Design schema with consideration for upgrade
. keep version in db
. sql script to choose different db via version.

2. XML
. RSS
. API via http

3. Ordered as: idea, marketing, tech.

Talk 3: SQLite & Core Data

----------------------
1. Browser: sqlitebrowser.sourceforge.net

2. Multi-platform use SQLite

3. Core Data on logic level; and optimized for caching, lazy-loading and memory management; KVO/KVC; undo/redo.


Talk 4: Three 20 Kit

----------------

Controls:

1. New message/mail
2. Styled fonts
3. Activity labels/progress bar
- screen lock styled label - glowing effect
4. Launcher
--

Concept:
1. Style: like CSS
2. using 'next' to combine different styles
3. URL: can point to res, view controller
- "bundle://..."
- "documents://..."

Talk 5: Core Animation

-------------------

Talk 6: Multi Touch

----------------
1. Use 2 fingers touch to drag canvas
2. Multi touch levels: 1 -> 2 -> 3 increase
3. app:
. SmartChoice
. OthelloCube

Talk 7: iFighter

------------
1. Lite before non-free version: get feedback for final version. iFighter used 1.5 month.
2. Promc code for promotion
3. Tips:
- old topic but be the best
- monkey -> hardcore: adapt to users of different levels
- great service to keep users
- only make the great product -> from product to brand
- share the success

4. Q/A:
. 3 peoples to make iFighter
. personal product to company product - refund if users have difficult to transfer
. why don't ship paied version when lite version is asending
. self made game engine
. made in home
. peer review, defining the great
. the product finishs where you stop working it
. price -> confidence in the product: check the sales chart.
. ccgamebox 2d engine
.

iPhone dev Stupidty 77: setAnimationDidStopSelector:

From iPhone App Programming Guide:

iPhone dev Stupidity 76: setNeedsDisplay is not free

If you use setNeedsDisplay's side effects instead of your proper refreshing logic, it might drag your app slow when refreshing big views.

iPhone dev Stupidity 75: melt at corner


Use CGGradient in linear mode, once for each side. But for this to work, I think I'd need to set up a trapezoidal clipping area for each side first, so that the gradients would be mitered at the corners.

Using NSBezierPath to create the trapezoidal regions would be fairly straightforward, and you would only have to perform four drawing operations.

Here's the basic code for creating the left side trapezoidal region:
NSRect outer = [self bounds];
NSPoint outerPoint[4];
outerPoint
[0] = NSMakePoint(0, 0);
outerPoint
[1] = NSMakePoint(0, outer.size.height);
outerPoint
[2] = NSMakePoint(outer.size.width, outer.size.height);
outerPoint
[3] = NSMakePoint(outer.size.width, 0);

NSRect inner = NSInsetRect([self bounds], borderSize, borderSize);
NSPoint innerPoint[4];
innerPoint
[0] = inner.origin;
innerPoint
[1] = NSMakePoint(inner.origin.x,
                            inner
.origin.y + inner.size.height);
innerPoint
[2] = NSMakePoint(inner.origin.x + inner.size.width,
                            inner
.origin.y + inner.size.height);
innerPoint
[3] = NSMakePoint(inner.origin.x + inner.size.width,
                            inner
.origin.y);

NSBezierPath leftSidePath = [[NSBezierPath bezierPath] retain];
[leftSidePath moveToPoint:outerPoint[0]];
[leftSidePath lineToPoint:outerPoint[1]];
[leftSidePath lineToPoint:innerPoint[1]];
[leftSidePath lineToPoint:innerPoint[0]];
[leftSidePath lineToPoint:outerPoint[0]];

// ... etc.

[leftSidePath release];