• Update your GitHub fork repo from its original repo

    //the active directory in the prompt to the newly cloned "ProjectName" directory
    $ cd ProjectName
    //Assigns the original repo to a remote called "upstream"
    $ git remote add upstream git:/ /
    //Fetches any new changes from the original repo
    $ git fetch upstream
    //Merges any changes fetched into your working files
    $ git merge upstream/master
    Author:admin | Categories:Dev | Tags:
  • Save any UIView to PNG files

    //Get the view from a specific window
    UIView *view = [[[[[UIApplication sharedApplication] windows] objectAtIndex:1] subviews] lastObject];
    //Will be used for naming png files
    NSInteger index = 0;
    //Check each subView
    for (UIView *subView in [view subviews]) {
    	//Find the UIView you need
    	if ([subView isKindOfClass:NSClassFromString(@"UIImageView")] || [subView isKindOfClass:NSClassFromString(@"UIThreePartButton")]) {
    		//Very important to support retina screen
    		if(UIGraphicsBeginImageContextWithOptions != NULL)
    			UIGraphicsBeginImageContextWithOptions(subView.frame.size, NO, 0.0);
    		//Get the image
    		[subView.layer renderInContext:UIGraphicsGetCurrentContext()];
    		UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    		//Save the image
    		NSString *path=[NSHomeDirectory() stringByAppendingFormat:@"/%d.png",index];
    		if ([UIImagePNGRepresentation(image) writeToFile:path atomically:YES]) {
    			index += 1;
    		else {
    Author:admin | Categories:Dev | Tags:
  • Key-Value Observing, Key-Value Coding, Key-Value Bindings


    1, KVO (Key-Value Observing Programming Guide)
    KVO is a mechanism to notify observers automatically when the observed object’s value is changed.
    Register an observation

    - (void)addObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context


    [observedObject addObserver:observer forKeyPath:@"keyPath"];//Register the observation here.

    Remove a registered observation

    - (void)removeObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath


    [observedObject removeObserver:observer forKeyPath:@"keyPath"];//Remember to remove the registration to avoid crashing.

    Receiving value changed messages

    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
    //You will get messages here.

    2, KVC (Key-Value Coding Programming Guide)
    KVC is a mechanism allows application to access an object’s properties by name (or key).
    Before KVC:

    - (id)tableView:(NSTableView *)tableview
        ChildObject *child = [childrenArray objectAtIndex:row];
        if ( [[column identifier] isEqualToString:@"name"] ) {
            return [child name];
        if ( [[column identifier] isEqualToString:@"age"] ) {
            return [child age];
        if ( [[column identifier] isEqualToString:@"favoriteColor"] ) {
            // etc...
        // etc...

    After KVC:

    - (id)tableView:(NSTableView *)tableview
        ChildObject *child = [childrenArray objectAtIndex:row];
        return [child valueForKey:[column identifier]];

    Be careful, if the application can’t find the key, it will try to call valueForUndefinedKey:, and if the object doesn’t override this method, it will raise an exception called NSUndefinedKeyException.

    3, KVB (Cocoa Bindings Programming)
    “Cocoa bindings supports multiple ways of viewing your data, and automatically synchronizes views when models change.”

    - (void)bind:(NSString *)binding toObject:(id)observableController withKeyPath:(NSString *)keyPath options:(NSDictionary *)options


    [self.view bind:@"frame" toObject:anotherView withKeyPath:@"frame" options:nil];

    After that, self.view will always have the same frame as anotherView, no need to use NSNotification or any other complicated mechanism.

    Author:admin | Categories:Dev | Tags:
  • Stop editing NSTextField


    I only post some results here. Reference from

    Failed solutions:

    [[[self view] window] endEditingFor:nil];

    Pressing return or pressing the tab key will not end the editing session

    [[[self view] window] makeFirstResponder:[self view]];

    Pressing return will allow the editing session to end, but pressing the tab key will not

    NSTextView *fieldEditor = [[aNotification userInfo] objectForKey:@"NSFieldEditor"];
    NSView *v = fieldEditor;
    while ( v && ( [v superview] != [aNotification object] ) )
    v = [v superview];
    [v removeFromSuperview];

    Pressing return or pressing the tab key will not end the editing session

    The editing session was started with:

    [textField selectText:nil];
    NSTextView    *currentEditor    = (NSTextView*)[textField currentEditor];
    NSPoint        windowLocation    = [theEvent locationInWindow];
    NSPoint        screenLocation    = [[self window] convertBaseToScreen:windowLocation];
    NSUInteger    characterIndex    = [currentEditor characterIndexForPoint:screenLocation];
    [currentEditor setSelectedRange:NSMakeRange( characterIndex + 1, 0 )];

    For me, I use [[[self view] window] makeFirstResponder:[self view]] to stop the text field by enter key.

    And use NSWindow’s setAutorecalculatesKeyViewLoop:YES to stop the text field by tab key.

    So both of them are solved.

    Author:admin | Categories:Dev | Tags:
  • 研究了一下CATiledLayer的levelsOfDetail和levelsOfDetailBias的含义


    levelsOfDetail是指,从UIScrollView的1倍zoomScale开始,能够支持细节刷新的缩小级数。每一级是上一级的1/2,所 以假设levelsOfDetail = n,levelsOfDetailBias不指定的话,CATiledLayer将会在UIScrollView的zoomScale为以下数字时重新 drawLayer
    2^-1 -> 2^-2 -> … -> 2^-n
    1/2, 1/4, 1/8, 1/16, … , 1/2^n


    levelsOfDetailBias = m表示,将原来的1/2,移到2^m倍的位置。
    假设levelsOfDetail = n,levelsOfDetailBias = m的话,会有如下队列:
    2^m * 2^-1 -> 2^m * 2^-2 -> … -> 2^m * 2^-n
    2^(m – 1) -> 2^(m – 2) -> 2^(m – 3) ->… -> 2^(m – n)

    举例,levelsOfDetail = 3,levelsOfDetailBias = 3,则你的UIScrollView将会在以下zoomScale时drawLayer
    2^(3 – 1) -> 2^(3 – 2) -> 2^(3 – 3)
    即4 -> 2 -> 1

    特例是,levelsOfDetailBias > levelsOfDetail时,则每相差2倍就会drawLayer一下。



    Author:admin | Categories:Dev | Tags:
  • A simple tutorial of UISearchDisplayController (iOS 3-7)


    After several years, thanks to StoryBoard and iOS 7, it becomes super easy to use Search Display Controller now.
    I attached a new sample project here, hope it could help everyone who needs it.


    UISearchDisplayController iOS 7

    I find out that, the API for UISearchDisplayController in SDK 3.0b is different from 3.0. And there’s no sample code for UISearchDisplayController anywhere else until now. (Yes, there is one in Apple’s sample code web page, but it uses Interface Builder to realize it. And there is one from the source code of “three20”, but it’s based on SDK 3.0b. )

    So I wrote this sample based on “Table Search” sample code.It realizes UISearchDisplayController programmatically without Interface Builder. It supports landscape screen and search scopes, and integrate one UITabBarController with two UITableViewControllers.

    Here is the tutorial.


    1. Declare an instance of UISearchDisplayController and set as property.
    2. Prepare two arrays to hold original data and filtered data.


    1. Set up viewDidLoadmethod
      1. Create an UISearchBar.
      2. Initialize the UISearchDisplayController based on the UISearchBar:
        [[UISearchDisplayController alloc] initWithSearchBar:mySearchBar contentsController:self];
      3. Set the UISearchDisplayController instance:
        [self setSearchDisplayController:searchDisplayController];
        [searchDisplayController setDelegate:self];
        [searchDisplayController setSearchResultsDataSource:self];
    2. Set up UISearchDisplayController delegate methods:
        - (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
        - (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption
        - (void)searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller

        Be careful, we need to set the delegate for self.searchDisplayController.searchResultsTableView each time we begin to search. Because the instance of searchResultsTableView is allocated and released automatically.

    3. Set up UITableView data source and delegate methods, we distinguish filtered or not filtered table by
        if (tableView == self.searchDisplayController.searchResultsTableView)
    4. Remember to return YES in shouldAutorotateToInterfaceOrientation to support landscape screen.

    Some details need to be cared:

    1. self.searchDisplayController.searchResultsTableView is created and release automatically, so its delegate should be setted each time it’s created.
    2. Every time we turn to a landscape UITableViewController, the UISearchBar in the tableHeaderView has only a width of 320 even we have already setted sizeToFit. It’s may be caused by UITabBarController, I don’t know. So I set the frame of tableHeaderView based on the screen orientation manually in the viewDidLoad method.

    Sample Code(.zip)
    Or get the project from GitHub : CBSearchDisplayControllerSample

    Author:admin | Categories:Dev | Tags: