呃...

其實不會有什麼精深的東西,也就只是把我學習過程記錄一下...

2014年9月8日 星期一

[問題] APNS通知 (My answer for question in MacDev)

    這個問題不長就不簡述了,最後倒是有不小心稍稍念了這位發問者 XD 我是覺得念得有理,畢竟APN不是什麼冷門問題,網路上一堆中文資源,還有很貼心的文章會解釋APNs原理,沒這麼難姑狗吧!?


 作者  flamelad (flamelad)                                       看板  MacDev
 標題  Re: [問題] APNS通知
 時間  Mon Aug 25 00:45:04 2014
───────────────────────────────────────

※ 引述《haves560 (新鮮人)》之銘言:
: 我是用UILocalNotification接收到APNS訊息後
: 顯示在app上面,可是遇到個問題,我把程式關閉後沒辦法push
: 請教一下 各位在做APNS push都是用什麼方式讓程式關閉後還能接收的到?

    問題描述有點不清楚,我先假設你的情況有兩種:1. 希望程式退到背景後,還可以收到APN 後讓App執行某些動作。 2. 程式完全關閉,不在foreground or background 執行,希望Device能收到APN後,讓App執行某些動作。

    假設1:
    若如1 的假設,則你必須了解UIApplication State。確切來說,你應該要知道什麼是背景處理,當然你若希望在App的其他階段執行你的動作,UIApplication State will help you more.
    另外下面這連結的文章,很清楚的說明iOS7在背景處理的狀況。
    http://onevcat.com/2013/08/ios7-background-multitask/

    假設2:
    若如2的假設,則情況與1不同,簡單來說,當App在not running狀態下時,Device收到APN後,iOS不會去替使用者執行App以及讓App執行某些動作,你可能需要多了解...呃,下段說明。

    可以看得出你在這部分所遇到的問題是你不太熟悉相關議題,因此建議你需要好好了解一下APNs、App lifecycle、前/背景處理差異、UIApplication State以及各種Notification的使用時機與用途,相信會對你在這邊遇到的問題有很大的幫助。

    最後算是我雞婆murmur,還請忍耐一下,有任何讓你感到不舒服的地方請多見諒:)
 這部分算是挺熱門的議題,相比其他問題,網路上姑狗一下關鍵字有很多相關的繁體資源以及衍伸議題,未來希望可以先稍微姑狗一下,我始終相信除了來自他人幫助以外,慢慢培養獨立解決問題的能力以及享受解決問題後所帶來的成就感,這種良好的自我循環,才是成就一個好的開發者的最重要因素。我也剛踏在這路上,共勉之 :)

[問題] UINavigationController and Camera (My answer for question in MacDev)

    發問者沒有很清楚描述問題,所以假設問題是想詢問使用UIImagePickerController時,NavigationBar消失了以及回不到rootView。


 作者  flamelad (flamelad)                                       看板  MacDev
 標題  Re: [問題] UINavigationController and Camera
 時間  Sun Aug 24 00:39:08 2014
───────────────────────────────────────

※ 引述《stevenlin08 (stevens)》之銘言:
: hi all,
: 請問,若第一個頁面是TableViewController,而我將會導航*1到
: 另一個viewController(B),並開啓照相。
: 此時,會使原本的NavigationBar 消失。
: 導致我沒法退出到rootView .
: *1:
: 用pushViewController: view(B)推入控制器。
: 目前,我認為有一列方式,但還是沒法成功。
: 1.要如何讓NavigationBar 出現?
: 2.使用popViewControllerAnimated:並無法使畫面回覆

    這部分同樣並非很熟悉,就直接回應於板上給其他版友指正:) 你的文章中缺少一些細
節,另外我也並不太懂你的*1的意思,因此我先假設幾件事情:
        a. 是一般tableView中的cell點了會導向另一個ViewController。
        b. 在另一個ViewController中的somewhere invoke UIImagePickerController。
        c. 照著一般UIIPC最簡單的範例去實作Camera功能的呼叫。

    問題1:
        若是因為要解決問題2才有問題1,那這應該沒問題了。若不是,可以使用
    isNavigationBarHidden確認是否NavigationBar在invoke Camera時被設定為hidden。
    問題2:
        請在imagePickerControllerDidCancel中,先dismiss掉正在使用的UIIPC,再
    pop回rootView即可。
    [self dismissViewControllerAnimated:YES completion:^{}];
    [self.navigationController popToRootViewControllerAnimated:YES];

[問題] 請教AVAudioPlayer小問題 (My answer for question in MacDev)

    原問題是詢問AudioToolBox,不過我沒使用過AVFundation相關類別,所以在這個問題的往來回信中,我是使用AVAudioPlayer進行測試。
    問題簡述:有關AVFundation中的AVAudioPlayer在連續播放音效時,似乎在音效之間會有些許間隔的存在問題。


 作者  flamelad (flamelad)
 標題  Re: F大您好 請教AudioToolBox小問題
 時間  Sat Aug 16 21:32:26 2014
───────────────────────────────────────

    Hello, 我先把上一封信打太快造成些謬誤的地方修正一下:p
    在上一封信中我闡述了alloc放在Button中所造成的問題,這邊我並不是想說延遲,而是重新又被assign一次,所以才會有第二次點擊就會中斷第一次的播放,並非延遲,因此你將alloc放在其他地方使用,就會發現第一次點擊後的音效並不會被中斷。

    回到你的問題,我重新思考一次,想要seamless播放音效,又不希望會重疊,我想一想,也許只是一個很簡單的問題。這邊真的挺不好意思,中午真的太趕沒好好仔細review寄給你的信,因為盲點在於AVAudioPlayer會有延遲感並非是program運作的問題,而是沒有對症下藥。你可以試試使用AVAudioPlayer,但是button 的 Sent Event改為TouchDown,而不是TouchUpInside,我想應該就能解決問題了。

    試試看吧,有問題再來信討論吧 :)

: 不好意思又打擾了
: 程式其實寫得差不多了
: 只是有些小問題不知道怎麼處理
: 想跟您請叫關於AudioToolBox的音效播放 不知您是否熟悉
: 由於我本來按鈕播放音效是用AVAudioPlayer
: 但聲音跑出來都會延遲個零點幾秒 很短的延遲 但是還是有感
: 對音樂軟體來說有些不太流暢
: 現在是考慮用AudioToolBox來播放
: 因為音效聲音跟我手觸碰幾乎同步反應 沒感覺到延遲
: 雖然無法調整音量 跟其他控制   但就是反應很快
: https://www.youtube.com/watch?v=bq7ldV9Wsnc
: 想請問一下F大
: 我用AudioToolBox播放  發現音跟音之間都會重疊
: 譬如第一個音還沒結束的時候  我再按第二個音,    第一個音不會消失 變成重疊存在
: 有辦法讓就只有最後一個點擊的有聲音 而之前的都被停止嗎?
: 就是只有單一個按鍵的聲音存在而已
: Thank you so much!

[問題] 請教如何改變UIButton的highlighted狀態? (My answer for question in MacDev)

引用:http://www.ptt.cc/bbs/MacDev/M.1407647206.A.BD3.html
原文章問題簡述:如何手指不離開螢幕觸發多個Object
在ptt上回應了一篇個人認為算是有通盤回應到答案的文章,如下。(回覆部分黑底反白)


 作者  flamelad (flamelad)                                       看板  MacDev
 標題  Re: [問題] 請教如何改變UIButton的highlighted狀態?
 時間  Sun Aug 10 13:06:43 2014
───────────────────────────────────────

    關於你的問題昨天原本想回信,但因為太晚又考慮到我並不是非常熟悉,所以就沒回
應了。由於你來信詢問,那我會盡我綿薄之力提供建議,不對之處還請多見諒。另外這篇
我就直接回應到版上占用一些版面,讓版友可以指出我不對之處或提供更佳解 :)

※ 引述《pistols (我不想上報 別寄信啦)》之銘言:
: 請問一下版友
: 我想設置多個UIButton
: 譬如我從xcode右下角拉了九個UIButton放到ViewControl
: 排列就像電話的按鈕 1 2 3...9這樣九宮格的排列
: 我想設計每個按鈕的state狀態為highlighted時  會產生個別的反應或音效
: 可是忽然發現UIButton的highlighted的特性跟我想的不太一樣
: 譬如當我按住button1時候  就會有highlighted
: 但是我手指拖移離開button1 移到button2的範圍內時
: button1的highlighted仍然未消失   button2也沒有出現highlighted

    就如上次你詢問時的解答,假如你只是想要click button 後可以得到被點擊後或點住
不放的狀態,那isHighLighted 就可以得到你想要的結果,否則應該使用其他的-(method)
或判斷。(請務必參考isHighLighted 的description)
    另外就我所了解的是,當你手指未離開屏幕而移動,整體來說只會是某個 Object 的
a series of events,包括Inside, Outside, DragExit等,而不是手指從button1 拖曳到
button2 就會trigger button2 的event。

: 想請問版友
: 我如果想讓每一個button只要是手指有接觸到該按鈕的範圍內就會有highlighted反應
: 而一離開或是拖移超出範圍馬上就不會有highlighted
: 我該如何設置呢?

    這並不難,請參考UIButton繼承的UIControl中的一些method,主要是需要改變按下
button的default UIControlEvent。

: 譬如像上面說的例子
: 當我手指離開button1範圍 移到button2範圍的時候
: 如何讓button1的highlighted馬上消失  而變成button2的highlighted跑出來

    這例子若是手指並不離開屏幕,則與上一段你所希望的並不相同,請見第一段的解釋
。若你想有手指不離開屏幕而觸發多個 Objects,應該使用Gesture Recognizer或是版友
所提到的UITouch中的-(method)。

: 是要拉每個按鈕的IBOutlet到interface底下 增加什麼判定的屬性嗎?
: 我是有試過拉IBAction 然後用touch drag outside或是drag inside等等
: 但都不會跑出我所說的那樣
: 而且  我的功能是用按鈕的state去做反應的
: 希望版友可幫忙解答一下
: 非常感謝!

    請參考UIControl。另外若有拉IBAction,每當你觸發了版面上的某個Object event時
,則IBAction中常見的sender就是被觸發Object的instance,你可以借由這個sender去改
變行為。

  以上,大致上是我的理解,希望有幫助:)

Edit:
    最後一段有些謬誤的地方,不好意思,趕吃飯:p
    謬誤:
        1. 在button中的sender並不該是改變event,而是增減一些event才對。
        2. 若是要修改該button的event,一般也不會在該button中實現,而是如你
           所說,另外declare一個IBOutlet,然後去增加該button的event

[問題] 如何讓兩個按鈕一起按會有獨立事件? (My answer for question in MacDev)

    有點久沒更新,罪惡啊~不過這也不能怪我,原本預計要寫iOS如何與php傳送加解密的資料,但原理部分實在有點難寫,這一兩個禮拜再來完成它。接下來一系列是將我在其他地方替其他人解答的文章或往來信件,轉錄過來做個記錄,哪天也需用得到。

原問題及回覆:(回覆部分黑底反白)


 作者  flamelad (flamelad)
 標題  Re: [問題] 如何讓兩個按鈕一起按會有獨立事件?
 時間  Sat Jul 26 01:59:14 2014
───────────────────────────────────────
: 想請教板友們
: 關於iOS開發的按鈕問題
: 譬如設計個音樂遊戲
: 按了A按鈕會有個IBAction方法 是發出Sound A的聲音
: 並另外再設計B跟C按鈕 但是按下去不具任何聲音
: 想請問一下
: 如果我想讓它有另外一個功能:
: "當B按鈕按住 再按A按鈕 才會產生Sound B的聲音"
: "當C按鈕按住 再按A按鈕 才會產生Sound C的聲音"
: 我應該要在A按鈕的IBAction方法怎麼寫才會有
: "按A = Sound A聲"   "B按住又按A = Sound B聲"  "C按住又按A = Sound C聲"
: 就是把A鈕當作發聲的主事者  B跟C只是疊加A用來改變聲音
: 請問這樣的功能大概是要如何寫?
: 希望板友可幫忙解答一下!  感謝!
: p.s. 另外 聲音的部分由於是短短的音效  我使用AudioToolbox去寫
:      實機測試才發現 音量無法從機身的音量按鍵調整大小聲....
:      如果使用短音音效比較推薦用哪種框架的呢?
    我是資淺開發者,就獻醜說說有關button的想法,覺得不好或根本是個誤會,
    還請多諒解:)

    1.
    寫一個-method裡頭含有button的istracking判斷,用來判斷buttonB以及buttonC的
UIControlEvents狀態,再透過tag或title判斷哪個button被按下。declare一個變數值,
並根據-method中的判斷是來指定數值,可以是1,2,3......,總之,就是用來當buttonA
按下時,判斷該使用什麼音效。
大致上是這樣:
UIButton *buttonB & *buttonC -> init button並各指定Down與cancel給B與C,並含有
一個@selector(-method)-> -method寫判斷式去判斷button以及利用istracking判斷
button狀態->修改一個@property的變數值為0,1,2其中一個 -> ButtonA按下時根據變數
選擇音效發出。

    2.
    用notificationcenter去監聽buttonB&C狀態,其餘判斷與構想差不多跟1一樣

   以上是一點淺見,不好用或根本誤解了還請多見諒:)

 作者  flamelad (flamelad)
 標題  Re: [問題] 如何讓兩個按鈕一起按會有獨立事件?
 時間  Sat Jul 26 12:14:35 2014
───────────────────────────────────────

    另外看到有版友說能使用highlighted這個State,在這邊補述一下,button的event有
各種不同狀況,那假定是最常見Down、Cancel與UpInside,highlighted可能不足夠滿足你
的條件。當button TouchDown的時候,isTracking與isHighLighted都會等於YES,但是當
button觸發的event是UpInside時,isTracking會等於NO,但isHighLighted會等於YES,這
在Description中也有提到。
    簡而言之,不管是Cancel或UpInside,istracking都會改變狀態,但isHighLighted只
有在Cancel時,才會改變狀態。另外,是我昏了頭,確實不需要額外寫-method,一時忘記
直接使用isTracking在buttonA中判斷buttonB&C的狀態即可,不好意思:P

2014年8月17日 星期日

NSNotificationCenter

同樣是很久前就解決的問題...積了不少文章 囧

這個類別在我剛接觸時其實有稍微困擾過,後來再姑狗上看到了同是Stanford的教學卻有附註解釋,真是容易懂太多了,不常用到時會經常忘記,就發這篇記錄一下囉。

透過defaultCenter這個+(method)來alloc與init一個NSNotificationCenter instance,在調用下方的-(method)即可實現監視物件活動的方法。

NSNotificationCenter *center=[NSNotificationCenter defaultCenter];
addObserver - 誰來收通知(通常是self)
selector    - 當收到通知時被調用的方法
name        - 決定監視該發出通知的情況類型,通常是已經預先define好的字串
object      - 被監視的對象

NSNotificationCenter

- (void)addObserver:(id)observer // you (the object to get notified)
selector:(SEL)methodToInvokeIfSomethingHappens
name:(NSString *)name 
// name of station (a constant somewhere)
object:(id)sender; // whose changes you’re interested in (nil is anyone’s) You will then be notified when there are broadcasts

You will then be notified when there are broadcasts 
- (void)methodToInvokeIfSomethingHappens:(NSNotification *)notification
{
notification.name 
// the name passed above
notification.object // the object sending you the notification notification.userInfo // notification-specific information about what happened
}

How to implement serial execution of GCD queue?(group, barrier, serial)


廢話time:
原本打算是從上一篇文章開始都用英文撰寫來練習英文寫作,但是打完上一篇文章後卻覺得,繁體中文資源已經不多,很多技術文件或討論文件在中文搜尋上根本是零零落落或乾脆搜尋不到相關資料,因此還是改變決定,繼續以中文撰寫,算是勉強盡一份心力於中文資源。

積存已久的問題,雖然早已解決,但是GCD的部分還是沒有很熟,還需要了解NSOperationQueue與NSThread的差別,現在主要在熟悉CS193p的文件,等未來有空再發一篇文章補齊三者的使用時機。

在main thread 使用NSURLConnection,建立一個thread等待資料庫讀完,再回到main thread執行一些code,在program裡面看起來如下:

//part.1
[NSURLConnection *myDB=[...];
//概要來說是使用POST Method, 送NSURLrequest以及設定delegate為self, 
//在NSURLconnection的protocol - connection didRecievedata實現一個loadprogress

//part.2
     dispatch_queue_t queue=dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
     dispatch_async(queue,^{
     while (myDB.loadprogress!=1){
          //這裡只是等待progress=1, 就是讓data收完
}
     dispath_async(dispatch_get_main_queue, ^{
          //data收完,回到main thread去做事,例如轉換格式,取資料,填資料到tableview等
     });
});

//part.3
//這邊繼續做main thread的事

現在問題在於,假使我希望part3在某個片段可以等待part2完成(收data)再繼續做事,比較好的寫法是什麼?

Solution:
GCD有group、serial或barrier的建立方式,都可以實現等待上個thread完成後再執行的效果。以下是一些簡單的implement:

barrier - 如同barrier的意思,會擋住下游的thread執行直到上游的thread執行完畢以及本身thread執行完畢,方讓下游的thread繼續執行。
   
    dispatch_queue_t queue=dispatch_queue_create("flamelad", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        for (int i=0; i<3; i++) {
            NSLog(@"concurrent:%d\n",i);
        }
    });
    dispatch_barrier_async(queue, ^{
        for (int i=0; i<3; i++) {
            NSLog(@"barrier:%d\n",i);
        }
    });
    dispatch_async(queue, ^{
        for (int i=0; i<3; i++) {
            NSLog(@"concurrent1:%d\n",i);
        }
    });
//    輸出結果:
//    2014-08-17 01:58:42.464 Sherlock[2836:1303] concurrent:0
//    2014-08-17 01:58:42.465 Sherlock[2836:1303] concurrent:1
//    2014-08-17 01:58:42.466 Sherlock[2836:1303] concurrent:2
//    2014-08-17 01:58:42.467 Sherlock[2836:1303] barrier:0
//    2014-08-17 01:58:42.468 Sherlock[2836:1303] barrier:1
//    2014-08-17 01:58:42.469 Sherlock[2836:1303] barrier:2
//    2014-08-17 01:58:42.470 Sherlock[2836:1303] concurrent1:0
//    2014-08-17 01:58:42.470 Sherlock[2836:1303] concurrent1:1
//    2014-08-17 01:58:42.471 Sherlock[2836:1303] concurrent1:2
 
serial- 與concurrent不同(很明顯吧XD),queue中的每一個thread會循序處理,FIFO
    dispatch_queue_t serial=dispatch_queue_create("flamelad", NULL);
    dispatch_async(serial, ^{
        for (int i=0; i<3; i++) {
            NSLog(@"serial:%d\n",i);
        }
    });
    dispatch_async(serial, ^{
        for (int i=0; i<3; i++) {
            NSLog(@"serial2:%d\n",i);
        }
    });
    dispatch_async(serial, ^{
        for (int i=0; i<3; i++) {
            NSLog(@"serial3:%d\n",i);
        }
    });
//    輸出結果
//    2014-08-17 02:19:43.616 Sherlock[2898:1303] serial:0
//    2014-08-17 02:19:43.626 Sherlock[2898:1303] serial:1
//    2014-08-17 02:19:43.643 Sherlock[2898:1303] serial:2
//    2014-08-17 02:19:43.644 Sherlock[2898:1303] serial2:0
//    2014-08-17 02:19:43.646 Sherlock[2898:1303] serial2:1
//    2014-08-17 02:19:43.648 Sherlock[2898:1303] serial2:2
//    2014-08-17 02:19:43.649 Sherlock[2898:1303] serial3:0
//    2014-08-17 02:19:43.650 Sherlock[2898:1303] serial3:1
//    2014-08-17 02:19:43.651 Sherlock[2898:1303] serial3:2
group - group有notify和wait方式可以實現類似barrier的效果,不同處在於可以做一些細節上的設定。從輸出結果即可知wait會等待上游thread完成,notify則會等到group中所有thread完成。
    dispatch_queue_t queue=dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_t group=dispatch_group_create();
    dispatch_group_async(group,queue,^{
        for (int i=0; i<3; i++) {
            NSLog(@"group:%d\n",i);
        }
    });
    dispatch_group_async(group,queue,^{
        for (int i=0; i<3; i++) {
            NSLog(@"group2:%d\n",i);
        }
    });
//    可設定等待下游的thread等待上游thread多久時間後開始執行,FOREVER則是等到上游執行完成後。
    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    dispatch_group_async(group,queue,^{
        for (int i=0; i<3; i++) {
            NSLog(@"group3:%d\n",i);
        }
    });
    dispatch_group_notify(group,queue,^{
        for (int i=0; i<3; i++) {
            NSLog(@"group4:%d\n",i);
        }
    });
    dispatch_group_async(group,queue,^{
        for (int i=0; i<3; i++) {
            NSLog(@"group5:%d\n",i);
        }
    });
//    輸出結果
//    2014-08-17 02:32:54.587 Sherlock[3001:130b] group:0
//    2014-08-17 02:32:54.587 Sherlock[3001:3c07] group2:0
//    2014-08-17 02:32:54.588 Sherlock[3001:130b] group:1
//    2014-08-17 02:32:54.588 Sherlock[3001:3c07] group2:1
//    2014-08-17 02:32:54.590 Sherlock[3001:130b] group:2
//    2014-08-17 02:32:54.591 Sherlock[3001:3c07] group2:2
//    2014-08-17 02:32:54.591 Sherlock[3001:130b] group3:0
//    2014-08-17 02:32:54.592 Sherlock[3001:3c07] group5:0
//    2014-08-17 02:32:54.593 Sherlock[3001:130b] group3:1
//    2014-08-17 02:32:54.593 Sherlock[3001:3c07] group5:1
//    2014-08-17 02:32:54.594 Sherlock[3001:130b] group3:2
//    2014-08-17 02:32:54.595 Sherlock[3001:3c07] group5:2
//    2014-08-17 02:32:54.596 Sherlock[3001:3c07] group4:0
//    2014-08-17 02:32:54.597 Sherlock[3001:3c07] group4:1
//    2014-08-17 02:32:54.598 Sherlock[3001:3c07] group4:2

這篇只介紹了三種最常用到的GCD thread執行方式來解決我的問題,但其實尚有些如dispatch_once、dispatch_semaphore_t等的執行方式,有興趣者再自行姑狗,都是在實現multi-thread石,可能會用到的方法。