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];

iPhone dev Stupidity 74: UIScrollView beyond bounds gradient?

From here:


// Setup top most gradient parameters and clipping mask.


CGPoint startPoint = CGPointMake(rect.origin.x, rect.origin.y);


CGPoint endPoint = CGPointMake(0.0, shadowHeight_);


CGRect clipRect = CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, shadowHeight_);



// Draw top most gradient within clipped rect. Look at Quartz Demo for details.


CGContextSaveGState(context);


CGContextClipToRect(context, clipRect);


CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0);


CGContextRestoreGState(context);



and to setup the gradient:

CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();



        CGFloat colors[] = {


            //0.0, 0.0, 0.0, 0.5,


            //1.0, 1.0, 1.0, 0.0


65.0/256, 81.0/256, 81.0/256, 1.0,


0.0, 0.0, 0.0, 1.0,


        };


        


        gradient = CGGradientCreateWithColorComponents(rgb, colors, NULL, 2);


        


        CGColorSpaceRelease(rgb);


iPhone dev Stupidity 73: memory alignment.

From here:

"All allocations that use the OS X supplied malloc are aligned to 16 bytes. You've clearly tried to free something that isn't so it's invalid."

iPhone dev Stupidity 72: Get the RGB of a Pixel

Using Gimp:


Using Mac OSX build in DigitalColor Meter:



iPhone dev Stupidity 71: Loading ... 17% - How to Make progress b

1. iPhone threading and screen refreshs

    Use kind of server and inter PROCESS communicating. Quite complex.

    Use notification center as a mid man - but NOT working.
    Because a notification is despatched synchronously - UI still get no chance to update.

My solution (based on 2):
    Sending notification in a separate thread instead of notifying directly:

- (void) sendProgressNotification: (NSNumber *) percentDeltaValue{


[[NSNotificationCenter defaultCenter] postNotificationName:@"StepPercent" object: percentDeltaValue];


}




// post the progress info


- (void) stepPercentage: (int) percentDelta{


[NSThread detachNewThreadSelector: @selector(sendProgressNotification:) toTarget: self withObject: [NSNumber numberWithInt: percentDelta]];


}


iPhone dev Stupidity 70: Profile to make proper progress percenta

2009-08-13 17:22:52.063 Flip[368:207 ] splash awake took 130.620000 ms!


2009-08-13 17:22:53.152 Flip[368:3f03] create scrollview took 11.913333 ms!


2009-08-13 17:22:53.164 Flip[368:3f03] loading ... 5


2009-08-13 17:22:54.412 Flip[368:3f03] create matrix took 1223.421500 ms!


2009-08-13 17:22:54.427 Flip[368:3f03] loading ... 15


2009-08-13 17:22:54.633 Flip[368:3f03] add texels took 173.522666 ms!


2009-08-13 17:22:54.646 Flip[368:3f03] loading ... 15


2009-08-13 17:22:54.662 Flip[368:3f03] create flipview took 1478.210500 ms!


2009-08-13 17:22:55.010 Flip[368:3f03] create background view took 335.918166 ms!


iPhone dev Stupidity 69: DEBUG flag

If you want to tell gcc use the DEBUG macro, add it in the target's get info panel:


iPhone dev Stupidity 68: Handcraft Profiler

Learned from here:


#include <mach/mach_time.h>




#define START_PROFILE(name)\


{\


const char * msg = name;\


mach_timebase_info_data_t info;\


mach_timebase_info(&info);\


uint64_t start = mach_absolute_time();




#define END_PROFILE\


uint64_t duration = mach_absolute_time() - start;\


duration *= info.numer;\


duration /= info.denom;\


NSLog(@"%s took %lld nanoseconds!", msg, duration);\


}



To use:

START_PROFILE("dude");
// some code here
// ...
END_PROFILE;

iPhone dev Stupidity 67: Symbol break point

(gdb) b resignFirstResponder


[0] cancel


[1] all




Non-debugging symbols:


[2]    -[UIFieldEditor resignFirstResponder]


[3]    -[UIPreferencesTextTableCell resignFirstResponder]


[4]    -[UIResponder resignFirstResponder]


[5]    -[UISearchBar(UISearchBarStatic) resignFirstResponder]


[6]    -[UITextContentView resignFirstResponder]


[7]    -[UITextField resignFirstResponder]


[8]    -[UITextView resignFirstResponder]


[9]    -[UIWebDocumentView resignFirstResponder]


[10]    -[WAKResponder resignFirstResponder]


[11]    -[WebHTMLView resignFirstResponder]


> 7


Breakpoint 9 at 0x30962ba0


(gdb) i b


Num Type           Disp Enb Address    What


1   breakpoint     keep y   0x0000a037 in -[Texel dealloc] at /Users/Carrie/MyProjects/Sandbox/Flip/Classes/Texel.m:108


2   breakpoint     keep y   <PENDING>  "TestUtility.m:18


3   breakpoint     keep y   0x0002320b in -[TemplateDB dealloc] at /Users/Carrie/MyProjects/Sandbox/Flip/Classes/TemplateDB.m:66


4   breakpoint     keep y   0x0000acc3 in -[Texel singleTapped] at /Users/Carrie/MyProjects/Sandbox/Flip/Classes/Texel.m:257


5   breakpoint     keep y   0x0000ac53 in -[Texel killEditor] at /Users/Carrie/MyProjects/Sandbox/Flip/Classes/Texel.m:249


6   breakpoint     keep y   0x00008548 in -[GlassView changed:With:] at /Users/Carrie/MyProjects/Sandbox/Flip/Classes/GlassView.m:300


breakpoint already hit 1 time


7   breakpoint     keep y   0x9360637c <__assert_rtn+6>


8   breakpoint     keep y   0x9360637c <__assert_rtn+6>


9   breakpoint     keep y   0x30962ba0 <-[UITextField resignFirstResponder]+6>