<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-2840066036916532236</id><updated>2024-10-25T17:20:43.244+08:00</updated><category term="objective-c"/><category term="iOS"/><category term="Mac"/><category term="swift"/><category term="雜感"/><category term="Go"/><category term="3C"/><category term="Apple"/><category term="facebook"/><category term="股票"/><category term="App"/><category term="English"/><category term="Git"/><category term="Linux"/><category term="MP4"/><category term="MobileVLCKit"/><category term="Parse"/><category term="Store"/><category term="VLC"/><category term="admob"/><category term="golang"/><category term="slack"/><category term="slackbot"/><category term="vpon"/><category term="房地產"/><category term="輸入法"/><category term="音樂藝術"/><title type='text'>Vampirewalk&#39;s iOS Garden</title><subtitle type='html'>iOS development</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://vampirewalk.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://vampirewalk.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default?start-index=26&amp;max-results=25&amp;redirect=false'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/17070298612568804458</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>73</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-2840066036916532236.post-7899161462663413704</id><published>2016-01-13T17:37:00.001+08:00</published><updated>2016-01-15T14:40:17.001+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="iOS"/><title type='text'>iOS多執行緒以及UITableView</title><content type='html'>&lt;p&gt;這篇主要紀錄我如何設計一個多執行緒存取NSMutableArray以及使用UITableView呈現的方法。&lt;/p&gt;

&lt;p&gt;關於Thread、GCD、NSOperation的基本知識可以參考&lt;a href=&quot;https://zonble.gitbooks.io/kkbox-ios-dev/content/threading/index.html&quot;&gt;KKBox的教材&lt;/a&gt;。&lt;/p&gt;



&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs objectivec&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;@property&lt;/span&gt; (&lt;span class=&quot;hljs-keyword&quot;&gt;strong&lt;/span&gt;, atomic) &lt;span class=&quot;hljs-built_in&quot;&gt;NSMutableArray&lt;/span&gt;&amp;lt;Order *&amp;gt; *orders;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;把property宣告成atomic只能保證setOrders:執行到一半不會被其他thread插入而已，對保護NSMutableArray裡面的東西一點效果都沒有。可以看&lt;a href=&quot;https://www.objc.io/issues/2-concurrency/thread-safe-class-design/#atomic-properties&quot;&gt;Objc.io這一篇&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;我們必須保證一次只能有一個執行緒修改NSMutableArray，這時需要使用保護機制，有 &lt;br&gt;
 - NSLock &lt;br&gt;
 - @synchronized &lt;br&gt;
 - pthread_mutex_t  &lt;br&gt;
 - NSRecursiveLock &lt;br&gt;
 - NSConditionLock &lt;br&gt;
 - NSDistributedLock &lt;br&gt;
 - OSSPinlock&lt;/p&gt;

&lt;p&gt;可以在GCD裡用的有 &lt;br&gt;
 - Serial queue &lt;br&gt;
 - dispatch_barrier_async + dispatch_sync &lt;br&gt;
 - dispatch group &lt;br&gt;
 - dispatch semaphore&lt;/p&gt;

&lt;p&gt;可以參考&lt;a href=&quot;https://www.zybuluo.com/MicroCai/note/64272&quot;&gt;https://www.zybuluo.com/MicroCai/note/64272&lt;/a&gt; &lt;br&gt;
另外也有人做效能評比&lt;a href=&quot;http://lijianfei.sinaapp.com/?p=655&quot;&gt;http://lijianfei.sinaapp.com/?p=655&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;有了保護機制之後就要決定要保護的區塊有多大。 &lt;br&gt;
考慮以下情況，假設我們正在實做一個remove方法，而這段code會跑在GCD的global queue，所以可以用dispatch semaphore。&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs axapta&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (_orders.&lt;span class=&quot;hljs-keyword&quot;&gt;count&lt;/span&gt; &amp;gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;) {
    NSInteger &lt;span class=&quot;hljs-keyword&quot;&gt;index&lt;/span&gt; = [self indexOfOrderByUUID:uuid];
    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-keyword&quot;&gt;index&lt;/span&gt; != NSNotFound) {
        Order *&lt;span class=&quot;hljs-keyword&quot;&gt;order&lt;/span&gt; = _orders[&lt;span class=&quot;hljs-keyword&quot;&gt;index&lt;/span&gt;];
        [self removeObjectFromOrdersAtIndex:&lt;span class=&quot;hljs-keyword&quot;&gt;index&lt;/span&gt;];
    }
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;我最後的作法是底下這樣，一進critical section之後檢查有沒有order可以刪，沒有就閃人。如果有，不管有沒有找到目標，最後都要signal一下讓別人可以進critical section繼續做事，不然就會卡死。&lt;/p&gt;



&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs axapta&quot;&gt;dispatch_semaphore_wait(_semaphore, DISPATCH_TIME_FOREVER);
&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (_orders.&lt;span class=&quot;hljs-keyword&quot;&gt;count&lt;/span&gt; &amp;gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;) {
    NSInteger &lt;span class=&quot;hljs-keyword&quot;&gt;index&lt;/span&gt; = [self indexOfOrderByUUID:uuid];
    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-keyword&quot;&gt;index&lt;/span&gt; != NSNotFound) {
        Order *&lt;span class=&quot;hljs-keyword&quot;&gt;order&lt;/span&gt; = _orders[&lt;span class=&quot;hljs-keyword&quot;&gt;index&lt;/span&gt;];
        [self removeObjectFromOrdersAtIndex:&lt;span class=&quot;hljs-keyword&quot;&gt;index&lt;/span&gt;];
        dispatch_semaphore_signal(_semaphore);
    }
    &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {
        dispatch_semaphore_signal(_semaphore);
    }
}
&lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {
    dispatch_semaphore_signal(_semaphore);
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;保護好NSMutableArray確保沒有race condition之後，就要考慮如何讓UITableView呈現資料了。&lt;/p&gt;

&lt;p&gt;如果直接讓UITableView對NSMutableArray做KVO的話會有一個問題，由於UITableView是呼叫dataSource的 &lt;br&gt;
numberOfSectionsInTableView以及cellForRowAtIndexPath決定資料數目與cell的設置，這些都是在main thread執行，但是如果有許多background thread在這兩個delegate被呼叫之間新增或刪除了NSMutableArray裡面的內容，那麼資料就會不同步了。&lt;/p&gt;

&lt;p&gt;我的解法是在view controller或是view model設置一個NSArray做cache，當KVO觀察到NSMutableArray變化時，copy到這個cache。如果單純使用self.cacheOrders = 這種accessor的話，其實只是做shallow copy，並不會有太大的overhead。每次KVO觀察到NSMutableArray變化都會先更新cache，而background thread並不會去動到這份cache，這樣應該就可以解決不同步的問題了。&lt;/p&gt;



&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs objectivec&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;@property&lt;/span&gt; (copy, &lt;span class=&quot;hljs-keyword&quot;&gt;nonatomic&lt;/span&gt;) &lt;span class=&quot;hljs-built_in&quot;&gt;NSArray&lt;/span&gt; *cacheOrders;

[&lt;span class=&quot;hljs-keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;.KVOController&lt;/span&gt; observe:_service keyPath:@keypath(_service, orders) options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew block:^(OrderListTableViewController *observer, OrderService *service, &lt;span class=&quot;hljs-built_in&quot;&gt;NSDictionary&lt;/span&gt; *change) {
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            &lt;span class=&quot;hljs-keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;.cacheOrders&lt;/span&gt; = _service&lt;span class=&quot;hljs-variable&quot;&gt;.orders&lt;/span&gt;;
            [observer&lt;span class=&quot;hljs-variable&quot;&gt;.tableView&lt;/span&gt; reloadData];
        }];
}];

- (&lt;span class=&quot;hljs-built_in&quot;&gt;NSInteger&lt;/span&gt;)tableView:(&lt;span class=&quot;hljs-built_in&quot;&gt;UITableView&lt;/span&gt; *)tableView numberOfRowsInSection:(&lt;span class=&quot;hljs-built_in&quot;&gt;NSInteger&lt;/span&gt;)section {
    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; _cacheOrders&lt;span class=&quot;hljs-variable&quot;&gt;.count&lt;/span&gt;;
}


- (&lt;span class=&quot;hljs-built_in&quot;&gt;UITableViewCell&lt;/span&gt; *)tableView:(&lt;span class=&quot;hljs-built_in&quot;&gt;UITableView&lt;/span&gt; *)tableView cellForRowAtIndexPath:(&lt;span class=&quot;hljs-built_in&quot;&gt;NSIndexPath&lt;/span&gt; *)indexPath {
    OrderListTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:OrderListTableViewControllerCellIdentifier forIndexPath:indexPath];
    Order *order = &lt;span class=&quot;hljs-keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;.cacheOrders&lt;/span&gt;[indexPath&lt;span class=&quot;hljs-variable&quot;&gt;.row&lt;/span&gt;];

    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; cell;
}&lt;/code&gt;&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://vampirewalk.blogspot.com/feeds/7899161462663413704/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://vampirewalk.blogspot.com/2016/01/iosuitableview.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/7899161462663413704'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/7899161462663413704'/><link rel='alternate' type='text/html' href='http://vampirewalk.blogspot.com/2016/01/iosuitableview.html' title='iOS多執行緒以及UITableView'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/17070298612568804458</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2840066036916532236.post-6583453706382653961</id><published>2015-12-23T15:53:00.001+08:00</published><updated>2016-01-25T09:56:02.762+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="golang"/><category scheme="http://www.blogger.com/atom/ns#" term="slack"/><category scheme="http://www.blogger.com/atom/ns#" term="slackbot"/><title type='text'>開發Slackbot的筆記</title><content type='html'>&lt;p&gt;source: &lt;a href=&quot;https://github.com/vampirewalk/vanguard&quot;&gt;https://github.com/vampirewalk/vanguard&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;本來是想用&lt;a href=&quot;https://github.com/pvzig/SlackKit&quot;&gt;swift&lt;/a&gt;開發的，但是後來想到&lt;a href=&quot;https://github.com/apple/swift-corelibs-foundation&quot;&gt;Foundation&lt;/a&gt;在Linux上&lt;a href=&quot;http://stackoverflow.com/questions/31210648/is-it-possible-to-build-swift-code-using-the-foundation-framework-and-target-lin&quot;&gt;還沒實做&lt;/a&gt; (&lt;a href=&quot;https://github.com/apple/swift-corelibs-foundation/blob/master/Docs/Status.md&quot;&gt;這裡有進度&lt;/a&gt;)，只好先用Go做了。&lt;/p&gt;

&lt;h1 id=&quot;slack-group設定&quot;&gt;Slack Group設定&lt;/h1&gt;

&lt;p&gt;要先到Group裡的Apps &amp;amp; Custom Integrations加入Bots Integration，在這裡會得到token，等一下會給bot用。&lt;/p&gt;



&lt;h1 id=&quot;開發&quot;&gt;開發&lt;/h1&gt;

&lt;p&gt;主要用的是&lt;a href=&quot;https://github.com/nlopes/slack&quot;&gt;https://github.com/nlopes/slack&lt;/a&gt;這個library，它實做了slack的&lt;a href=&quot;https://api.slack.com/rtm&quot;&gt;Real Time Messaging API&lt;/a&gt;，底層走的是WebSocket。做出來的效果嘛，以我的slackbot為例，如下圖，只要在channel裡面貼出github repo的訊息，bot會自動返回repo的語言、star、issue數。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_ZcV-_a407MPfBV9Po4OH6sFwUN7nd3S2hCiPoEzR4evS4voCSxhckB0hBlhOz_1LVQvdDwMhy2F9726Ct7EzUmpzTN2t4C0BHcotrnyvYAEGbQr6ue-DI57oKgrLYBv9StM9LrzXkXQA/s0/repobot.png&quot; alt=&quot;repobot&quot; title=&quot;repobot.png&quot;&gt;&lt;/p&gt;

&lt;p&gt;從&lt;a href=&quot;https://github.com/BeepBoopHQ/go-slack-bot/blob/master/src/bot/main.go&quot;&gt;簡單的範例&lt;/a&gt;開始改，ConnectedEvent就是bot連上group，MessageEvent就是bot接收到訊息，依此類推。我的bot就是在MessageEvent把接收到的訊息做分析，如果包含Git repo，就透過&lt;a href=&quot;https://api.github.com/repos/[user]/[repo]&quot;&gt;https://api.github.com/repos/[user]/[repo]&lt;/a&gt;這個endpoint拿到repo的資料，然後再回傳。&lt;/p&gt;



&lt;h1 id=&quot;heroku&quot;&gt;Heroku&lt;/h1&gt;

&lt;p&gt;Bot做好之後要找個雲端放，目前我用Heroku，可以參考&lt;a href=&quot;https://devcenter.heroku.com/articles/getting-started-with-go#introduction&quot;&gt;https://devcenter.heroku.com/articles/getting-started-with-go#introduction&lt;/a&gt;。要讓Go可以在Heroku上跑需要三個步驟&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Godep&lt;/li&gt;
&lt;li&gt;Procfile&lt;/li&gt;
&lt;li&gt;env&lt;/li&gt;
&lt;/ol&gt;



&lt;h3 id=&quot;godep&quot;&gt;Godep&lt;/h3&gt;

&lt;p&gt;整個project做好後，用&lt;a href=&quot;https://github.com/tools/godep&quot;&gt;godep&lt;/a&gt;管理vender code。&lt;/p&gt;



&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs lasso&quot;&gt;godep save &lt;span class=&quot;hljs-attribute&quot;&gt;-r&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;



&lt;h3 id=&quot;procfile&quot;&gt;Procfile&lt;/h3&gt;

&lt;p&gt;這邊用的是worker&lt;/p&gt;



&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs http&quot;&gt;&lt;span class=&quot;hljs-attribute&quot;&gt;worker&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;slackbot&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;



&lt;h3 id=&quot;設定env參數&quot;&gt;設定env參數&lt;/h3&gt;

&lt;p&gt;可以透過Heroku的管理介面或是透過command設定&lt;/p&gt;



&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs bash&quot;&gt;heroku config:&lt;span class=&quot;hljs-keyword&quot;&gt;set&lt;/span&gt; SLACK_TOKEN=YOUR_REAL_TOKEN&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;然後在Go裡面用下面的方式拿到實際參數，這樣就可以避免在open source時洩漏token了。&lt;/p&gt;



&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs lua&quot;&gt;token := &lt;span class=&quot;hljs-built_in&quot;&gt;os&lt;/span&gt;.Getenv(&lt;span class=&quot;hljs-string&quot;&gt;&quot;SLACK_TOKEN&quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;



&lt;h3 id=&quot;本地測試&quot;&gt;本地測試&lt;/h3&gt;

&lt;p&gt;可以在本地建立一個.env檔，內容就是&lt;/p&gt;



&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs fix&quot;&gt;&lt;span class=&quot;hljs-attribute&quot;&gt;SLACK_TOKEN&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;YOUR_REAL_TOKEN&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;然後用heroku local測試，這樣一樣可以拿到參數。&lt;/p&gt;



&lt;h1 id=&quot;注意事項&quot;&gt;注意事項&lt;/h1&gt;

&lt;p&gt;有一點要注意的是現在bot似乎不能主動加入channel，必須先在channel裡面用invite指令邀請bot進聊天室才能讀到訊息。&lt;/p&gt;



&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs &quot;&gt;/invite YOUR_BOT_USERNAME&lt;/code&gt;&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://vampirewalk.blogspot.com/feeds/6583453706382653961/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://vampirewalk.blogspot.com/2015/12/slackbot.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/6583453706382653961'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/6583453706382653961'/><link rel='alternate' type='text/html' href='http://vampirewalk.blogspot.com/2015/12/slackbot.html' title='開發Slackbot的筆記'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/17070298612568804458</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_ZcV-_a407MPfBV9Po4OH6sFwUN7nd3S2hCiPoEzR4evS4voCSxhckB0hBlhOz_1LVQvdDwMhy2F9726Ct7EzUmpzTN2t4C0BHcotrnyvYAEGbQr6ue-DI57oKgrLYBv9StM9LrzXkXQA/s72-c/repobot.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2840066036916532236.post-2271225347670554236</id><published>2015-12-17T10:14:00.001+08:00</published><updated>2015-12-17T10:15:37.189+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="iOS"/><category scheme="http://www.blogger.com/atom/ns#" term="swift"/><title type='text'>一個關於遵循多個Swift 2.0 protocol extension的問題</title><content type='html'>&lt;h1 id=&quot;問題&quot;&gt;問題&lt;/h1&gt;

&lt;p&gt;最近練習用Protocol-Oriented Programming實做可移動以及縮放的View，遇到一個很有趣的問題，假設有以下兩個protocol&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs actionscript&quot;&gt;protocol Draggable: &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; {&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt; view: UIView { &lt;span class=&quot;hljs-keyword&quot;&gt;get&lt;/span&gt; }
    &lt;span class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt; initialLocation: CGPoint { &lt;span class=&quot;hljs-keyword&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;set&lt;/span&gt; }
}

extension Draggable where Self: UIView {
    &lt;span class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt; view: UIView { &lt;span class=&quot;hljs-keyword&quot;&gt;get&lt;/span&gt; { &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; self } }
    &lt;span class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt; parentView: UIView? { &lt;span class=&quot;hljs-keyword&quot;&gt;get&lt;/span&gt; { &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; self.view.superview } }
}
&lt;/code&gt;&lt;/pre&gt;



&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs php&quot;&gt;protocol Scalable: &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; {&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt; view: UIView { get }
}

extension Scalable where &lt;span class=&quot;hljs-keyword&quot;&gt;Self&lt;/span&gt;: UIView {
    &lt;span class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt; view: UIView { get { &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;self&lt;/span&gt; } }
    &lt;span class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt; parentView: UIView? { get { &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;self&lt;/span&gt;.view.superview } }
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;然後實做一個View遵循這兩個protocol&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs cs&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; VWView: UIView, Draggable, Scalable {
    &lt;span class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt; initialLocation: CGPoint = CGPointZero
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;這時候會發生compile error，告訴你 &lt;br&gt;
&lt;code&gt;Type &#39;VWView&#39; does not conform to protocol &#39;Scalable&#39;&lt;/code&gt; &lt;br&gt;
&lt;code&gt;Type &#39;VWView&#39; does not conform to protocol &#39;Draggable&#39;&lt;/code&gt;&lt;/p&gt;

&lt;h1 id=&quot;怎麼一回事呢&quot;&gt;怎麼一回事呢？&lt;/h1&gt;

&lt;p&gt;原來是因為兩個protocol都有&lt;code&gt;var view: UIView { get { return self } }&lt;/code&gt;的default implementations，編譯器不曉得該用哪一個，乾脆來一個編譯錯誤。&lt;/p&gt;



&lt;h1 id=&quot;解法&quot;&gt;解法&lt;/h1&gt;

&lt;p&gt;其實解決方法很簡單，就是在class裡實做這個值，這樣編譯器就知道該用class裡面的這個了。&lt;/p&gt;



&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs cs&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; VWView: UIView, Draggable, Scalable {
    &lt;span class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt; view: UIView { &lt;span class=&quot;hljs-keyword&quot;&gt;get&lt;/span&gt; { &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; self } }
    &lt;span class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt; initialLocation: CGPoint = CGPointZero
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Reference: &lt;br&gt;
&lt;a href=&quot;http://stackoverflow.com/questions/31586864/swift-2-0-protocol-extensions-two-protocols-with-the-same-function-signature-c&quot;&gt;http://stackoverflow.com/questions/31586864/swift-2-0-protocol-extensions-two-protocols-with-the-same-function-signature-c&lt;/a&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://vampirewalk.blogspot.com/feeds/2271225347670554236/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://vampirewalk.blogspot.com/2015/12/swift-20-protocol-extension.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/2271225347670554236'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/2271225347670554236'/><link rel='alternate' type='text/html' href='http://vampirewalk.blogspot.com/2015/12/swift-20-protocol-extension.html' title='一個關於遵循多個Swift 2.0 protocol extension的問題'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/17070298612568804458</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2840066036916532236.post-7518458124294111647</id><published>2015-12-09T14:24:00.001+08:00</published><updated>2015-12-09T14:24:39.995+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Parse"/><title type='text'>Parse Cloud Code初體驗</title><content type='html'>&lt;p&gt;最近在我的App&lt;a href=&quot;https://itunes.apple.com/tw/app/bei-bao-ke-zhu-su/id895741214?l=zh&amp;amp;mt=8&quot;&gt;背包客住宿&lt;/a&gt;裡需要新增一個上傳住宿資料的功能，由於App是用Parse.com當後端，所以可以選擇用Client SDK直接上傳或是呼叫Cloud Code去管理Data。這次我選擇使用Cloud Code，這樣之後如果要對上傳上來的資料做篩選或是處理都可以立即生效，不用等下一版App上架。&lt;/p&gt;

&lt;p&gt;安裝步驟那些就不說了，網路上資料一大把，紀錄幾個自己遇到的問題。&lt;/p&gt;

&lt;h1 id=&quot;beforesave&quot;&gt;beforeSave&lt;/h1&gt;

&lt;p&gt;我一開始以為beforeSave會比function早執行，結果卻相反，是先執行function，在儲存前才執行beforeSave。&lt;/p&gt;

&lt;h1 id=&quot;geocode&quot;&gt;Geocode&lt;/h1&gt;

&lt;p&gt;住宿資料上傳前，需要先對Address做Geocode，這個部份可以使用Google Maps API達成，在&lt;a href=&quot;http://stackoverflow.com/questions/25926293/geocoding-with-google-maps-api-via-parse-cloud-code&quot;&gt;Geocoding with Google Maps API via Parse Cloud Code&lt;/a&gt;這個stackoverflow上的問題有人提供了作法，但是語法跟現在的有點不同，在原答案是用&lt;code&gt;success: error:&lt;/code&gt;去分別處理呼叫成功與失敗，現在要用&lt;/p&gt;



&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs lua&quot;&gt;Parse.Cloud.httpRequest({
  url: &lt;span class=&quot;hljs-string&quot;&gt;&#39;http://www.example.com/&#39;&lt;/span&gt;,
  followRedirects: &lt;span class=&quot;hljs-keyword&quot;&gt;true&lt;/span&gt;
}).&lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt;(&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(httpResponse)&lt;/span&gt;&lt;/span&gt; {
  console.log(httpResponse.text);
}, &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(httpResponse)&lt;/span&gt;&lt;/span&gt; {
  console.&lt;span class=&quot;hljs-built_in&quot;&gt;error&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&#39;Request failed with response code &#39;&lt;/span&gt; + httpResponse.status);
});&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;then之後接的第一個function處理成功，第二個處理失敗。 &lt;br&gt;
一般在Parse Object裡我們會用GeoPoint表示地理位置，那麼從Maps API回來的資料要怎麼轉換為GeoPoint呢？ &lt;br&gt;
假設我的Hostel物件有一個欄位叫做location，而它是GeoPoint型別，那麼用下面這樣的轉換方式。&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs avrasm&quot;&gt;var lat = geocodeResponse&lt;span class=&quot;hljs-preprocessor&quot;&gt;.results&lt;/span&gt;[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;]&lt;span class=&quot;hljs-preprocessor&quot;&gt;.geometry&lt;/span&gt;&lt;span class=&quot;hljs-preprocessor&quot;&gt;.location&lt;/span&gt;&lt;span class=&quot;hljs-preprocessor&quot;&gt;.lat&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;;&lt;/span&gt;
var lng = geocodeResponse&lt;span class=&quot;hljs-preprocessor&quot;&gt;.results&lt;/span&gt;[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;]&lt;span class=&quot;hljs-preprocessor&quot;&gt;.geometry&lt;/span&gt;&lt;span class=&quot;hljs-preprocessor&quot;&gt;.location&lt;/span&gt;&lt;span class=&quot;hljs-preprocessor&quot;&gt;.lng&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;;&lt;/span&gt;
var point = new Parse&lt;span class=&quot;hljs-preprocessor&quot;&gt;.GeoPoint&lt;/span&gt;({latitude: lat, longitude: lng})&lt;span class=&quot;hljs-comment&quot;&gt;;&lt;/span&gt;
hostel&lt;span class=&quot;hljs-preprocessor&quot;&gt;.set&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&quot;location&quot;&lt;/span&gt;, point)&lt;/code&gt;&lt;/pre&gt;

&lt;h1 id=&quot;除錯&quot;&gt;除錯&lt;/h1&gt;

&lt;p&gt;目前還沒有找到什麼好方法debug，只能在code裡多log，然後在command line用&lt;code&gt;parse log&lt;/code&gt;看結果。&lt;/p&gt;



&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs avrasm&quot;&gt;console&lt;span class=&quot;hljs-preprocessor&quot;&gt;.log&lt;/span&gt;(request&lt;span class=&quot;hljs-preprocessor&quot;&gt;.params&lt;/span&gt;)&lt;span class=&quot;hljs-comment&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://vampirewalk.blogspot.com/feeds/7518458124294111647/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://vampirewalk.blogspot.com/2015/12/parse-cloud-code.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/7518458124294111647'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/7518458124294111647'/><link rel='alternate' type='text/html' href='http://vampirewalk.blogspot.com/2015/12/parse-cloud-code.html' title='Parse Cloud Code初體驗'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/17070298612568804458</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2840066036916532236.post-4593618499394697282</id><published>2015-12-04T13:51:00.001+08:00</published><updated>2015-12-04T13:51:07.380+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="swift"/><title type='text'>Swiftlint - 維護coding style的好工具</title><content type='html'>&lt;p&gt;&lt;a href=&quot;https://github.com/realm/SwiftLint&quot;&gt;https://github.com/realm/SwiftLint&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;在多人協作開發專案時，遵守團隊訂出的coding style是一個好習慣，可以讓其他協作者更容易看懂我們產出的程式碼。Realm釋出的這個tool就可以幫助我們將專案中不符合coding style的地方用warning甚至是error標出，利用Xcode幫我們自動把關，節省其他協作者幫我們檢查coding style的時間。目前Swiftlint是遵照&lt;a href=&quot;https://github.com/github/swift-style-guide&quot;&gt;GitHub’s Swift Style Guide&lt;/a&gt; 做檢查。&lt;/p&gt;



&lt;h1 id=&quot;安裝&quot;&gt;安裝&lt;/h1&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs cmake&quot;&gt;brew &lt;span class=&quot;hljs-keyword&quot;&gt;install&lt;/span&gt; swiftlint&lt;/code&gt;&lt;/pre&gt;

&lt;h1 id=&quot;設定&quot;&gt;設定&lt;/h1&gt;

&lt;p&gt;&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4otKF-9wQrtBMSigt9L_Xt_slP0_WVoALViEtFfQPmX5YD24BxXpt3CFnEnhfgJVZhMhDD1V_wdgOQNMZxcSlzjthwd6x2tbmunulmml8V_XA9B0SEYmTBwD6Ifv6k_9zN9sjUccg7BS0/s0/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2015-12-04+%25E4%25B8%258B%25E5%258D%25881.41.40.png&quot; alt=&quot;lint&quot; title=&quot;swiftlint.png&quot;&gt;&lt;/p&gt;

&lt;p&gt;在target的run script加入&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs bash&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; which swiftlint &amp;gt;/dev/null; &lt;span class=&quot;hljs-keyword&quot;&gt;then&lt;/span&gt;
  swiftlint
&lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;
  &lt;span class=&quot;hljs-built_in&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;SwiftLint does not exist, download from https://github.com/realm/SwiftLint&quot;&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;fi&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;然後在Xcode裡Build專案，哇，怎麼連Pod裡面的code都檢查了呢？&lt;/p&gt;

&lt;p&gt;在專案root path新建一個 &lt;code&gt;.swiftlint.yml&lt;/code&gt; 檔案，輸入&lt;/p&gt;



&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs haml&quot;&gt;included:
  -&lt;span class=&quot;ruby&quot;&gt; &lt;span class=&quot;hljs-constant&quot;&gt;YourProjectSourceDirectiryName&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;把YourProjectSourceDirectiryName替換成你的專案原始碼資料夾名稱就可以只檢查自己專案的coding style囉。&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://vampirewalk.blogspot.com/feeds/4593618499394697282/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://vampirewalk.blogspot.com/2015/12/swiftlint-coding-style.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/4593618499394697282'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/4593618499394697282'/><link rel='alternate' type='text/html' href='http://vampirewalk.blogspot.com/2015/12/swiftlint-coding-style.html' title='Swiftlint - 維護coding style的好工具'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/17070298612568804458</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4otKF-9wQrtBMSigt9L_Xt_slP0_WVoALViEtFfQPmX5YD24BxXpt3CFnEnhfgJVZhMhDD1V_wdgOQNMZxcSlzjthwd6x2tbmunulmml8V_XA9B0SEYmTBwD6Ifv6k_9zN9sjUccg7BS0/s72-c/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2015-12-04+%25E4%25B8%258B%25E5%258D%25881.41.40.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2840066036916532236.post-656381830924877950</id><published>2015-11-26T16:02:00.001+08:00</published><updated>2015-11-26T16:02:09.707+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="iOS"/><category scheme="http://www.blogger.com/atom/ns#" term="swift"/><title type='text'>Swift Optionals</title><content type='html'>&lt;p&gt;在swift中使用Optional來處理值缺失的狀況，如果看見一個variable是Optional類型，只有兩種可能，要嘛有值，要嘛就是nil。&lt;/p&gt;

&lt;h1 id=&quot;宣告方式&quot;&gt;宣告方式&lt;/h1&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs javascript&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt; coffee:&lt;span class=&quot;hljs-built_in&quot;&gt;String&lt;/span&gt;?&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;等於下面這種宣告方式&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs javascript&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt; coffee: Optional&amp;lt;&lt;span class=&quot;hljs-built_in&quot;&gt;String&lt;/span&gt;&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;由此可知 ? 其實是syntactic sugar。&lt;/p&gt;

&lt;p&gt;看看Optional的原始宣告&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs cpp&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;enum&lt;/span&gt; Optional&amp;lt;Wrapped&amp;gt; : _Reflectable, NilLiteralConvertible {
    &lt;span class=&quot;hljs-keyword&quot;&gt;case&lt;/span&gt; None
    &lt;span class=&quot;hljs-keyword&quot;&gt;case&lt;/span&gt; Some(Wrapped)
    &lt;span class=&quot;hljs-comment&quot;&gt;/// Construct a `nil` instance.&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; init()
    &lt;span class=&quot;hljs-comment&quot;&gt;/// Construct a non-`nil` instance that stores `some`.&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; init(_ some: Wrapped)
    &lt;span class=&quot;hljs-comment&quot;&gt;/// If `self == nil`, returns `nil`.  Otherwise, returns `f(self!)`.&lt;/span&gt;
    @warn_unused_result
    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; func &lt;span class=&quot;hljs-stl_container&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;map&lt;/span&gt;&amp;lt;U&amp;gt;&lt;/span&gt;(@noescape f: (Wrapped) throws -&amp;gt; U) rethrows -&amp;gt; U?
    &lt;span class=&quot;hljs-comment&quot;&gt;/// Returns `nil` if `self` is nil, `f(self!)` otherwise.&lt;/span&gt;
    @warn_unused_result
    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; func flatMap&amp;lt;U&amp;gt;(@noescape f: (Wrapped) throws -&amp;gt; U?) rethrows -&amp;gt; U?
    &lt;span class=&quot;hljs-comment&quot;&gt;/// Create an instance initialized with `nil`.&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; init(nilLiteral: ())
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;如果沒有賦值的話，Optional的預設值是nil。在Objective-C中，nil是一個0指標，在swift中nil是一個確定的值，任何Optioanl都可以設為nil。關於瞭解空值，可以參考&lt;a href=&quot;http://yulingtianxia.com/blog/2015/03/08/Insight-of-Null/&quot;&gt;悟空&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;其他關於Optional chaining以及一些更深度的剖析，可以參考&lt;a href=&quot;http://onevcat.com/2014/06/walk-in-swift/&quot;&gt;喵神的文章&lt;/a&gt;或是&lt;a href=&quot;http://yulingtianxia.com/blog/2014/06/17/optionals-and-optional-chaining-in-swift/#Nil_Coalescing_Operator&quot;&gt;玉令天下的Blog&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;另外有一種情況是如果Optional呼叫的function需要傳入Optional本身，像&lt;/p&gt;



&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs ruby&quot;&gt;&lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;ViewController&lt;/span&gt;: &lt;span class=&quot;hljs-title&quot;&gt;UIViewController&lt;/span&gt; {&lt;/span&gt;

    let finishedMessage = &lt;span class=&quot;hljs-string&quot;&gt;&quot;Network call has finished&quot;&lt;/span&gt;
    let messageLabel = &lt;span class=&quot;hljs-constant&quot;&gt;UILabel&lt;/span&gt;()

    override func viewDidLoad() {
        &lt;span class=&quot;hljs-keyword&quot;&gt;super&lt;/span&gt;.viewDidLoad()

        someNetworkCall { [weak &lt;span class=&quot;hljs-keyword&quot;&gt;self&lt;/span&gt;] &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt;
            &lt;span class=&quot;hljs-keyword&quot;&gt;self&lt;/span&gt;?.finished(&lt;span class=&quot;hljs-keyword&quot;&gt;self&lt;/span&gt;?.finishedMessage)
        }
    }

    func finished(&lt;span class=&quot;hljs-symbol&quot;&gt;message:&lt;/span&gt; &lt;span class=&quot;hljs-constant&quot;&gt;String&lt;/span&gt;) {
        messageLabel.text = message
    }
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;這一段是編譯不過的，因為self?.finishedMessage是Optional chaining，而Optional chaining回傳的一定是Optional值。那麼應該怎麼解呢？&lt;/p&gt;

&lt;p&gt;可以直接使用!，因為當self?為nil時不會繼續呼叫function，所以一旦呼叫了function就代表有值。&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs ruby&quot;&gt;someNetworkCall { [weak &lt;span class=&quot;hljs-keyword&quot;&gt;self&lt;/span&gt;] &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt;
            &lt;span class=&quot;hljs-keyword&quot;&gt;self&lt;/span&gt;?.finished(&lt;span class=&quot;hljs-keyword&quot;&gt;self&lt;/span&gt;!.finishedMessage)
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;詳情可以參考&lt;a href=&quot;http://blog.xebia.com/swift-optional-chaining-and-method-argument-evaluation/&quot;&gt;http://blog.xebia.com/swift-optional-chaining-and-method-argument-evaluation/&lt;/a&gt; 。&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://vampirewalk.blogspot.com/feeds/656381830924877950/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://vampirewalk.blogspot.com/2015/11/swift-optionals.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/656381830924877950'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/656381830924877950'/><link rel='alternate' type='text/html' href='http://vampirewalk.blogspot.com/2015/11/swift-optionals.html' title='Swift Optionals'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/17070298612568804458</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2840066036916532236.post-1093055604798264654</id><published>2015-11-04T15:03:00.001+08:00</published><updated>2015-11-18T09:37:39.577+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="iOS"/><title type='text'>隱藏無內容的Self Sizing Cell</title><content type='html'>&lt;p&gt;基本上看完&lt;a href=&quot;http://blog.sunnyxx.com/2015/05/17/cell-height-calculation/&quot;&gt;优化UITableViewCell高度计算的那些事&lt;/a&gt;就可以大概瞭解從iOS7以後計算TableViewCell高度需要注意的事。&lt;/p&gt;

&lt;p&gt;假設cell裡只有一個addressLabel，而且我們使用iOS8的self sizing，想讓無內容的cell高度變為0，也就是不顯示，可以把top跟bottom constraint的constant設為0。先把xib或storyboard中上下的constraint拉出IBOutlet到 .m 檔中，在cellForRowAtIndexPath的時候根據內容是否為空決定constant大小。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGi35h1DSJzwvTcQpf6VJzPuckfOEa5gVnh1zLz746gPcYJ9hl-M5haBlyATB_AYVuDl4VDijg8ccDWwcwv0jE7a5I-G4RB4EVYTKj8YAmcCFN2xL3_rFVbX6V5U79Byd25eNVBsH6UKi_/s0/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2015-11-18+%25E4%25B8%258A%25E5%258D%25889.34.54.png&quot; alt=&quot;Constraint&quot; title=&quot;Label constraint&quot;&gt;&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs avrasm&quot;&gt;- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *simpleTableIdentifier = @&lt;span class=&quot;hljs-string&quot;&gt;&quot;ListTableViewCell&quot;&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;;&lt;/span&gt;

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier forIndexPath:indexPath]&lt;span class=&quot;hljs-comment&quot;&gt;;&lt;/span&gt;
    if (cell&lt;span class=&quot;hljs-preprocessor&quot;&gt;.addressLabel&lt;/span&gt;&lt;span class=&quot;hljs-preprocessor&quot;&gt;.text&lt;/span&gt;&lt;span class=&quot;hljs-preprocessor&quot;&gt;.length&lt;/span&gt; == &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;) {
        cell&lt;span class=&quot;hljs-preprocessor&quot;&gt;.addressLabelTopConstraint&lt;/span&gt;&lt;span class=&quot;hljs-preprocessor&quot;&gt;.constant&lt;/span&gt; = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;;&lt;/span&gt;
        cell&lt;span class=&quot;hljs-preprocessor&quot;&gt;.addressLabelBottomConstraint&lt;/span&gt;&lt;span class=&quot;hljs-preprocessor&quot;&gt;.constant&lt;/span&gt; = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;;&lt;/span&gt;
    }
    else {
        cell&lt;span class=&quot;hljs-preprocessor&quot;&gt;.addressLabelTopConstraint&lt;/span&gt;&lt;span class=&quot;hljs-preprocessor&quot;&gt;.constant&lt;/span&gt; = &lt;span class=&quot;hljs-number&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;;&lt;/span&gt;
        cell&lt;span class=&quot;hljs-preprocessor&quot;&gt;.addressLabelBottomConstraint&lt;/span&gt;&lt;span class=&quot;hljs-preprocessor&quot;&gt;.constant&lt;/span&gt; = &lt;span class=&quot;hljs-number&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;;&lt;/span&gt;
    }
    [cell layoutIfNeeded]&lt;span class=&quot;hljs-comment&quot;&gt;;&lt;/span&gt;
    return cell&lt;span class=&quot;hljs-comment&quot;&gt;;&lt;/span&gt;
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;addressLabel如果沒有內容，因為Label約束與上下邊緣一致 (constant為0)，所以Label高度會被自動計算為0，且不會佔任何空間。&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://vampirewalk.blogspot.com/feeds/1093055604798264654/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://vampirewalk.blogspot.com/2015/11/self-sizing-cell.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/1093055604798264654'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/1093055604798264654'/><link rel='alternate' type='text/html' href='http://vampirewalk.blogspot.com/2015/11/self-sizing-cell.html' title='隱藏無內容的Self Sizing Cell'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/17070298612568804458</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGi35h1DSJzwvTcQpf6VJzPuckfOEa5gVnh1zLz746gPcYJ9hl-M5haBlyATB_AYVuDl4VDijg8ccDWwcwv0jE7a5I-G4RB4EVYTKj8YAmcCFN2xL3_rFVbX6V5U79Byd25eNVBsH6UKi_/s72-c/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2015-11-18+%25E4%25B8%258A%25E5%258D%25889.34.54.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2840066036916532236.post-9071281960797967993</id><published>2015-10-30T11:49:00.001+08:00</published><updated>2015-10-30T11:55:43.143+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="App"/><category scheme="http://www.blogger.com/atom/ns#" term="facebook"/><category scheme="http://www.blogger.com/atom/ns#" term="iOS"/><category scheme="http://www.blogger.com/atom/ns#" term="objective-c"/><category scheme="http://www.blogger.com/atom/ns#" term="Store"/><title type='text'>在iOS App裡加入Fan page與App Store link</title><content type='html'>&lt;p&gt;&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmoPBNORKTZ8_IYafVOx0sk7a_HxDdWnLnUJMIJNKFNVNOOOfy3O3-jTbtwDNYIGU0Zp2YVXq00dmThrtOSnFr9rWaYI-UEGRQdHZebNCQa0GwOevq03uFTqxa2O38wxZVFQD0pS81QLJH/s0/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2015-10-30+%25E4%25B8%258A%25E5%258D%258811.28.34.png&quot; alt=&quot;Screenshot&quot; title=&quot;範例&quot;&gt;&lt;/p&gt;

&lt;p&gt;在App裡面，我們經常會需要連結到自己的粉絲團，或是App Store頁面請使用者評分。 &lt;br&gt;
接下來講解怎麼實做。&lt;/p&gt;

&lt;h1 id=&quot;連到粉絲團&quot;&gt;連到粉絲團&lt;/h1&gt;

&lt;p&gt;下面這一段code的思考模式是這樣，我們會先用canOpenURL去檢查使用者是否安裝了Facebook app， &lt;br&gt;
若有則用原生的facebook app開啟粉絲團頁面，若無則使用safari去開啟行動網頁。 &lt;br&gt;
如果不知道自己的粉絲團id可以使用 &lt;a href=&quot;http://findmyfbid.com/&quot;&gt;http://findmyfbid.com/&lt;/a&gt; 查詢。&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs objectivec&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;NSURL&lt;/span&gt; *facebookAppLink = [&lt;span class=&quot;hljs-built_in&quot;&gt;NSURL&lt;/span&gt; URLWithString:@&lt;span class=&quot;hljs-string&quot;&gt;&quot;fb://profile/yourid&quot;&lt;/span&gt;];
&lt;span class=&quot;hljs-built_in&quot;&gt;NSURL&lt;/span&gt; *facebookURL = [&lt;span class=&quot;hljs-built_in&quot;&gt;NSURL&lt;/span&gt; URLWithString:@&lt;span class=&quot;hljs-string&quot;&gt;&quot;https://m.facebook.com/yourid&quot;&lt;/span&gt;];

&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; ([[&lt;span class=&quot;hljs-built_in&quot;&gt;UIApplication&lt;/span&gt; sharedApplication] canOpenURL:facebookAppLink]) {
    [[&lt;span class=&quot;hljs-built_in&quot;&gt;UIApplication&lt;/span&gt; sharedApplication] openURL:facebookAppLink];
} &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {
    [[&lt;span class=&quot;hljs-built_in&quot;&gt;UIApplication&lt;/span&gt; sharedApplication] openURL:facebookURL];
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;在iOS9你很可能會遇到這樣的錯誤&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs lua&quot;&gt;CanOpen[&lt;span class=&quot;hljs-number&quot;&gt;2255&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;1002610&lt;/span&gt;] -canOpenURL: failed &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; URL:
 &lt;span class=&quot;hljs-string&quot;&gt;&quot;fb://&quot;&lt;/span&gt; - &lt;span class=&quot;hljs-built_in&quot;&gt;error&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;(null)&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;這裡要特別注意的是，在iOS9之後必需要在info.plist裡面設置LSApplicationQueriesSchemes， &lt;br&gt;
這樣canOpenURL才會回傳YES，沒有設定他只會回傳NO。所以要到info.plist裡面加入 &lt;br&gt;
LSApplicationQueriesSchemes，新增一個fb item，類別是String，這樣就可以了。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEioHZrKRAfZgj5mNSno0Izzo8P3OHDbxcRRV6KtDu9Z6-dkKzrgYJEdCQsmugtTKx6zbPRcciFRDS677Zq7O7Mi_O5fjlS9pnzEVW9zGEDv48M0X8ef5TLdyVQZYhQJ1tQ7wGdCixzPD9Eo/s0/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2015-10-30+%25E4%25B8%258A%25E5%258D%258810.59.56.png&quot; alt=&quot;scheme&quot; title=&quot;範例&quot;&gt;&lt;/p&gt;

&lt;p&gt;圖片裡有很多item是因為我有整合facebook登入，如果要打開粉絲團頁面其實只需要fb那個就可以。&lt;/p&gt;

&lt;h1 id=&quot;app-store頁面&quot;&gt;App Store頁面&lt;/h1&gt;

&lt;p&gt;網路上有很多人採用openURL的方式來打開App Store連結，如下所示。 &lt;br&gt;
但我個人覺得這個方式打開的速度有點慢，因為它會先打開safari，然後再跳轉到原生App Store裡面， &lt;br&gt;
大概會lag幾秒，使用者體驗不是很優。&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs lua&quot;&gt;NSString *iTunesLink = @&lt;span class=&quot;hljs-string&quot;&gt;&quot;itms://itunes.apple.com/us/app/apple-store/id375380948?mt=8&quot;&lt;/span&gt;;
&lt;span class=&quot;hljs-string&quot;&gt;[[UIApplication sharedApplication] openURL:[NSURL URLWithString:iTunesLink]]&lt;/span&gt;;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;其實在iOS6之後就有新增一個SKStoreProductViewController類別可以在App內打開App Store頁面， &lt;br&gt;
不用跳出自己的App就可以讓使用者評分了，這樣感覺是不是好很多了？&lt;/p&gt;

&lt;p&gt;首先引入StoreKit，並讓自己的ViewController遵從SKStoreProductViewControllerDelegate。&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs ruby&quot;&gt;&lt;span class=&quot;hljs-variable&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;hljs-constant&quot;&gt;StoreKit&lt;/span&gt;;

&lt;span class=&quot;hljs-variable&quot;&gt;@interface&lt;/span&gt; &lt;span class=&quot;hljs-constant&quot;&gt;ViewController&lt;/span&gt; &lt;span class=&quot;hljs-symbol&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hljs-constant&quot;&gt;UIViewController&lt;/span&gt;&amp;lt;&lt;span class=&quot;hljs-constant&quot;&gt;SKStoreProductViewControllerDelegate&lt;/span&gt;&amp;gt;
&lt;span class=&quot;hljs-variable&quot;&gt;@end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;打開頁面&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs objectivec&quot;&gt;- (&lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt;)openAppStorePage
{
    &lt;span class=&quot;hljs-built_in&quot;&gt;NSString&lt;/span&gt; *cAppleID = @&lt;span class=&quot;hljs-string&quot;&gt;&quot;your app id&quot;&lt;/span&gt;;
    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; ([SKStoreProductViewController class]) {
        SKStoreProductViewController *storeViewController = [[SKStoreProductViewController alloc] init];
        storeViewController&lt;span class=&quot;hljs-variable&quot;&gt;.delegate&lt;/span&gt; = &lt;span class=&quot;hljs-keyword&quot;&gt;self&lt;/span&gt;;
        &lt;span class=&quot;hljs-built_in&quot;&gt;NSDictionary&lt;/span&gt; *dict = [&lt;span class=&quot;hljs-built_in&quot;&gt;NSDictionary&lt;/span&gt; dictionaryWithObject:cAppleID forKey: SKStoreProductParameterITunesItemIdentifier];
        [storeViewController loadProductWithParameters:dict completionBlock:^(&lt;span class=&quot;hljs-built_in&quot;&gt;BOOL&lt;/span&gt; result, &lt;span class=&quot;hljs-built_in&quot;&gt;NSError&lt;/span&gt; * _Nullable error) {
            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (result) {
                [&lt;span class=&quot;hljs-keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;.navigationController&lt;/span&gt; presentViewController:storeViewController animated:&lt;span class=&quot;hljs-literal&quot;&gt;YES&lt;/span&gt; completion:&lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt;];
            }
        }];
    }&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;按下關閉時要dismiss目前顯示的頁面。&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs objectivec&quot;&gt;- (&lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt;)productViewControllerDidFinish:(SKStoreProductViewController *)viewController {
    [viewController dismissViewControllerAnimated: &lt;span class=&quot;hljs-literal&quot;&gt;YES&lt;/span&gt; completion: &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt;];
}&lt;/code&gt;&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://vampirewalk.blogspot.com/feeds/9071281960797967993/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://vampirewalk.blogspot.com/2015/10/ios-9-appfan-pageapp-store-link.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/9071281960797967993'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/9071281960797967993'/><link rel='alternate' type='text/html' href='http://vampirewalk.blogspot.com/2015/10/ios-9-appfan-pageapp-store-link.html' title='在iOS App裡加入Fan page與App Store link'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/17070298612568804458</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmoPBNORKTZ8_IYafVOx0sk7a_HxDdWnLnUJMIJNKFNVNOOOfy3O3-jTbtwDNYIGU0Zp2YVXq00dmThrtOSnFr9rWaYI-UEGRQdHZebNCQa0GwOevq03uFTqxa2O38wxZVFQD0pS81QLJH/s72-c/%25E8%259E%25A2%25E5%25B9%2595%25E5%25BF%25AB%25E7%2585%25A7+2015-10-30+%25E4%25B8%258A%25E5%258D%258811.28.34.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2840066036916532236.post-2230260455526455048</id><published>2015-10-20T16:20:00.001+08:00</published><updated>2015-11-03T13:36:44.748+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="facebook"/><category scheme="http://www.blogger.com/atom/ns#" term="iOS"/><title type='text'>整合Parse與Facebook登入</title><content type='html'>&lt;p&gt;其實已經有人整理好一篇&lt;a href=&quot;https://swiftlyios.com/parse-facebook-login-register/&quot;&gt;文章&lt;/a&gt;了，照著步驟做應該沒有什麼問題。不過呢，我們至少要知道為什麼要這樣做。Apple在iOS9預設HTTP必須走TLS1.2，也就是HTTPS的形式。不過看起來目前FB的Server還沒有支援，所以必須設置例外讓連線可以接通。關於ATS以及詳細的資訊可以參考&lt;a href=&quot;https://github.com/ChenYilong/iOS9AdaptationTips#1-demo1_ios9%E7%BD%91%E7%BB%9C%E9%80%82%E9%85%8D_ats%E6%94%B9%E7%94%A8%E6%9B%B4%E5%AE%89%E5%85%A8%E7%9A%84https&quot;&gt;iOS9网络适配_ATS：改用更安全的HTTPS&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;另外，如果要對UI做本地化(Localization)，記得要新增一個ParseUI.strings而不是使用原本的Localizable.strings。&lt;/p&gt;

&lt;p&gt;客制化按鈕顏色的話，要先去除backgroundImage再設定backgroundColor。&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs avrasm&quot;&gt;[self&lt;span class=&quot;hljs-preprocessor&quot;&gt;.logInView&lt;/span&gt;&lt;span class=&quot;hljs-preprocessor&quot;&gt;.logInButton&lt;/span&gt; setBackgroundImage:nil forState:UIControlStateNormal]&lt;span class=&quot;hljs-comment&quot;&gt;;&lt;/span&gt;
self&lt;span class=&quot;hljs-preprocessor&quot;&gt;.logInView&lt;/span&gt;&lt;span class=&quot;hljs-preprocessor&quot;&gt;.logInButton&lt;/span&gt;&lt;span class=&quot;hljs-preprocessor&quot;&gt;.backgroundColor&lt;/span&gt; = [UIColor orangeColor]&lt;span class=&quot;hljs-comment&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://vampirewalk.blogspot.com/feeds/2230260455526455048/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://vampirewalk.blogspot.com/2015/10/parsefacebook.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/2230260455526455048'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/2230260455526455048'/><link rel='alternate' type='text/html' href='http://vampirewalk.blogspot.com/2015/10/parsefacebook.html' title='整合Parse與Facebook登入'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/17070298612568804458</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2840066036916532236.post-6823996499727923841</id><published>2015-10-08T00:07:00.001+08:00</published><updated>2015-10-08T00:07:42.504+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="iOS"/><category scheme="http://www.blogger.com/atom/ns#" term="swift"/><title type='text'>用swift判斷是否在模擬器上編譯</title><content type='html'>&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs r&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#if (arch(i386) || arch(x86_64)) &amp;amp;&amp;amp; os(iOS)&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;hljs-comment&quot;&gt;#endif&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://vampirewalk.blogspot.com/feeds/6823996499727923841/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://vampirewalk.blogspot.com/2015/10/swift.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/6823996499727923841'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/6823996499727923841'/><link rel='alternate' type='text/html' href='http://vampirewalk.blogspot.com/2015/10/swift.html' title='用swift判斷是否在模擬器上編譯'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/17070298612568804458</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2840066036916532236.post-2509401370388246770</id><published>2015-10-05T14:34:00.001+08:00</published><updated>2015-10-07T16:27:32.701+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="iOS"/><category scheme="http://www.blogger.com/atom/ns#" term="objective-c"/><title type='text'>做一個無限旋轉的UIView</title><content type='html'>&lt;p&gt;這幾天需要做一個無限旋轉的View，有點像下圖這樣，一個開關控制風扇啟動與停止。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiiPdemL2aFaI_wBS0UQLTAhGAU2mNTdlBFHdpA4ca9QvZhOzi1lj08fVuj85WqH7cjtzNU4LHUbj9A_5oxiysDI84rDV_d_mCCs9FrdmT1-pFtz5rBnYlBfXAUZWupyxybZd5OfGCoZhoB/s0/Fan.png&quot; alt=&quot;Fan&quot; title=&quot;Fan.png&quot;&gt;&lt;/p&gt;

&lt;p&gt;在&lt;a href=&quot;http://stackoverflow.com/questions/9844925/uiview-infinite-360-degree-rotation-animation&quot;&gt;stackoverflow&lt;/a&gt;上找到一篇相關的討論，在所有答案中我最喜歡&lt;a href=&quot;http://stackoverflow.com/a/11242492/1060971&quot;&gt;Nate的答案&lt;/a&gt;。&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs objectivec&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// an ivar for your class:&lt;/span&gt;
&lt;span class=&quot;hljs-built_in&quot;&gt;BOOL&lt;/span&gt; animating;

- (&lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt;) spinWithOptions: (UIViewAnimationOptions) options {
   &lt;span class=&quot;hljs-comment&quot;&gt;// this spin completes 360 degrees every 2 seconds&lt;/span&gt;
   [&lt;span class=&quot;hljs-built_in&quot;&gt;UIView&lt;/span&gt; animateWithDuration: &lt;span class=&quot;hljs-number&quot;&gt;0.5&lt;/span&gt;f
                         delay: &lt;span class=&quot;hljs-number&quot;&gt;0.0&lt;/span&gt;f
                       options: options
                    animations: ^{
                       &lt;span class=&quot;hljs-keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;.imageToMove&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;.transform&lt;/span&gt; = CGAffineTransformRotate(imageToMove&lt;span class=&quot;hljs-variable&quot;&gt;.transform&lt;/span&gt;, M_PI / &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;);
                    }
                    completion: ^(&lt;span class=&quot;hljs-built_in&quot;&gt;BOOL&lt;/span&gt; finished) {
                       &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (finished) {
                          &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (animating) {
                             &lt;span class=&quot;hljs-comment&quot;&gt;// if flag still set, keep spinning with constant speed&lt;/span&gt;
                             [&lt;span class=&quot;hljs-keyword&quot;&gt;self&lt;/span&gt; spinWithOptions: UIViewAnimationOptionCurveLinear];
                          } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (options != UIViewAnimationOptionCurveEaseOut) {
                             &lt;span class=&quot;hljs-comment&quot;&gt;// one last spin, with deceleration&lt;/span&gt;
                             [&lt;span class=&quot;hljs-keyword&quot;&gt;self&lt;/span&gt; spinWithOptions: UIViewAnimationOptionCurveEaseOut];
                          }
                       }
                    }];
}

- (&lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt;) startSpin {
   &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (!animating) {
      animating = &lt;span class=&quot;hljs-literal&quot;&gt;YES&lt;/span&gt;;
      [&lt;span class=&quot;hljs-keyword&quot;&gt;self&lt;/span&gt; spinWithOptions: UIViewAnimationOptionCurveEaseIn];
   }   
}

- (&lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt;) stopSpin {
    &lt;span class=&quot;hljs-comment&quot;&gt;// set the flag to stop spinning after one last 90 degree increment&lt;/span&gt;
    animating = &lt;span class=&quot;hljs-literal&quot;&gt;NO&lt;/span&gt;;
}&lt;/code&gt;&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://vampirewalk.blogspot.com/feeds/2509401370388246770/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://vampirewalk.blogspot.com/2015/10/uiview.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/2509401370388246770'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/2509401370388246770'/><link rel='alternate' type='text/html' href='http://vampirewalk.blogspot.com/2015/10/uiview.html' title='做一個無限旋轉的UIView'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/17070298612568804458</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiiPdemL2aFaI_wBS0UQLTAhGAU2mNTdlBFHdpA4ca9QvZhOzi1lj08fVuj85WqH7cjtzNU4LHUbj9A_5oxiysDI84rDV_d_mCCs9FrdmT1-pFtz5rBnYlBfXAUZWupyxybZd5OfGCoZhoB/s72-c/Fan.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2840066036916532236.post-6704564166714046293</id><published>2015-10-02T16:25:00.001+08:00</published><updated>2015-10-02T16:25:30.065+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="iOS"/><category scheme="http://www.blogger.com/atom/ns#" term="objective-c"/><title type='text'>Objective-C 基本觀念複習</title><content type='html'>&lt;p&gt;雖然現在Swift已經出到2.0了，但是大多數公司還是使用Objective-C為主力語言。因此，適時複習一下觀念還是很有必要的。網路上有一些不錯的題目，例如 &lt;a href=&quot;http://blog.sunnyxx.com/2015/07/04/ios-interview/&quot;&gt;招聘一个靠谱的 iOS&lt;/a&gt;、&lt;a href=&quot;http://nelson.logdown.com/posts/2015/04/27/questions-i-ask-when-interview-ios-engineer&quot;&gt;面試 iOS 工程師的一些題目&lt;/a&gt;、&lt;a href=&quot;http://www.zhihu.com/question/19604641&quot;&gt;如何面试 iOS 工程师？&lt;/a&gt;、&lt;a href=&quot;http://onevcat.com/2013/04/ios-interview/&quot;&gt;上级向的十个iOS面试问题&lt;/a&gt;。也有一些網友給出了自己的解答，例如：&lt;a href=&quot;https://github.com/ChenYilong/iOSInterviewQuestions&quot;&gt;https://github.com/ChenYilong/iOSInterviewQuestions&lt;/a&gt; 以及 &lt;a href=&quot;http://www.90159.com/2015/07/26/71/&quot;&gt;http://www.90159.com/2015/07/26/71/&lt;/a&gt; 還有 &lt;a href=&quot;http://www.jianshu.com/p/4fea8fa60d75&quot;&gt;http://www.jianshu.com/p/4fea8fa60d75&lt;/a&gt; 。不過網路上的答案終究是別人的，唯有實實在在的自己研究過一遍，才會成為自己的東西，共勉之。&lt;/p&gt;

&lt;p&gt;下面是一些我蒐集的基本觀念文章，也許可以幫你節省一點找資料的時間。&lt;/p&gt;

&lt;h1 id=&quot;property&quot;&gt;Property&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;http://www.devtalking.com/articles/you-should-to-know-property/&quot;&gt;http://www.devtalking.com/articles/you-should-to-know-property/&lt;/a&gt;&lt;/p&gt;



&lt;h1 id=&quot;block&quot;&gt;Block&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;http://www.devtalking.com/articles/you-should-know-block/&quot;&gt;http://www.devtalking.com/articles/you-should-know-block/&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&quot;物件之間的溝通&quot;&gt;物件之間的溝通&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://www.objc.io/issues/7-foundation/communication-patterns/&quot;&gt;https://www.objc.io/issues/7-foundation/communication-patterns/&lt;/a&gt;&lt;/p&gt;



&lt;h1 id=&quot;category&quot;&gt;Category&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;http://tech.meituan.com/DiveIntoCategory.html&quot;&gt;http://tech.meituan.com/DiveIntoCategory.html&lt;/a&gt;&lt;/p&gt;



&lt;h1 id=&quot;kvc-kvo&quot;&gt;KVC, KVO&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;http://objccn.io/issue-7-3/&quot;&gt;http://objccn.io/issue-7-3/&lt;/a&gt; &lt;br&gt;
&lt;a href=&quot;http://southpeak.github.io/blog/2015/04/23/nskeyvalueobserving-kvo/&quot;&gt;http://southpeak.github.io/blog/2015/04/23/nskeyvalueobserving-kvo/&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&quot;runloop&quot;&gt;Runloop&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;http://blog.ibireme.com/2015/05/18/runloop/&quot;&gt;http://blog.ibireme.com/2015/05/18/runloop/&lt;/a&gt;&lt;/p&gt;



&lt;h1 id=&quot;deep-copy-shallow-copy&quot;&gt;Deep copy &amp;amp; Shallow copy&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://www.zybuluo.com/MicroCai/note/50592&quot;&gt;https://www.zybuluo.com/MicroCai/note/50592&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&quot;runtime&quot;&gt;Runtime&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;http://blog.eddie.com.tw/2013/12/05/object-class-and-meta-class-in-objective-c/&quot;&gt;http://blog.eddie.com.tw/2013/12/05/object-class-and-meta-class-in-objective-c/&lt;/a&gt; &lt;br&gt;
&lt;a href=&quot;http://yulingtianxia.com/blog/2014/11/05/objective-c-runtime/&quot;&gt;http://yulingtianxia.com/blog/2014/11/05/objective-c-runtime/&lt;/a&gt; &lt;br&gt;
&lt;a href=&quot;http://chun.tips/blog/categories/objective-c-runtime/&quot;&gt;http://chun.tips/blog/categories/objective-c-runtime/&lt;/a&gt;  &lt;br&gt;
&lt;a href=&quot;http://southpeak.github.io/blog/2014/10/25/objective-c-runtime-yun-xing-shi-zhi-lei-yu-dui-xiang/&quot;&gt;http://southpeak.github.io/blog/2014/10/25/objective-c-runtime-yun-xing-shi-zhi-lei-yu-dui-xiang/&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&quot;arc釋放機制&quot;&gt;ARC釋放機制&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;http://blog.sunnyxx.com/2014/04/02/objc_dig_arc_dealloc/&quot;&gt;http://blog.sunnyxx.com/2014/04/02/objc_dig_arc_dealloc/&lt;/a&gt;&lt;/p&gt;



&lt;h1 id=&quot;autorelease原理&quot;&gt;Autorelease原理&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;http://blog.sunnyxx.com/2014/10/15/behind-autorelease/&quot;&gt;http://blog.sunnyxx.com/2014/10/15/behind-autorelease/&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&quot;method-swizzling&quot;&gt;Method swizzling&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;http://southpeak.github.io/blog/2014/11/06/objective-c-runtime-yun-xing-shi-zhi-si-:method-swizzling/&quot;&gt;http://southpeak.github.io/blog/2014/11/06/objective-c-runtime-yun-xing-shi-zhi-si-:method-swizzling/&lt;/a&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://vampirewalk.blogspot.com/feeds/6704564166714046293/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://vampirewalk.blogspot.com/2015/10/objective-c.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/6704564166714046293'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/6704564166714046293'/><link rel='alternate' type='text/html' href='http://vampirewalk.blogspot.com/2015/10/objective-c.html' title='Objective-C 基本觀念複習'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/17070298612568804458</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2840066036916532236.post-6931972740090883635</id><published>2015-08-11T10:48:00.001+08:00</published><updated>2015-08-11T10:56:26.526+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="iOS"/><title type='text'>Mock completion block with OCMock</title><content type='html'>&lt;p&gt;This is an example unit test using Specta, Expecta and OCMock. &lt;br&gt;
Another example - &lt;a href=&quot;https://github.com/wordpress-mobile/WordPress-iOS/blob/d2100c0d64fa2363ad14919cf7b4ea0e4a00dc02/WordPress/WordPressTest/LoginViewModelTests.m#L822&quot;&gt;WordPress iOS app unit test&lt;/a&gt;.&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs objectivec&quot;&gt;&lt;span class=&quot;hljs-preprocessor&quot;&gt;#import &lt;span class=&quot;hljs-title&quot;&gt;&quot;Specta.h&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;hljs-preprocessor&quot;&gt;#define EXP_SHORTHAND&lt;/span&gt;
&lt;span class=&quot;hljs-preprocessor&quot;&gt;#import &lt;span class=&quot;hljs-title&quot;&gt;&quot;Expecta.h&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;hljs-preprocessor&quot;&gt;#import &lt;span class=&quot;hljs-title&quot;&gt;&amp;lt;OCMock/OCMock.h&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;hljs-preprocessor&quot;&gt;#import &lt;span class=&quot;hljs-title&quot;&gt;&quot;RoomListViewModel.h&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;hljs-preprocessor&quot;&gt;#import &lt;span class=&quot;hljs-title&quot;&gt;&amp;lt;EXTScope.h&amp;gt;&lt;/span&gt;&lt;/span&gt;

SpecBegin(RoomListViewModel)

describe(@&lt;span class=&quot;hljs-string&quot;&gt;&quot;RoomListViewModel&quot;&lt;/span&gt;, ^{

    __block RoomListViewModel *viewModel;
    __block &lt;span class=&quot;hljs-keyword&quot;&gt;id&lt;/span&gt; home;
    __block &lt;span class=&quot;hljs-keyword&quot;&gt;id&lt;/span&gt; room;

    beforeAll(^{

    });

    beforeEach(^{
        home = OCMClassMock([HMHome class]);
        room = OCMClassMock([HMRoom class]);
        viewModel = [[RoomListViewModel alloc] initWithHome:home];
    });

    it(@&lt;span class=&quot;hljs-string&quot;&gt;&quot;add room with name&quot;&lt;/span&gt;, ^{
        OCMStub([home addRoomWithName:OCMOCK_ANY completionHandler:OCMOCK_ANY])&lt;span class=&quot;hljs-variable&quot;&gt;.andDo&lt;/span&gt;(^(NSInvocation *invocation) {
            &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt;(^ __unsafe_unretained completionHandler)(HMRoom *room, &lt;span class=&quot;hljs-built_in&quot;&gt;NSError&lt;/span&gt; *error);
            [invocation getArgument:&amp;amp;completionHandler atIndex:&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;];
            completionHandler(room, &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt;);
        });    
        waitUntil(^(DoneCallback done) {
            @weakify(viewModel);
            [viewModel addRoomWithName:@&lt;span class=&quot;hljs-string&quot;&gt;&quot;test&quot;&lt;/span&gt; completionHandler:^(&lt;span class=&quot;hljs-built_in&quot;&gt;NSError&lt;/span&gt; *error) {
                @strongify(viewModel);
                expect(...);
                done();
            }];
        });

    });  

    afterEach(^{
        viewModel = &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt;;
    });

    afterAll(^{

    });
});

SpecEnd&lt;/code&gt;&lt;/pre&gt;



&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs perl&quot;&gt;void(^ __unsafe_unretained completionHandler)(HMRoom &lt;span class=&quot;hljs-variable&quot;&gt;*room&lt;/span&gt;, NSError &lt;span class=&quot;hljs-variable&quot;&gt;*error&lt;/span&gt;);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Why declare our block __unsafe_unretained?  &lt;br&gt;
See &lt;a href=&quot;http://stackoverflow.com/a/13831074/1060971&quot;&gt;http://stackoverflow.com/a/13831074/1060971&lt;/a&gt;,  Carl Lindberg’s comment.&lt;/p&gt;



&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs ini&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;[invocation getArgument:&amp;amp;completionHandler atIndex:3]&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In NSInvocation, argument index 0 is self , index 1 is cmd. &lt;br&gt;
First argument of addRoomWithName is at index 2, completion block argument is at index 3. &lt;br&gt;
So, assign our mock block at index 3.&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://vampirewalk.blogspot.com/feeds/6931972740090883635/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://vampirewalk.blogspot.com/2015/08/mock-completion-block-with-ocmock.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/6931972740090883635'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/6931972740090883635'/><link rel='alternate' type='text/html' href='http://vampirewalk.blogspot.com/2015/08/mock-completion-block-with-ocmock.html' title='Mock completion block with OCMock'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/17070298612568804458</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2840066036916532236.post-5887200444161644193</id><published>2015-08-06T10:21:00.001+08:00</published><updated>2015-08-06T10:21:31.182+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="iOS"/><title type='text'>Xcode6 + Swift 1.2 Podfile</title><content type='html'>&lt;p&gt;Swift 1.2 + RAC3&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs ruby&quot;&gt;platform &lt;span class=&quot;hljs-symbol&quot;&gt;:ios&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&quot;8.0&quot;&lt;/span&gt;
use_frameworks!

pod &lt;span class=&quot;hljs-string&quot;&gt;&quot;ReactiveCocoa&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&#39;3.0-RC.1&#39;&lt;/span&gt;

target &lt;span class=&quot;hljs-symbol&quot;&gt;:MyAppTests&lt;/span&gt;, &lt;span class=&quot;hljs-symbol&quot;&gt;:exclusive&lt;/span&gt; =&amp;gt; &lt;span class=&quot;hljs-keyword&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;do&lt;/span&gt;
  pod &lt;span class=&quot;hljs-string&quot;&gt;&#39;Quick&#39;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&#39;0.3.1&#39;&lt;/span&gt;
  pod &lt;span class=&quot;hljs-string&quot;&gt;&#39;Nimble&#39;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&#39;1.0.0&#39;&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://vampirewalk.blogspot.com/feeds/5887200444161644193/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://vampirewalk.blogspot.com/2015/08/xcode6-swift-12-podfile.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/5887200444161644193'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/5887200444161644193'/><link rel='alternate' type='text/html' href='http://vampirewalk.blogspot.com/2015/08/xcode6-swift-12-podfile.html' title='Xcode6 + Swift 1.2 Podfile'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/17070298612568804458</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2840066036916532236.post-2250915815822773760</id><published>2015-07-22T09:27:00.001+08:00</published><updated>2015-07-22T09:29:54.246+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Mac"/><category scheme="http://www.blogger.com/atom/ns#" term="MP4"/><title type='text'>在Mac下開發MP4的相關資源</title><content type='html'>&lt;h1 id=&quot;簡介&quot;&gt;簡介&lt;/h1&gt;

&lt;p&gt;MP4只是一種container，可以想像成容器，裡面可以放mp3或aac等音樂。 &lt;br&gt;
關於MP4格式的spec可以在&lt;a href=&quot;https://github.com/bharathwaaj/sandbox/raw/master/Programming%20books/TrickPlay%20related%20ISO%20Docs/H264/c041828_ISO_IEC_14496-12_2005%28E%29.pdf&quot;&gt;這裡下載&lt;/a&gt;。&lt;/p&gt;

&lt;h1 id=&quot;library&quot;&gt;Library&lt;/h1&gt;

&lt;p&gt;關於MP4檔案的操作，已經有現成的library可以使用囉～ &lt;br&gt;
&lt;a href=&quot;https://code.google.com/p/mp4v2/&quot;&gt;https://code.google.com/p/mp4v2/&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&quot;觀察mp4格式的工具&quot;&gt;觀察MP4格式的工具&lt;/h1&gt;

&lt;p&gt;可以藉由atomicparsley這個工具來印出MP4檔案的內部結構&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs lasso&quot;&gt;brew install atomicparsley
atomicparsley /path/&lt;span class=&quot;hljs-keyword&quot;&gt;to&lt;/span&gt;/mp4 &lt;span class=&quot;hljs-attribute&quot;&gt;-T&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;印出來的結果像這樣&lt;/p&gt;



&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs livecodeserver&quot;&gt;Atom ftyp @ &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;of&lt;/span&gt; size: &lt;span class=&quot;hljs-number&quot;&gt;24&lt;/span&gt;, &lt;span class=&quot;hljs-operator&quot;&gt;ends&lt;/span&gt; @ &lt;span class=&quot;hljs-number&quot;&gt;24&lt;/span&gt;
Atom moov @ &lt;span class=&quot;hljs-number&quot;&gt;24&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;of&lt;/span&gt; size: &lt;span class=&quot;hljs-number&quot;&gt;569&lt;/span&gt;, &lt;span class=&quot;hljs-operator&quot;&gt;ends&lt;/span&gt; @ &lt;span class=&quot;hljs-number&quot;&gt;593&lt;/span&gt;
     Atom mvhd @ &lt;span class=&quot;hljs-number&quot;&gt;32&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;of&lt;/span&gt; size: &lt;span class=&quot;hljs-number&quot;&gt;108&lt;/span&gt;, &lt;span class=&quot;hljs-operator&quot;&gt;ends&lt;/span&gt; @ &lt;span class=&quot;hljs-number&quot;&gt;140&lt;/span&gt;
     Atom iods @ &lt;span class=&quot;hljs-number&quot;&gt;140&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;of&lt;/span&gt; size: &lt;span class=&quot;hljs-number&quot;&gt;24&lt;/span&gt;, &lt;span class=&quot;hljs-operator&quot;&gt;ends&lt;/span&gt; @ &lt;span class=&quot;hljs-number&quot;&gt;164&lt;/span&gt;
     Atom trak @ &lt;span class=&quot;hljs-number&quot;&gt;164&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;of&lt;/span&gt; size: &lt;span class=&quot;hljs-number&quot;&gt;429&lt;/span&gt;, &lt;span class=&quot;hljs-operator&quot;&gt;ends&lt;/span&gt; @ &lt;span class=&quot;hljs-number&quot;&gt;593&lt;/span&gt;
         Atom tkhd @ &lt;span class=&quot;hljs-number&quot;&gt;172&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;of&lt;/span&gt; size: &lt;span class=&quot;hljs-number&quot;&gt;92&lt;/span&gt;, &lt;span class=&quot;hljs-operator&quot;&gt;ends&lt;/span&gt; @ &lt;span class=&quot;hljs-number&quot;&gt;264&lt;/span&gt;
         Atom mdia @ &lt;span class=&quot;hljs-number&quot;&gt;264&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;of&lt;/span&gt; size: &lt;span class=&quot;hljs-number&quot;&gt;329&lt;/span&gt;, &lt;span class=&quot;hljs-operator&quot;&gt;ends&lt;/span&gt; @ &lt;span class=&quot;hljs-number&quot;&gt;593&lt;/span&gt;
             Atom mdhd @ &lt;span class=&quot;hljs-number&quot;&gt;272&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;of&lt;/span&gt; size: &lt;span class=&quot;hljs-number&quot;&gt;32&lt;/span&gt;, &lt;span class=&quot;hljs-operator&quot;&gt;ends&lt;/span&gt; @ &lt;span class=&quot;hljs-number&quot;&gt;304&lt;/span&gt;
             Atom hdlr @ &lt;span class=&quot;hljs-number&quot;&gt;304&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;of&lt;/span&gt; size: &lt;span class=&quot;hljs-number&quot;&gt;33&lt;/span&gt;, &lt;span class=&quot;hljs-operator&quot;&gt;ends&lt;/span&gt; @ &lt;span class=&quot;hljs-number&quot;&gt;337&lt;/span&gt;
             Atom minf @ &lt;span class=&quot;hljs-number&quot;&gt;337&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;of&lt;/span&gt; size: &lt;span class=&quot;hljs-number&quot;&gt;256&lt;/span&gt;, &lt;span class=&quot;hljs-operator&quot;&gt;ends&lt;/span&gt; @ &lt;span class=&quot;hljs-number&quot;&gt;593&lt;/span&gt;
                 Atom smhd @ &lt;span class=&quot;hljs-number&quot;&gt;345&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;of&lt;/span&gt; size: &lt;span class=&quot;hljs-number&quot;&gt;16&lt;/span&gt;, &lt;span class=&quot;hljs-operator&quot;&gt;ends&lt;/span&gt; @ &lt;span class=&quot;hljs-number&quot;&gt;361&lt;/span&gt;
                 Atom dinf @ &lt;span class=&quot;hljs-number&quot;&gt;361&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;of&lt;/span&gt; size: &lt;span class=&quot;hljs-number&quot;&gt;36&lt;/span&gt;, &lt;span class=&quot;hljs-operator&quot;&gt;ends&lt;/span&gt; @ &lt;span class=&quot;hljs-number&quot;&gt;397&lt;/span&gt;
                     Atom dref @ &lt;span class=&quot;hljs-number&quot;&gt;369&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;of&lt;/span&gt; size: &lt;span class=&quot;hljs-number&quot;&gt;28&lt;/span&gt;, &lt;span class=&quot;hljs-operator&quot;&gt;ends&lt;/span&gt; @ &lt;span class=&quot;hljs-number&quot;&gt;397&lt;/span&gt;
                         Atom url  @ &lt;span class=&quot;hljs-number&quot;&gt;385&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;of&lt;/span&gt; size: &lt;span class=&quot;hljs-number&quot;&gt;12&lt;/span&gt;, &lt;span class=&quot;hljs-operator&quot;&gt;ends&lt;/span&gt; @ &lt;span class=&quot;hljs-number&quot;&gt;397&lt;/span&gt;
                 Atom stbl @ &lt;span class=&quot;hljs-number&quot;&gt;397&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;of&lt;/span&gt; size: &lt;span class=&quot;hljs-number&quot;&gt;196&lt;/span&gt;, &lt;span class=&quot;hljs-operator&quot;&gt;ends&lt;/span&gt; @ &lt;span class=&quot;hljs-number&quot;&gt;593&lt;/span&gt;
                     Atom stsd @ &lt;span class=&quot;hljs-number&quot;&gt;405&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;of&lt;/span&gt; size: &lt;span class=&quot;hljs-number&quot;&gt;96&lt;/span&gt;, &lt;span class=&quot;hljs-operator&quot;&gt;ends&lt;/span&gt; @ &lt;span class=&quot;hljs-number&quot;&gt;501&lt;/span&gt;
                         Atom mp4a @ &lt;span class=&quot;hljs-number&quot;&gt;421&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;of&lt;/span&gt; size: &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;, &lt;span class=&quot;hljs-operator&quot;&gt;ends&lt;/span&gt; @ &lt;span class=&quot;hljs-number&quot;&gt;501&lt;/span&gt;
                             Atom esds @ &lt;span class=&quot;hljs-number&quot;&gt;457&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;of&lt;/span&gt; size: &lt;span class=&quot;hljs-number&quot;&gt;44&lt;/span&gt;, &lt;span class=&quot;hljs-operator&quot;&gt;ends&lt;/span&gt; @ &lt;span class=&quot;hljs-number&quot;&gt;501&lt;/span&gt;
                     Atom stts @ &lt;span class=&quot;hljs-number&quot;&gt;501&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;of&lt;/span&gt; size: &lt;span class=&quot;hljs-number&quot;&gt;24&lt;/span&gt;, &lt;span class=&quot;hljs-operator&quot;&gt;ends&lt;/span&gt; @ &lt;span class=&quot;hljs-number&quot;&gt;525&lt;/span&gt;
                     Atom stsz @ &lt;span class=&quot;hljs-number&quot;&gt;525&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;of&lt;/span&gt; size: &lt;span class=&quot;hljs-number&quot;&gt;20&lt;/span&gt;, &lt;span class=&quot;hljs-operator&quot;&gt;ends&lt;/span&gt; @ &lt;span class=&quot;hljs-number&quot;&gt;545&lt;/span&gt;
                     Atom stsc @ &lt;span class=&quot;hljs-number&quot;&gt;545&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;of&lt;/span&gt; size: &lt;span class=&quot;hljs-number&quot;&gt;28&lt;/span&gt;, &lt;span class=&quot;hljs-operator&quot;&gt;ends&lt;/span&gt; @ &lt;span class=&quot;hljs-number&quot;&gt;573&lt;/span&gt;
                     Atom stco @ &lt;span class=&quot;hljs-number&quot;&gt;573&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;of&lt;/span&gt; size: &lt;span class=&quot;hljs-number&quot;&gt;20&lt;/span&gt;, &lt;span class=&quot;hljs-operator&quot;&gt;ends&lt;/span&gt; @ &lt;span class=&quot;hljs-number&quot;&gt;593&lt;/span&gt;
Atom mdat @ &lt;span class=&quot;hljs-number&quot;&gt;593&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;of&lt;/span&gt; size: &lt;span class=&quot;hljs-number&quot;&gt;9&lt;/span&gt;, &lt;span class=&quot;hljs-operator&quot;&gt;ends&lt;/span&gt; @ &lt;span class=&quot;hljs-number&quot;&gt;602&lt;/span&gt;
&lt;span class=&quot;hljs-comment&quot;&gt;------------------------------------------------------&lt;/span&gt;
Total size: &lt;span class=&quot;hljs-number&quot;&gt;602&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;bytes&lt;/span&gt;; &lt;span class=&quot;hljs-number&quot;&gt;22&lt;/span&gt; atoms total.
Media data: &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;bytes&lt;/span&gt;; &lt;span class=&quot;hljs-number&quot;&gt;602&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;bytes&lt;/span&gt; all other atoms (&lt;span class=&quot;hljs-number&quot;&gt;100.000&lt;/span&gt;% atom overhead).
Total free atom &lt;span class=&quot;hljs-constant&quot;&gt;space&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;bytes&lt;/span&gt;; &lt;span class=&quot;hljs-number&quot;&gt;0.000&lt;/span&gt;% waste.
&lt;span class=&quot;hljs-comment&quot;&gt;------------------------------------------------------&lt;/span&gt;
AtomicParsley &lt;span class=&quot;hljs-built_in&quot;&gt;version&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;0.9&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.6&lt;/span&gt; (utf8)
&lt;span class=&quot;hljs-comment&quot;&gt;------------------------------------------------------&lt;/span&gt;
Movie duration: &lt;span class=&quot;hljs-number&quot;&gt;7504.597&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;seconds&lt;/span&gt; (&lt;span class=&quot;hljs-number&quot;&gt;02&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;05&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;04.60&lt;/span&gt;) - &lt;span class=&quot;hljs-number&quot;&gt;0.00&lt;/span&gt;* kbp/&lt;span class=&quot;hljs-built_in&quot;&gt;sec&lt;/span&gt; bitrate (*=approximate)
Low-level details. Total tracks: &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;
Trk  Type  Handler                    Kind  Lang  Bytes
&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;    soun  [&lt;span class=&quot;hljs-constant&quot;&gt;none&lt;/span&gt; listed]              mp4a  und   &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;
     &lt;span class=&quot;hljs-number&quot;&gt;0.00&lt;/span&gt;* kbp/s  &lt;span class=&quot;hljs-number&quot;&gt;7504.597&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;sec&lt;/span&gt;  MPEG-&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt; Unknown profile: &lt;span class=&quot;hljs-number&quot;&gt;0x0&lt;/span&gt;    channels: (&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;這個用python寫的工具也是不錯的選擇 &lt;br&gt;
&lt;a href=&quot;https://github.com/amarghosh/mp4viewer&quot;&gt;https://github.com/amarghosh/mp4viewer&lt;/a&gt; &lt;br&gt;
&lt;img src=&quot;https://camo.githubusercontent.com/ed710da52ddda72336273228a9327cccf949d752/687474703a2f2f332e62702e626c6f6773706f742e636f6d2f2d4150622d344c7345394c4d2f556b556f6f6d65345534492f414141414141414144466b2f5a6b547064374a6b4632342f73313630302f6d70347669657765725f7368656c6c2e706e67&quot; alt=&quot;mp4Viewer&quot; title=&quot;&quot;&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://vampirewalk.blogspot.com/feeds/2250915815822773760/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://vampirewalk.blogspot.com/2015/07/macmp4.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/2250915815822773760'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/2250915815822773760'/><link rel='alternate' type='text/html' href='http://vampirewalk.blogspot.com/2015/07/macmp4.html' title='在Mac下開發MP4的相關資源'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/17070298612568804458</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2840066036916532236.post-1481552656823781800</id><published>2015-03-10T14:09:00.001+08:00</published><updated>2015-03-10T14:09:52.311+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="iOS"/><title type='text'>讓Alcatraz支援Xcode 6.2</title><content type='html'>&lt;ol&gt;
&lt;li&gt;打開Finder，跳到~/Library/Application Support/Developer/Shared/Xcode/Plug-ins&lt;/li&gt;
&lt;li&gt;右鍵點plugin，顯示套件內容&lt;/li&gt;
&lt;li&gt;打開Info.plist&lt;/li&gt;
&lt;li&gt;在DVTPlugInCompatibilityUUIDs的Array加入&lt;code&gt;A16FF353-8441-459E-A50C-B071F53F51B7&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;重啟Xcode&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;參考：&lt;a href=&quot;https://github.com/supermarin/Alcatraz/issues/218&quot;&gt;https://github.com/supermarin/Alcatraz/issues/218&lt;/a&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://vampirewalk.blogspot.com/feeds/1481552656823781800/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://vampirewalk.blogspot.com/2015/03/alcatrazxcode-62.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/1481552656823781800'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/1481552656823781800'/><link rel='alternate' type='text/html' href='http://vampirewalk.blogspot.com/2015/03/alcatrazxcode-62.html' title='讓Alcatraz支援Xcode 6.2'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/17070298612568804458</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2840066036916532236.post-7647406471300002615</id><published>2015-02-11T09:32:00.001+08:00</published><updated>2015-02-11T09:32:06.977+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="iOS"/><category scheme="http://www.blogger.com/atom/ns#" term="MobileVLCKit"/><category scheme="http://www.blogger.com/atom/ns#" term="objective-c"/><category scheme="http://www.blogger.com/atom/ns#" term="VLC"/><title type='text'>支援眾多video與audio格式的MobileVLCKit</title><content type='html'>&lt;h1 id=&quot;支援格式&quot;&gt;支援格式&lt;/h1&gt;

&lt;p&gt;支援的video格式&lt;a href=&quot;https://www.videolan.org/vlc/features.php?cat=video&quot;&gt;https://www.videolan.org/vlc/features.php?cat=video&lt;/a&gt; &lt;br&gt;
支援的audio格式&lt;a href=&quot;https://www.videolan.org/vlc/features.php?cat=audio&quot;&gt;https://www.videolan.org/vlc/features.php?cat=audio&lt;/a&gt;&lt;/p&gt;



&lt;h1 id=&quot;安裝方式&quot;&gt;安裝方式&lt;/h1&gt;

&lt;p&gt;By CocoaPods&lt;/p&gt;



&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs bash&quot;&gt;pod &lt;span class=&quot;hljs-string&quot;&gt;&#39;MobileVLCKit&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;從night build下載 &lt;br&gt;
&lt;a href=&quot;http://nightlies.videolan.org/build/ios/&quot;&gt;http://nightlies.videolan.org/build/ios/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Build source code，使用-f參數build出包含所有arch的framework&lt;/p&gt;



&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs bash&quot;&gt;./buildMobileVLCKit.sh &lt;span class=&quot;hljs-operator&quot;&gt;-f&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a href=&quot;https://wiki.videolan.org/VLCKit/#Building_the_framework_for_iOS&quot;&gt;https://wiki.videolan.org/VLCKit/#Building_the_framework_for_iOS&lt;/a&gt;&lt;/p&gt;



&lt;h1 id=&quot;sample-code&quot;&gt;Sample Code&lt;/h1&gt;

&lt;p&gt;參考範例DropIn-Player &lt;a href=&quot;http://cl.ly/0G2Y2M1R1X3U&quot;&gt;http://cl.ly/0G2Y2M1R1X3U&lt;/a&gt;&lt;/p&gt;



&lt;h1 id=&quot;初始化&quot;&gt;初始化&lt;/h1&gt;

&lt;p&gt;記得引用MobileVLCKit的原始檔要從.m改為.mm，這樣編譯才不會出錯。&lt;/p&gt;



&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs coffeescript&quot;&gt;&lt;span class=&quot;hljs-regexp&quot;&gt;//&lt;/span&gt; Set up a videoView &lt;span class=&quot;hljs-keyword&quot;&gt;by&lt;/span&gt; hand. You can also &lt;span class=&quot;hljs-keyword&quot;&gt;do&lt;/span&gt; that &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; the nib file
   videoView = [[VLCVideoView alloc] &lt;span class=&quot;hljs-attribute&quot;&gt;initWithFrame&lt;/span&gt;:[[&lt;span class=&quot;hljs-built_in&quot;&gt;window&lt;/span&gt; contentView] bounds]];
   [[&lt;span class=&quot;hljs-built_in&quot;&gt;window&lt;/span&gt; contentView] &lt;span class=&quot;hljs-attribute&quot;&gt;addSubview&lt;/span&gt;:videoView];
   [videoView &lt;span class=&quot;hljs-attribute&quot;&gt;setAutoresizingMask&lt;/span&gt;: NSViewHeightSizable|NSViewWidthSizable];

   &lt;span class=&quot;hljs-regexp&quot;&gt;//&lt;/span&gt; Init the player object
   player = [[VLCMediaPlayer alloc] &lt;span class=&quot;hljs-attribute&quot;&gt;initWithVideoView&lt;/span&gt;:videoView];
   VLCMedia *media = [VLCMedia &lt;span class=&quot;hljs-attribute&quot;&gt;mediaWithPath&lt;/span&gt;:@&lt;span class=&quot;hljs-string&quot;&gt;&quot;/to/my/movie&quot;&lt;/span&gt;];
   &lt;span class=&quot;hljs-regexp&quot;&gt;//&lt;/span&gt;設置delegate等一下可以知道歌曲有多長
   media.delegate = self;
   [player &lt;span class=&quot;hljs-attribute&quot;&gt;setMedia&lt;/span&gt;:media];
   [player play];&lt;/code&gt;&lt;/pre&gt;



&lt;h1 id=&quot;控制播放進度progress&quot;&gt;控制播放進度(progress)&lt;/h1&gt;

&lt;p&gt;progressValue為UISlider傳過來的值&lt;/p&gt;



&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs objectivec&quot;&gt;- (&lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt;)seek:(&lt;span class=&quot;hljs-keyword&quot;&gt;float&lt;/span&gt;) progressValue
{
    [&lt;span class=&quot;hljs-keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;.mediaPlayer&lt;/span&gt; setPosition:progressValue];
}&lt;/code&gt;&lt;/pre&gt;



&lt;h1 id=&quot;顯示目前播放進度&quot;&gt;顯示目前播放進度&lt;/h1&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs css&quot;&gt;&lt;span class=&quot;hljs-attr_selector&quot;&gt;[[NSNotificationCenter defaultCenter]&lt;/span&gt; &lt;span class=&quot;hljs-tag&quot;&gt;addObserver&lt;/span&gt;&lt;span class=&quot;hljs-pseudo&quot;&gt;:self&lt;/span&gt; &lt;span class=&quot;hljs-tag&quot;&gt;selector&lt;/span&gt;:&lt;span class=&quot;hljs-at_rule&quot;&gt;@&lt;span class=&quot;hljs-keyword&quot;&gt;selector(mediaPlayerTimeChanged:)&lt;/span&gt; name:VLCMediaPlayerTimeChanged object:nil]&lt;/span&gt;;&lt;/code&gt;&lt;/pre&gt;



&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs objectivec&quot;&gt;- (&lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt;)mediaPlayerTimeChanged:(&lt;span class=&quot;hljs-built_in&quot;&gt;NSNotification&lt;/span&gt; *)aNotification
{
    &lt;span class=&quot;hljs-keyword&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;.playbackTime&lt;/span&gt; = [_player&lt;span class=&quot;hljs-variable&quot;&gt;.time&lt;/span&gt; stringValue];
}&lt;/code&gt;&lt;/pre&gt;

&lt;h1 id=&quot;獲取duration&quot;&gt;獲取duration&lt;/h1&gt;

&lt;p&gt;如果有把player裡面的VLCMedia設置delegate的話，就會收到通知&lt;/p&gt;



&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs erlang&quot;&gt;&lt;span class=&quot;hljs-pp&quot;&gt;- &lt;span class=&quot;hljs-params&quot;&gt;(void)&lt;/span&gt;mediaDidFinishParsing:&lt;span class=&quot;hljs-params&quot;&gt;(&lt;span class=&quot;hljs-variable&quot;&gt;VLCMedia&lt;/span&gt; *)&lt;/span&gt;aMedia
{
    //更新duration
}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;



&lt;h1 id=&quot;監控狀態&quot;&gt;監控狀態&lt;/h1&gt;



&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs css&quot;&gt;&lt;span class=&quot;hljs-attr_selector&quot;&gt;[[NSNotificationCenter defaultCenter]&lt;/span&gt; &lt;span class=&quot;hljs-tag&quot;&gt;addObserver&lt;/span&gt;&lt;span class=&quot;hljs-pseudo&quot;&gt;:self&lt;/span&gt; &lt;span class=&quot;hljs-tag&quot;&gt;selector&lt;/span&gt;:&lt;span class=&quot;hljs-at_rule&quot;&gt;@&lt;span class=&quot;hljs-keyword&quot;&gt;selector(mediaPlayerStateChanged:)&lt;/span&gt; name:VLCMediaPlayerStateChanged object:nil]&lt;/span&gt;;&lt;/code&gt;&lt;/pre&gt;



&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs objectivec&quot;&gt;- (&lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt;)mediaPlayerStateChanged:(&lt;span class=&quot;hljs-built_in&quot;&gt;NSNotification&lt;/span&gt; *)aNotification
{
    VLCMediaPlayerState state;
    &lt;span class=&quot;hljs-keyword&quot;&gt;switch&lt;/span&gt; (state) {
        &lt;span class=&quot;hljs-keyword&quot;&gt;case&lt;/span&gt; VLCMediaPlayerStatePaused:
            &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;;

        &lt;span class=&quot;hljs-keyword&quot;&gt;case&lt;/span&gt; VLCMediaPlayerStateStopped:
            &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;;

        &lt;span class=&quot;hljs-keyword&quot;&gt;case&lt;/span&gt; VLCMediaPlayerStateBuffering:
            &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;;

        &lt;span class=&quot;hljs-keyword&quot;&gt;case&lt;/span&gt; VLCMediaPlayerStatePlaying:
            &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;;

        &lt;span class=&quot;hljs-keyword&quot;&gt;case&lt;/span&gt; VLCMediaPlayerStateEnded:
            &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;;

        &lt;span class=&quot;hljs-keyword&quot;&gt;case&lt;/span&gt; VLCMediaPlayerStateError:
            &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;;

        &lt;span class=&quot;hljs-keyword&quot;&gt;default&lt;/span&gt;:
            &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;;
    }
}&lt;/code&gt;&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://vampirewalk.blogspot.com/feeds/7647406471300002615/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://vampirewalk.blogspot.com/2015/02/videoaudiomobilevlckit.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/7647406471300002615'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/7647406471300002615'/><link rel='alternate' type='text/html' href='http://vampirewalk.blogspot.com/2015/02/videoaudiomobilevlckit.html' title='支援眾多video與audio格式的MobileVLCKit'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/17070298612568804458</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2840066036916532236.post-7445908801189003320</id><published>2015-01-31T16:46:00.001+08:00</published><updated>2015-05-05T17:45:41.306+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="iOS"/><category scheme="http://www.blogger.com/atom/ns#" term="objective-c"/><title type='text'>在iOS上開發UPnP相關App的資源</title><content type='html'>&lt;p&gt;說實在的iOS上的UPnP資源有夠難找，大概是因為比較少人做的關係吧，加上如果下錯關鍵字保證是找好幾天找不到什麼東西，就算找到了也不知道能不能達成自己需要的功能，因此就產生了這一篇，希望幫助那些仍在迷途中的靈魂們。&lt;/p&gt;



&lt;h1 id=&quot;upnp-control-point-library&quot;&gt;UPnP Control Point Library&lt;/h1&gt;

&lt;p&gt;顧名思義這邊列出的library主要是做control point的&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/cybergarage/CyberLink4C&quot;&gt;CyberLink4C&lt;/a&gt; &lt;br&gt;
用C語言實現的library，有提供objective-c的wrapper，但並沒有包含全部功能，例如event的部份就需要使用到c api。&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://sourceforge.net/projects/platinum/&quot;&gt;Platinum&lt;/a&gt; &lt;br&gt;
這是一個以C++實現的解決方案，一樣有提供objective-c的wrapper，control point跟DMS都可以做。注意這個library預設是GPL授權的，如果商業使用需要申請商業授權。&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/fkuehne/upnpx&quot;&gt;upnpx&lt;/a&gt; &lt;br&gt;
核心是C++，加上Objective-C API。VLC for iOS使用了這套library。年代有點久遠，不過堪用。簡單範例可以參考&lt;a href=&quot;https://github.com/basti2310/upnpx-classes&quot;&gt;https://github.com/basti2310/upnpx-classes&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;個人推薦程度 Platinum &amp;gt; upnpx &amp;gt; CyberLink4C&lt;/p&gt;

&lt;p&gt;Edit: &lt;br&gt;
兩個新library &lt;br&gt;
&lt;a href=&quot;https://github.com/master-nevi/UPnAtom&quot;&gt;UPnAtom&lt;/a&gt; &lt;br&gt;
使用swift實現的版本，可以用在Objective-C以及swift專案，目前swift變動很快，production環境不建議使用這個library。&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/arcam/CocoaUPnP&quot;&gt;CocoaUPnP&lt;/a&gt; &lt;br&gt;
某個開發者因為upnpx無法滿足需求而自己寫的新library，還在非常早期的階段。&lt;/p&gt;

&lt;h1 id=&quot;upnp-media-server&quot;&gt;UPnP Media Server&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;http://sourceforge.net/projects/platinum/&quot;&gt;Platinum&lt;/a&gt; &lt;br&gt;
很多App的Local DMS都是用這套做的，應該沒什麼大問題。 &lt;br&gt;
&lt;a href=&quot;https://github.com/Coevotech/coevo-upnp-server&quot;&gt;coevo-upnp-server&lt;/a&gt; &lt;br&gt;
這個source只能當參考用，年代已經有點久遠，而且裡面有非常多的bug，相信光是要掃雷就會花掉很多時間。&lt;/p&gt;

&lt;p&gt;個人推薦程度 Platinum &amp;gt; coevo-upnp-server&lt;/p&gt;

&lt;p&gt;順便附上用Platinum做DMS的demo project &lt;br&gt;
&lt;a href=&quot;https://github.com/vampirewalk/MediaServer&quot;&gt;https://github.com/vampirewalk/MediaServer&lt;/a&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://vampirewalk.blogspot.com/feeds/7445908801189003320/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://vampirewalk.blogspot.com/2015/01/iosupnpapp.html#comment-form' title='4 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/7445908801189003320'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/7445908801189003320'/><link rel='alternate' type='text/html' href='http://vampirewalk.blogspot.com/2015/01/iosupnpapp.html' title='在iOS上開發UPnP相關App的資源'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/17070298612568804458</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2840066036916532236.post-1053877011411362953</id><published>2015-01-29T19:03:00.001+08:00</published><updated>2015-01-31T16:10:36.092+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="iOS"/><title type='text'>Realm 0.89.0先期研究</title><content type='html'>&lt;p&gt;近期出現了Realm這個新的mobile database，先做點筆記。 &lt;br&gt;
Document: &lt;a href=&quot;http://realm.io/docs/cocoa/0.89.0/&quot;&gt;http://realm.io/docs/cocoa/0.89.0/&lt;/a&gt;&lt;/p&gt;



&lt;h1 id=&quot;subclass-rlmobject&quot;&gt;Subclass RLMObject&lt;/h1&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs objectivec&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// Dog.h&lt;/span&gt;
 &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;@interface&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Dog&lt;/span&gt; : &lt;span class=&quot;hljs-title&quot;&gt;RLMObject&lt;/span&gt;&lt;/span&gt;
 &lt;span class=&quot;hljs-keyword&quot;&gt;@property&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;NSString&lt;/span&gt; *name;
 &lt;span class=&quot;hljs-keyword&quot;&gt;@property&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;BOOL&lt;/span&gt;      adopted;
 &lt;span class=&quot;hljs-keyword&quot;&gt;@end&lt;/span&gt;

 &lt;span class=&quot;hljs-comment&quot;&gt;// Dog.m&lt;/span&gt;
 &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;@implementation&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Dog&lt;/span&gt;&lt;/span&gt;
 &lt;span class=&quot;hljs-keyword&quot;&gt;@end&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;//none needed&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;目前Model物件必須subclass RLMObject。RLMObject只能在創建它的thread內使用。&lt;/p&gt;



&lt;h1 id=&quot;supported-property-types&quot;&gt;Supported property types&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;NSString&lt;/strong&gt; &lt;br&gt;
&lt;strong&gt;NSInteger&lt;/strong&gt;, &lt;strong&gt;CGFloat&lt;/strong&gt;, &lt;strong&gt;int&lt;/strong&gt;, &lt;strong&gt;long&lt;/strong&gt;, &lt;strong&gt;float&lt;/strong&gt;, and &lt;strong&gt;double&lt;/strong&gt; &lt;br&gt;
&lt;strong&gt;BOOL&lt;/strong&gt; or bool &lt;br&gt;
&lt;strong&gt;NSDate&lt;/strong&gt; &lt;br&gt;
&lt;strong&gt;NSData&lt;/strong&gt; &lt;br&gt;
&lt;strong&gt;RLMObject&lt;/strong&gt; subclasses, so you can have many-to-one relationships. &lt;br&gt;
&lt;strong&gt;RLMArray&lt;/strong&gt; &amp;lt; X &amp;gt;, where X is an RLMObject subclass, so you can have many-to-many relationships.&lt;/p&gt;

&lt;h1 id=&quot;write&quot;&gt;Write&lt;/h1&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs sql&quot;&gt;// &lt;span class=&quot;hljs-operator&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Create&lt;/span&gt; object
Person *author = [[Person alloc] init];&lt;/span&gt;
author.name    = @&quot;David Foster Wallace&quot;;

// Get the default Realm
RLMRealm *realm = [RLMRealm defaultRealm];
// You only need to &lt;span class=&quot;hljs-operator&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;do&lt;/span&gt; this once (per thread)

// &lt;span class=&quot;hljs-keyword&quot;&gt;Add&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;to&lt;/span&gt; Realm &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;transaction&lt;/span&gt;
[realm beginWriteTransaction];&lt;/span&gt;
[realm addObject:author];
[realm commitWriteTransaction];

// &lt;span class=&quot;hljs-operator&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;Update&lt;/span&gt; an object &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt; a &lt;span class=&quot;hljs-keyword&quot;&gt;transaction&lt;/span&gt;
[realm beginWriteTransaction];&lt;/span&gt;
author.name = @&quot;Thomas Pynchon&quot;;
[realm commitWriteTransaction];&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;所有對物件的新增修改刪除都必須包在WriteTransaction裡，因為在RLMObject裏的所有ivar都是跟資料庫直接相連的，而不是一般我們習慣的memory。&lt;a href=&quot;http://stackoverflow.com/a/25002895/1060971&quot;&gt;http://stackoverflow.com/a/25002895/1060971&lt;/a&gt; 說明了所有對物件property的修改都會被同步進database。&lt;/p&gt;



&lt;h1 id=&quot;primarykey&quot;&gt;PrimaryKey&lt;/h1&gt;

&lt;p&gt;在設計Model物件時，PrimaryKey絕對是不可或缺的property之一。在不同的thread之間無法互相傳遞RLMObject使用，因為RLMObject只能在創建它的thread內使用。所以我們只能透過在非main thread查詢到物件的PrimaryKey，然後把PrimaryKey傳到main thread，然後再&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs ini&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;[MyObject objectsWhere:&quot;primaryId IN %@&quot;, idArray]&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;獲得一個新的RLMObject，然後才在main thread使用這個新的RLMObject。 &lt;br&gt;
參考：&lt;a href=&quot;https://groups.google.com/d/msg/realm-cocoa/naRBh-WMet0/ONPvTCGaSUkJ&quot;&gt;https://groups.google.com/d/msg/realm-cocoa/naRBh-WMet0/ONPvTCGaSUkJ&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;產生primary key的方式常見有兩種，一是流水號，二是uuid。 &lt;br&gt;
產生流水號的method在multi-thread環境下記得保證其thread-safe，否則很可能會產生相同的流水號。 &lt;br&gt;
uuid的話，在multi-thread環境下直接產生就好，因為衝突機率很小。&lt;/p&gt;



&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs css&quot;&gt;&lt;span class=&quot;hljs-attr_selector&quot;&gt;[[NSUUID UUID]&lt;/span&gt; &lt;span class=&quot;hljs-tag&quot;&gt;UUIDString&lt;/span&gt;];&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;參考：&lt;a href=&quot;http://stackoverflow.com/a/26257616/1060971&quot;&gt;http://stackoverflow.com/a/26257616/1060971&lt;/a&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://vampirewalk.blogspot.com/feeds/1053877011411362953/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://vampirewalk.blogspot.com/2015/01/realm-0890.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/1053877011411362953'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/1053877011411362953'/><link rel='alternate' type='text/html' href='http://vampirewalk.blogspot.com/2015/01/realm-0890.html' title='Realm 0.89.0先期研究'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/17070298612568804458</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2840066036916532236.post-5228984654043823716</id><published>2015-01-29T18:58:00.001+08:00</published><updated>2015-01-29T18:58:58.031+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="iOS"/><title type='text'>Multi async task completion block</title><content type='html'>&lt;p&gt;假設現在有一些task需要去執行，在method裡面我們想等所有task完成再call completionBlock，那麼可以分兩種情況 &lt;br&gt;
1. task是synchronous的 &lt;br&gt;
2. task是asynchronous的&lt;/p&gt;

&lt;p&gt;1比較好解決，用NSOperationQueue加dependency就OK了，2的話需要用到dispatch_group_t group。&lt;/p&gt;

&lt;p&gt;範例：AVAssetExportSession的exportAsynchronouslyWithCompletionHandler方法是用來把iPod Library中的音樂轉成檔案用的。&lt;/p&gt;



&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs erlang&quot;&gt;&lt;span class=&quot;hljs-pp&quot;&gt;- &lt;span class=&quot;hljs-params&quot;&gt;(void)&lt;/span&gt;exportAsynchronouslyWithCompletionHandler:&lt;span class=&quot;hljs-params&quot;&gt;(void (^)&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(void)&lt;/span&gt;)handler;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;現在我們選擇了一批歌曲轉出，想要在全部歌曲轉完之後收到通知並呈現UI，但是AVAssetExportSession不提供一次轉多個歌曲，我們只能知道個別task完成的時間，但是不知道哪時候全部完成，那麼要如何在全部轉完之後才收到通知呢？ &lt;br&gt;
這時候就可以使用dispatch_group_t group等待group裡的task統統完成再執行收尾工作。&lt;/p&gt;



&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs r&quot;&gt;- (void) convertMediaItemsToMp3:(MPMediaItemCollection *) collection completionBlock:(void(^)()) block
dispatch_group_t group = dispatch_group_create();

    NSArray *songs = collection.items;
    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (MPMediaItem *song &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; songs) {

        dispatch_group_enter(group);

        AVAssetExportSession *exporter = [[AVAssetExportSession alloc]
                                      initWithAsset:asset
                                      presetName: AVAssetExportPresetAppleM4A];
        exporter.outputFileType = @&lt;span class=&quot;hljs-string&quot;&gt;&quot;com.apple.m4a-audio&quot;&lt;/span&gt;;
        exporter.outputURL = &lt;span class=&quot;hljs-keyword&quot;&gt;...&lt;/span&gt;; 

        [exporter exportAsynchronouslyWithCompletionHandler:^{
            dispatch_group_leave(group);
        }];
    }
    dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;), ^{
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (block) {
            block();
        }
    });&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a href=&quot;http://stackoverflow.com/a/20910658/1060971&quot;&gt;http://stackoverflow.com/a/20910658/1060971&lt;/a&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://vampirewalk.blogspot.com/feeds/5228984654043823716/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://vampirewalk.blogspot.com/2015/01/multi-async-task-completion-block.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/5228984654043823716'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/5228984654043823716'/><link rel='alternate' type='text/html' href='http://vampirewalk.blogspot.com/2015/01/multi-async-task-completion-block.html' title='Multi async task completion block'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/17070298612568804458</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2840066036916532236.post-2850235594609085178</id><published>2015-01-16T14:49:00.001+08:00</published><updated>2015-01-16T14:49:27.558+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="iOS"/><title type='text'>使用Instrument找出被retain無法釋放的instance</title><content type='html'>&lt;p&gt;使用⌘+I叫出Instrument &lt;br&gt;
選擇allocation &lt;br&gt;
&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVwOGZD3a8-yFGY7tXAM93E0jckEWCl3JsxjYBm66NIlgIbAXv78psi7T1HEypMmrzSg9bm53SMtd8tQZ1rI-sYeW3bnGYqH96q3dOIsMiJkWnkHL999-yPnzTO_Mvgw4FfaDFA80NiiX1/s0/%E8%9E%A2%E5%B9%95%E5%BF%AB%E7%85%A7+2015-01-16+%E4%B8%8B%E5%8D%882.24.52.png&quot; alt=&quot;allocation&quot; title=&quot;螢幕快照 2015-01-16 下午2.24.52.png&quot;&gt;&lt;/p&gt;

&lt;p&gt;看右邊的面板，勾選Record reference counts &lt;br&gt;
&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2iyvjcWTagBPhRFiQWAoU8wDgoJQqPvX9i_IwWHFRlMCDftvzAHxD3OIKeP_N5fItgC1jsKXR4d5WLovoONOXhHcaGWgd1tfIMi8wz9xi0kl1oHgVWjcF78n9Pwo_LA7YukCixw3EvJoT/s0/%E8%9E%A2%E5%B9%95%E5%BF%AB%E7%85%A7+2015-01-16+%E4%B8%8B%E5%8D%882.25.11.png&quot; alt=&quot;Record reference counts&quot; title=&quot;螢幕快照 2015-01-16 下午2.25.11.png&quot;&gt;&lt;/p&gt;

&lt;p&gt;然後開始檢測程式，執行那些你懷疑有問題的動作。執行完後在搜尋框輸入你要找的Class名稱。 &lt;br&gt;
滑鼠移到在Category那欄的物件名稱後面會有小箭頭，點進去，出現所有instance，再找要研究的instance一樣點小箭頭。 &lt;br&gt;
&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQiXskbv_Fk3mJdUJounqzbT677Fsl2nIXlT6o3X5i-saRXhyphenhyphenyftZHrrBOp85RIHClD7f8ipw_Tw72Jtk7I_bvqKsiNOT_poxqCtQ9w61hVbHfFqX4jCWKnwdwPo7mww5sTselCnDNDdJi/s0/%E8%9E%A2%E5%B9%95%E5%BF%AB%E7%85%A7+2015-01-16+%E4%B8%8B%E5%8D%882.34.24.png&quot; alt=&quot;Search&quot; title=&quot;search&quot;&gt;&lt;/p&gt;

&lt;p&gt;進去之後會出現所有retain跟release的紀錄，上方標籤選unpaired可以列出沒有成對的retain或是release。 &lt;br&gt;
選擇懷疑有問題的那一行，在右邊面板選擇第三個頁籤，可以看call stack。 &lt;br&gt;
&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyLGGZR10Fp24UiFkefNUy29NhQE1YjKvsxl8y8WVCHHTLmbLExHx00I-dbJSyM8S9Z3yR2mzwAU5vYO5Yo_5X-Vt20mZuNXDDbxy1Emzq_A3x5ZLvJAGPdLDMGS9bnpTyzG24NnciwU0h/s0/%E8%9E%A2%E5%B9%95%E5%BF%AB%E7%85%A7+2015-01-16+%E4%B8%8B%E5%8D%882.34.46.png&quot; alt=&quot;reference count&quot; title=&quot;螢幕快照 2015-01-16 下午2.34.46.png&quot;&gt;&lt;/p&gt;

&lt;p&gt;這次我遇到的問題是KVOController的block retain自己所在的instance，下次要記得unobserve。 &lt;br&gt;
還有使用[[FBKVOController alloc] initWithObserver:self retainObserved:NO]才不會retain被觀察的物件。&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://vampirewalk.blogspot.com/feeds/2850235594609085178/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://vampirewalk.blogspot.com/2015/01/instrumentretaininstance.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/2850235594609085178'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/2850235594609085178'/><link rel='alternate' type='text/html' href='http://vampirewalk.blogspot.com/2015/01/instrumentretaininstance.html' title='使用Instrument找出被retain無法釋放的instance'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/17070298612568804458</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVwOGZD3a8-yFGY7tXAM93E0jckEWCl3JsxjYBm66NIlgIbAXv78psi7T1HEypMmrzSg9bm53SMtd8tQZ1rI-sYeW3bnGYqH96q3dOIsMiJkWnkHL999-yPnzTO_Mvgw4FfaDFA80NiiX1/s72-c/%E8%9E%A2%E5%B9%95%E5%BF%AB%E7%85%A7+2015-01-16+%E4%B8%8B%E5%8D%882.24.52.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2840066036916532236.post-5440388012980315956</id><published>2014-12-31T16:37:00.001+08:00</published><updated>2014-12-31T16:38:28.223+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="iOS"/><title type='text'>在iOS專案引入外部Library的另一種選擇 - git subtree</title><content type='html'>&lt;h1 id=&quot;cocoapods&quot;&gt;CocoaPods&lt;/h1&gt;

&lt;p&gt;CocoaPods可說是目前iOS coder之間最流行的module管理方式，CocoaPods非常適合那些自己很少去維護的外部library，通常都是等別人更新完之後自己下pod update更新。但是當我們也需要經常性的去維護這個library時，我們需要在另外一個git repository修改，然後在自己的專案下pod update指令更新，實在很麻煩！&lt;/p&gt;

&lt;h1 id=&quot;git-subtree&quot;&gt;Git Subtree&lt;/h1&gt;

&lt;p&gt;那麼對於需要經常去修改的pod，我們就可以採用Git Subtree來管理。使用Git Subtree來管理的好處是什麼呢？&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;原有的工作流程不會被打斷，只需要照平常一樣commit就好，更新library的遠端repository只要再打一行指令就好，要從遠端repository把更新拉下來一樣只需要一行指令。&lt;/li&gt;
&lt;li&gt;新專案成員把repository clone下來之後不用再另外下指令更新sub tree，全部的東西都已經被clone下來了&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;參考:  &lt;br&gt;
&lt;a href=&quot;https://medium.com/medium-eng/how-we-modularized-mediums-ios-codebase-8f8f26965c76&quot;&gt;https://medium.com/medium-eng/how-we-modularized-mediums-ios-codebase-8f8f26965c76&lt;/a&gt; &lt;br&gt;
&lt;a href=&quot;http://yutin.logdown.com/posts/188306-git-subtree-total-addendum-library&quot;&gt;http://yutin.logdown.com/posts/188306-git-subtree-total-addendum-library&lt;/a&gt; &lt;br&gt;
&lt;a href=&quot;http://www.lemonlatte.tw/posts/175465-git-subtree-trial&quot;&gt;http://www.lemonlatte.tw/posts/175465-git-subtree-trial&lt;/a&gt; &lt;br&gt;
&lt;a href=&quot;http://www.xiwan.info/subtree-detach-subdirectory-into-separate-repository.html&quot;&gt;http://www.xiwan.info/subtree-detach-subdirectory-into-separate-repository.html&lt;/a&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://vampirewalk.blogspot.com/feeds/5440388012980315956/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://vampirewalk.blogspot.com/2014/12/ioslibrary-git-subtree.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/5440388012980315956'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/5440388012980315956'/><link rel='alternate' type='text/html' href='http://vampirewalk.blogspot.com/2014/12/ioslibrary-git-subtree.html' title='在iOS專案引入外部Library的另一種選擇 - git subtree'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/17070298612568804458</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2840066036916532236.post-1987603970989347712</id><published>2014-12-30T16:42:00.001+08:00</published><updated>2014-12-30T16:43:56.669+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="iOS"/><title type='text'>在Xcode中用breakpoint印出時間</title><content type='html'>&lt;p&gt;&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWeskYkZUFiNzEm2RU7CT4PuNOLdrzkZqz4iQ4a5C_gB50lZ_S9w6ny3XFAa2jaUJBQ-GvPVdso8F08iJFV9NB4HCZTjk9LGn42ZMXdF5gVbtcI_MqyTDu9K0iiYP6dcMhRg5R9rZopoNC/s0/%E8%9E%A2%E5%B9%95%E5%BF%AB%E7%85%A7+2014-12-30+%E4%B8%8B%E5%8D%884.39.15.png&quot; alt=&quot;breakpoint&quot; title=&quot;螢幕快照 2014-12-30 下午4.39.15.png&quot;&gt;&lt;/p&gt;



&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs erlang&quot;&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-title&quot;&gt;expr&lt;/span&gt; &lt;span class=&quot;hljs-params&quot;&gt;(void)&lt;/span&gt;NSL&lt;span class=&quot;hljs-title&quot;&gt;og&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(@&lt;span class=&quot;hljs-string&quot;&gt;&quot;Request Data&quot;&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;效果像這樣 &lt;br&gt;
&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzVHMaRzzqoHCiwTWMZV7pbqX5oFJT0U-gpx8emBh1NoMQmLpvbrCZoC1tM9EyRvr6wNnWzh9HZgaH_S__E7y3gh3T2Pe85Xa_dFe9a_Tj5jzZ1HG-Jc5wXtqzD3vwGDi-ArqACmjrDSZv/s0/%E8%9E%A2%E5%B9%95%E5%BF%AB%E7%85%A7+2014-12-30+%E4%B8%8B%E5%8D%884.39.50.png&quot; alt=&quot;Console&quot; title=&quot;螢幕快照 2014-12-30 下午4.39.50.png&quot;&gt;&lt;/p&gt;

&lt;p&gt;參考: &lt;a href=&quot;http://www.raywenderlich.com/28289/debugging-ios-apps-in-xcode-4-5&quot;&gt;http://www.raywenderlich.com/28289/debugging-ios-apps-in-xcode-4-5&lt;/a&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://vampirewalk.blogspot.com/feeds/1987603970989347712/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://vampirewalk.blogspot.com/2014/12/xcodebreakpoint.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/1987603970989347712'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/1987603970989347712'/><link rel='alternate' type='text/html' href='http://vampirewalk.blogspot.com/2014/12/xcodebreakpoint.html' title='在Xcode中用breakpoint印出時間'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/17070298612568804458</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWeskYkZUFiNzEm2RU7CT4PuNOLdrzkZqz4iQ4a5C_gB50lZ_S9w6ny3XFAa2jaUJBQ-GvPVdso8F08iJFV9NB4HCZTjk9LGn42ZMXdF5gVbtcI_MqyTDu9K0iiYP6dcMhRg5R9rZopoNC/s72-c/%E8%9E%A2%E5%B9%95%E5%BF%AB%E7%85%A7+2014-12-30+%E4%B8%8B%E5%8D%884.39.15.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2840066036916532236.post-3513697800779446764</id><published>2014-12-25T09:45:00.001+08:00</published><updated>2014-12-25T10:50:33.289+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="iOS"/><title type='text'>Xcode 6已經內建類似Reveal的新功能</title><content type='html'>&lt;p&gt;目前在Xcode裡查看view hierarchy有幾個比較知名的工具，像是&lt;a href=&quot;http://revealapp.com/&quot;&gt;Reveal&lt;/a&gt;跟&lt;a href=&quot;http://sparkinspector.com/&quot;&gt;Spark&lt;/a&gt;。 &lt;br&gt;
現在Xcode 6內建了一個很類似的功能，不過功能就沒有這麼完整。 &lt;br&gt;
&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOdUO004bx-eq0B7gQ6io4aeS2pHayWRUMRbqV3nB6ZopPlCKpO1-UyWrmxp1YLcgm6hMXF8RlXjMtjw_4cZYW1s_2ItLpEmEpGNWJWTFqKhitGyxOYLTwf8jCxml5bNPVtW_Oil05Vqi4/s0/%E8%9E%A2%E5%B9%95%E5%BF%AB%E7%85%A7+2014-12-25+%E4%B8%8A%E5%8D%889.36.15.png&quot; alt=&quot;inspector&quot; title=&quot;inspector.png&quot;&gt;&lt;/p&gt;

&lt;p&gt;定位按鈕左邊那顆就是了。&lt;/p&gt;

&lt;p&gt;效果如下圖 &lt;br&gt;
&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh9pjGHnzsrVlGpc9Cjw-zJ405PHrlw_s_TW4zgDyeD7wCkgQvHasQURpAjygD_HNix7pDKIZaz0reZpvhgHTCVo9a94xkM1S1esg58cbi9EcZT2E986ESQgSm0IXJZEZDfvmn_meW0AhBT/s0/%E8%9E%A2%E5%B9%95%E5%BF%AB%E7%85%A7+2014-12-25+%E4%B8%8A%E5%8D%889.40.26.png&quot; alt=&quot;inspector2&quot; title=&quot;螢幕快照 2014-12-25 上午9.40.26.png&quot;&gt;&lt;/p&gt;

&lt;p&gt;還可以看frame以及autolayout的constraint。 &lt;br&gt;
&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEissx5eosydbNCrYV6ShlPL52X6_5THmTysF6TZUeTW37SWHXRZ2zUoBvNItvAU8aQzW9m4-HK74RdFJGju0CY7qeMskZThwz5ROOxFgDNd6YzkeN9wa3pNgXFWJkrYB4B3ZIrMbR8GM3Ij/s0/%E8%9E%A2%E5%B9%95%E5%BF%AB%E7%85%A7+2014-12-25+%E4%B8%8A%E5%8D%889.42.03.png&quot; alt=&quot;inspector3&quot; title=&quot;螢幕快照 2014-12-25 上午9.42.03.png&quot;&gt;&lt;/p&gt;

&lt;p&gt;其實這些基本功能就很夠用了，對我來說就可以把買Reveal的錢省下來了XD。 &lt;br&gt;
更詳細的介紹可以參考&lt;a href=&quot;http://www.cocoachina.com/ios/20141224/10748.html&quot;&gt;Xcode 6视图调试小贴士&lt;/a&gt;。&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://vampirewalk.blogspot.com/feeds/3513697800779446764/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://vampirewalk.blogspot.com/2014/12/xcode-6reveal.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/3513697800779446764'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/3513697800779446764'/><link rel='alternate' type='text/html' href='http://vampirewalk.blogspot.com/2014/12/xcode-6reveal.html' title='Xcode 6已經內建類似Reveal的新功能'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/17070298612568804458</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOdUO004bx-eq0B7gQ6io4aeS2pHayWRUMRbqV3nB6ZopPlCKpO1-UyWrmxp1YLcgm6hMXF8RlXjMtjw_4cZYW1s_2ItLpEmEpGNWJWTFqKhitGyxOYLTwf8jCxml5bNPVtW_Oil05Vqi4/s72-c/%E8%9E%A2%E5%B9%95%E5%BF%AB%E7%85%A7+2014-12-25+%E4%B8%8A%E5%8D%889.36.15.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2840066036916532236.post-8939555275070715755</id><published>2014-12-15T15:34:00.001+08:00</published><updated>2014-12-15T15:34:47.647+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="iOS"/><title type='text'>在iOS App實作Airplay Audio功能</title><content type='html'>&lt;h2 id=&quot;前言&quot;&gt;前言&lt;/h2&gt;

&lt;p&gt;由於Airplay開發者能控制的部分還不多，所以只能透過在自訂播放介面加入MPVolumeView的方式開啟Airplay的功能。&lt;/p&gt;



&lt;h2 id=&quot;實作&quot;&gt;實作&lt;/h2&gt;

&lt;p&gt;如果需要包含內建的音量控制元件&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs fix&quot;&gt;&lt;span class=&quot;hljs-attribute&quot;&gt;MPVolumeView *volumeView &lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt; [ [MPVolumeView alloc] init] ;
[view addSubview:volumeView];&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;如果不需要&lt;/p&gt;



&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs bash&quot;&gt;MPVolumeView *volumeView = [ [MPVolumeView alloc] init] ;
[volumeView &lt;span class=&quot;hljs-keyword&quot;&gt;set&lt;/span&gt;ShowsVolumeSlider:NO];
[volumeView sizeToFit];
[view addSubview:volumeView];&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;在iOS裡聲音可以分為兩大類，App sound跟System sound，System sound做為按鍵回饋或是警示聲使用，剩下的就是App sound。在MPVolumeView選擇了Airplay裝置之後，系統會自動把App sound導到支援Airplay的裝置上。&lt;/p&gt;

&lt;p&gt;在iOS7，MPVolumeView新增了兩個property&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs css&quot;&gt;&lt;span class=&quot;hljs-at_rule&quot;&gt;@&lt;span class=&quot;hljs-keyword&quot;&gt;property&lt;/span&gt; areWirelessRoutesAvailable&lt;/span&gt;;  
&lt;span class=&quot;hljs-at_rule&quot;&gt;@&lt;span class=&quot;hljs-keyword&quot;&gt;property&lt;/span&gt; isWirelessRouteActive&lt;/span&gt;; &lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;以及兩個通知&lt;/p&gt;



&lt;pre class=&quot;prettyprint&quot;&gt;&lt;code class=&quot; hljs objectivec&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;NSString&lt;/span&gt; *&lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; MPVolumeViewWirelessRoutesAvailableDidChangeNotification;  
&lt;span class=&quot;hljs-built_in&quot;&gt;NSString&lt;/span&gt; *&lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; MPVolumeViewWirelessRouteActiveDidChangeNotification; &lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;可以偵測到有airplay以及使用者改變了airplay route，如果想要在偵測到可以使用Airplay裝置時加入動畫這會是一個好的實作方法。&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://vampirewalk.blogspot.com/feeds/8939555275070715755/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://vampirewalk.blogspot.com/2014/12/ios-appairplay-audio.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/8939555275070715755'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2840066036916532236/posts/default/8939555275070715755'/><link rel='alternate' type='text/html' href='http://vampirewalk.blogspot.com/2014/12/ios-appairplay-audio.html' title='在iOS App實作Airplay Audio功能'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/17070298612568804458</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>