2014年8月21日星期四

Waiting until asynchronous blocks are executed 水為什麼不走直路

在寫程式時有很多的 completion block, 都是 asynchronous, 一開始的解法是想透過 dispatch_group_t 的 wait 去等, 後來一直試不出來, 經神人Lyle Wang 的指點後, 就是多傳一個參數進 completion block 裡, 當是最後一個 node 進來, 並且 completion 就去執行畫 UI 的工作, 執行出來的結果是正確的, 而且沒有多餘的等待.

只是要特別注意的是,這個 last node 的判斷不能在一開始匯入的地方做判斷,而是要在每一個 completion block 裡去判斷,因為有可能 第1個先執行的 completion block 卻在最後才跑完。

這個讓我想起來水為什麼不走直路的文章, 我的直覺是要 synchronous 等傳回值後, program flow 再往下走, 實際上在 asyncronous 下的 completion block 裡做事情也ok.

每件事情的發生必有其原因, 河流為什麼是彎的? 下面故事裡的用觀點滿有趣的, 他說彎是必然的就和人生會遇到無法跨愈的障礙一樣, 需要繞過去.

我覺得河流彎有彎的好, 缺點是水太大時容易淹水, 有時候需要截彎取直.













佛學院的一名禪師在上課時把一幅中國地圖展開,問:「這幅圖上的河流有什麼特點?」

「都不是直線,而是彎彎的曲線。」「為什麼會是這樣呢?也就是說,河流為什麼不走直路,而偏偏要走彎路呢?」禪師繼續問。

學僧們七嘴八舌地議論開了,有的說,河流走彎路,拉長了河流的流程,河流也因此能擁有更大的流量,當夏季洪水來臨時,河流就不會以水滿為患了;還有的說,由於河流的流程拉長,每個單位河段的流量就相對減少,河水對河床的衝擊力也隨之減弱,這就起到了保護河床的作用……

「你們說的這些都對。」禪師說,「但在我看來,河流不走直路而走彎路,最根本的原因就是,走彎路是自然界的一種常態,走直路而是一種非常態,因為河流在前進的過程中,會遇到各種各樣的障礙,有些障礙是無法逾越的。所以,它只有取彎路,繞道而行,也正因為走彎路,讓它避開了一道道障礙,最終抵達了遙遠的大海。

說到這裡,禪師突然把話題一轉,說:「其實,人生也是如此,當人們遇到坎坷、挫折時,也要把曲折的人生看做是一種常態,不悲觀失望,不長吁短歎,不停滯不前,把走彎路看成是前行的另一種形式、另一條途徑,這樣你就可以像那些走彎路的河流一樣,抵達那遙遠的人生大海。」

把走彎路看成是一種常態,懷著平常心去看待前進中遇到的坎坷和挫折,您會像河流一樣,抵達到人生的目標。




The best is yet to come.

Waiting until two async blocks are executed before starting another block

寫的程式裡有很多 connection request 都是 async 但有時候 main block 需要等 return 回來的值再繼續 process flow. sample code 如下:

dispatch_group_t group = dispatch_group_create();

dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^ {
    // block1
    NSLog(@"Block1");
    [NSThread sleepForTimeInterval:5.0];
    NSLog(@"Block1 End");
});


dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^ {
    // block2
    NSLog(@"Block2");
    [NSThread sleepForTimeInterval:8.0];
    NSLog(@"Block2 End");
});

dispatch_group_notify(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^ {
    // block3
    NSLog(@"Block3");
});

dispatch_release(group);
and could produce output like this:
2012-08-11 16:10:18.049 Dispatch[11858:1e03] Block1
2012-08-11 16:10:18.052 Dispatch[11858:1d03] Block2
2012-08-11 16:10:23.051 Dispatch[11858:1e03] Block1 End
2012-08-11 16:10:26.053 Dispatch[11858:1d03] Block2 End
2012-08-11 16:10:26.054 Dispatch[11858:1d03] Block3

========================

// create a group
dispatch_group_t group = dispatch_group_create();

// pair a dispatch_group_enter for each dispatch_group_leave
dispatch_group_enter(group);     // pair 1 enter
[self computeInBackground:1 completion:^{
    NSLog(@"1 done");
    dispatch_group_leave(group); // pair 1 leave
}];

// again... (and again...)
dispatch_group_enter(group);     // pair 2 enter
[self computeInBackground:2 completion:^{
    NSLog(@"2 done");
    dispatch_group_leave(group); // pair 2 leave
}];

// dispatch your final block after all the dispatch_group_enters
dispatch_async(dispatch_get_main_queue(), ^{
    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    NSLog(@"finally!");
});
In this example, computeInBackground:completion: is implemented as:
- (void)computeInBackground:(int)no completion:(void (^)(void))block {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
        NSLog(@"%d starting", no);
        sleep(no*2);
        block();
    });
}
Output (with timestamps from a run):
12:57:02.574  2 running
12:57:02.574  1 running
12:57:04.590  1 done
12:57:06.590  2 done
12:57:06.591  finally!

from:
http://stackoverflow.com/questions/11909629/waiting-until-two-async-blocks-are-executed-before-starting-another-block

Hide cells in a UITableView with static cells

在 static cell 要 hide 某一row 的最快作法是 set 該 row height=0;

sample code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
    if (indexPath.section == 0 && hideStuff) {
        cell = self.cellIWantToShow;
    }
    return cell;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    CGFloat height = [super tableView:tableView heightForRowAtIndexPath:indexPath];
    if (indexPath.section == 0 && hideStuff) {
        height = [super tableView:tableView heightForRowAtIndexPath:[NSIndexPath indexPathForRow:2 inSection:0]];
    }
    return height;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    NSInteger count = [super tableView:tableView numberOfRowsInSection:section];

    if (section == 0 && hideStuff) {
        count -= hiddenCells.count;
    }

    return count;
}


from:
http://stackoverflow.com/questions/18939879/hide-cells-in-a-uitableview-with-static-cells-and-no-autolayout-crash

2014年8月19日星期二

NSDictionary key sort

NSDictionary 似乎無法sort, 要轉成 Array.

example 1:
NSArray *keys = [myDictionary allKeys];
keys = [[keys mutableCopy] sortUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
上面這個 example 會 show error, 什麼 _strong 之類的 error.


example 2:
NSArray* sortedKeys = [myDict keysSortedByValueUsingSelector:@selector(comparator)];
這個範例是OK, for non-object value.
for Object Value 會 show error:

Exception: -[MyObject comparator]: unrecognized selector sent to instance 0x156a9ec0

example 3:
下面的範例,如果 dictionary 裡放的是 object, 使用 allValues 會比較有問題。
NSArray *sortedValues = [[yourDictionary allValues] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
NSMutableDictionary *orderedDictionary=[[NSMutableDictionary alloc]init];
for(NSString *valor in sortedValues){
    for(NSString *clave in [yourDictionary allKeys]){
        if ([valor isEqualToString:[yourDictionary valueForKey:clave]]) {
            [orderedDictionary setValue:valor forKey:clave];
        }
    }
}


取object 的 sample:

MyObject *data = [[myDictionary allValues] objectAtIndex:accessIndex];


NSDictionary如同hash table,它的key是沒排序過,查了下,其實可以用變通方式

Step 1: 先將Key排序做成一個array
NSArray * sortedKeys = [[keys allKeys] sortedArrayUsingSelector: @selector(caseInsensitiveCompare:)]; 

Step 2: 使用時用做出來的array來遞迴取出
for( Object *ob in sortedKeys ) {
    //你想做的事

這樣就是排好的了.

結論就是,透過objectAtIndex 來存取 dictionary 一定會是亂的!
要馬就是把 dictionary 先 sort 好存到一個 Array,放 table view access, 或是每次在 table view 裡 access 亂亂的 dictionary 時都 sort 一次。