顯示具有 iOS 標籤的文章。 顯示所有文章
顯示具有 iOS 標籤的文章。 顯示所有文章

2015年9月2日 星期三

iOS Push/Local Notification之原理

這次來介紹一下如何使用iOS上的Push Notification,舉凡Facebook上的訊息、Gmail的郵件通知都是此類。而首先就是要知道Notification有分成Local和Push兩種,前者像是行事曆的定時通知,後者就是前面講的。Local的通知好處理,可以指定日期和時間來通知:
 NSCalendar * calendar = [NSCalendar autoupdatingCurrentCalendar];

NSDateComponents * dateComponent = [NSDateComponents alloc] init];

[dateComponent setDay: item.day];  // item: self defined object

[dateComponent setMonth: item.month];

[dateComponent setYear: item.year];

[dateComponent setHour: item.hour];

[dateComponent setMinute: item.minute];

NSDate * date = [calendar dateFromComponents: dateComponent];



 UILocalNotification *localNotif = [[UILocalNotification alloc] init];

 if (localNotif == nil)

    return;

localNotif.fireDate =

[date
  dateByAddingTimeIntervalInterval:-(minutesBefore*60)];

 localNotif.timeZone = [NSTimeZone defaultTimeZone];

 localNotif.alertBody = [NSString stringWithFormat:NSLocalizedString(@"%@ in
  %i minutes.", nil),
           item.eventName, minutesBefore];



localNotif.alertAction = NSLocalizedString(@"View Details", nil);

localNotif.alerttitle = NSLocalizedString(@"Item Due", nil);

localNotif.soundName = UILocalNotificationDefaultSoundName;
      localNotif.applicationIconBadgeNumber = 1;

NSDictionary *infoDict = [NSDictionary dictionaryWithObject:item.eventName
  forKey:ToDoItemKey];

localNotif.userInfo = infoDict;

[[UIApplication sharedApplication] scheduleLocalNotification:localNotif];

那麼要設定Push Notification要怎麼做?首先要用Apple的Push Notification機制(簡稱APN),自己的Server發出通知後會傳到Apple的Server,之後再從Apple傳給使用者的App:


我覺得這樣做的原因是要保持通知的完整性和安全性,假如說你傳送有惡意訊息的封包給使用者豈不是不好?而建立整個連線流程如下圖所示,裝置先和APN建立TLS(Transport Layer Security)連線,之後取得憑證後TLS就算建立完成:

而Provider也是同樣要建立TLS連線和取得憑證:

而當憑證建立完成後App和APN, Provider的互動就是靠Token來完成,App若要使用Push Notificaition必須先行註冊至APN(從使用者那邊獲取通知許可),然後APN再回傳加密過的Token給Provider,之後該Token再從Device回傳到Provider,如下圖所示:
而在傳送Push Notification時會連同Token,並藉由裝置ID來回傳加密的通知內容給裝置:

到這邊整個Push Notification就算完成,接下來就是在AppDelegate.m加上程式碼:

// Remote notifications
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{
    NSLog(@"Receive deviceToken: %@", deviceToken);
}
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error{
    NSLog(@"Remote notification error: %@", error.localizedDescription);
}
另外當收到了Notification後要做什麼事就先靠didReceiveRemoteNotification來完成,而handleActionWithIdentifier則是當使用者對Notification做出回應後你要採取什麼動作時,可用completionHandler的block來完成:

// When app is waked up, this method will be called
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{
    // with push notification from remote server
    // When app is running in the foreground, this method will be called
}
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void (^)())completionHandler{
    // Test for identifier with a sample indentifier
    if ([identifier isEqualToString:@"ACCEPT_IDENTIFIER"]) {
        [self handleAcceptActionWithNotification:userInfo];
    }
}
以上就是整個流程,至於說要註冊憑證的方法可參考這篇:popcorny的碎碎念

2015年8月31日 星期一

NSOperation及NSOperationQueue與GCD之比較

之前上Stanford iOS 7的課程時有介紹到GCD(Grand Central Dispatch),是一種比較低階的函數,讓code可以在不同的thread中跑。可是假如說我今天要檢查該thread的運作情況,好比說他的優先順序、是否還在運行等,這時候GCD能提供的設定就比較少,於是就需要NSOperation和NSOperationQueue啦~

在Mac OS X 10.6之前,NSOperation跟GCD是採用不同的運作模式,10.6之後NSOperation就改成運作在GCD之上了,換言之他是比較高階的API,但是同時也保有GCD的效能。使用NSOperation時有以下步驟:

  1. 繼承自NSOperation
  2. 覆寫main()
  3. 在main中建立autorelease pool(自動釋放池)
  4. 把code放到autorelease pool中
  5. 針對需求,在外部檢查isCancelled等屬性
至於NSOperation中有以下method:
  1. start:呼叫該函數來執行該operation,但如果沒有特別指定去哪個queue時將會在main queue執行,要特別注意
  2. dependency:可以設定兩個operation的相依性來設定先後順序。舉例來說我今天下載了一段音訊,要等下載完成後才能進行裁剪,GCD中的dispatch_barrier_async()有提供類似的功能
  3. priority:這點是我覺得比較有趣的地方,可針對特定的operation來設定setQueuePriority:,像是NSOperationQueuePriorityVeryLow
  4. completion block:當operation完成後可以在setCompletionBlock:^{}去做其他事情,好比說存檔等等
另外NSOperationQueue相較於NSOperation就更為簡單,僅需要alloc並init即可,之後可調用以下方法:
  1. concurrent operations:這點比較複雜,簡單來說一個queue可以有多個thread,而每個operation會分配到一個thread來執行。舉例來說我有一個queue,然後加入2個operations,這樣建立兩個thread對應到每個operation,所以我這個queue就會有兩個thread
  2. maximum number of concurrent operations:設定每個queue中最多只能有幾個operations來執行
  3. add operation:增加operation到queue,如果要釋放的用使用release方法
  4. pending operation:查詢在queue中有哪些operations。只有「待執行」和「正在執行」的operation才會在queue中。這部分可以用NSArray來保存operations,或是使用NSDictionary來查詢相關的operation
  5. pause(suspend)queue:就是停止queue
  6. cancel operation:如果說該operation尚未執行,呼叫cancel會把operation從queue中移除;如果是正在執行的operation,就要看該operation會不會去檢查isCancelled
  7. addOperationWithBlock:如果當你不想要有NSOperation的子類別卻又想要來queue中執行,就可在該方法中的block插入程式碼。這有點像GCD的block。不過要注意的是若要參考block外的物件,就必須傳入weak屬性的物件
最後綜合比較NSOperation和GCD,我覺得GCD比較簡單、直覺,但是可以操作的範圍不大(因為就是函數),可是其他物件可以繼承NSOperation,獲得了使用多線程的能力。所以我想當要操作物件時就用NSOperation,然後某些片段(下載等需求)就可以用GCD來解決。總之在iOS中多線程是個很重要的觀念,有這麼好用的功能就要好好用它啊~~

Protocol v.s. Delegate

最近剛好寫了一些跟NSOperation的東西,裡面用到許多的Protocol和Delegate,之前學到我們可以宣告一個Protocol,然後讓class去遵循它,可是那為何我們還需要有Delegate? Delegte不也是讓我們去遵循其中的方法來實作嗎?就像是我們在寫UITableView時都要有UITableViewDataSource和UITableViewDelegate來對資料和cell進行設定(因為View無法擁有自己的資料)。那麼兩個這麼像,Protocol和Delegate又有什麼差別呢?

答案是一定有差別的,不然你就不會一直看到這兩個名詞。先複習一下什麼事Protocol,假設當我宣告MyProtocol中有個aMethodInMyProtocol時,任何一個遵循MyProtocol就可調用該方法;另外也可讓實體變數遵循Protocol,譬如我的MyClass中有以下變數:

@property (nonatomic, strong) id  <myprotocol>  instanceThatImplementMyProtocol;

此時該instanceThatImplementMyProtocol就可調用MyProtocol的方法。此外宣告Protocol時也可再遵循其他Protocol,例如:

@protocol Foo
...
@end

只有當你實作了anotherProtocol後,然後你再實作Foo後你才可以說已經實作好該Foo Protocol。那麼在Delegate又是怎麼樣呢?

Delegate說起來是一種設計方法,全名叫做Delegation Design Pattern,Delegate要求遵循該delegation的class去實作Protocol的方法(可以說是一種「方法」),使得該class可以在特定時候使用該Protocol的method。對我來說,Protocol提供一個介面來讓大家共享裡面的方法,然後Delegate會讓用它的class去實現該方法,使用Delegate的好處是可以減弱耦合,達到共享的目的。

另外取自StackoverFlow的解答,我覺得看英文比較能懂:)
The class that uses the delegate knows that its delegate coforms to the protocol, so it knows that it can call the implemented methods at given times.