軽量Evernoteクライアント
  SmartEverにおける
アプリ高速化の工夫と課題


   Makoto Setoh
   @setoh2000


             1
自己紹介
• 個人iOSデベロッパー

• アプリで生計を立てたい!

• 主に深夜に活動

• Twitter @setoh2000



                       2
アプリ紹介
• MY辞書登録
• Touch Icon Creator
• Duet Browser (iPad)
• TweetLink
• 和暦+
• SmartEver
                        3
SmartEverとは
• 軽量Evernoteクライアント
• テキスト、写真の投稿ができる
• ノートの編集ができる
• 高速な検索
•   SmartEver タグが付いたノート
    を同期


                     4
ユーザーの声
•   あなたのEvernoteにスピード革命を☆とに
    かく動作が速くて作業がサクサク進
    む!!(iPhone女史さん)

• 同期爆速で閲覧・編集ともにハイレベルな
    操作が可能な軽量Evernoteクライアント
    「SmartEver」が凄すぎる!(OZPAの表4)

                 5
目標


空気のように軽いEvernoteクライアント



                    イメージ図




           6
高速化の工夫
時間のかかる処理はバックグラウンドで


• NSOperation

• GCD+Blocks




                7
NSOperation
• 目的に合わせてクラスを継承して使う

• NSOperationQueueに追加することで実行

• キャンセルの仕組みがある

• 複雑な処理に向いている


               8
NSOperationから
  ENSearchOperationを派生
//
// ENSearchOperation.h
//
@interface ENSearchOperation : NSOperation

@property (nonatomic, copy) NSString *notebookName;
@property (nonatomic, retain) NSArray *tagNames;
@property (nonatomic, copy) NSString *searchString;
...




                            9
ENSearchOperationの実装
- (void)main
{
  ...
    for (NSInteger i = 0; i <= 100000; i += maxNotes) {
     if (self.isCancelled) return;
     ...
      NSError *error;
      tempResults = [myNoteStore findNotes:self.searchString
                              notebookName:self.notebookName
                                  tagNames:self.tagNames
                                    offset:startIndex
                                  maxNotes:maxNotes
                                     error:&error];
      ...
     [self postNotificationOnMainThread:@"UpdatedSearchResult"];

    }
    ...
}


                                     10
NSNotification による通知
- (void)postNotificationOnMainThread:(NSString *)notificationName
{
  NSNotification* notification
    = [NSNotification notificationWithName:notificationName
                                    object:self userInfo:nil];

    [[NSNotificationCenter defaultCenter]
        performSelector:@selector(postNotification:)
               onThread:[NSThread mainThread]
             withObject:notification
          waitUntilDone:NO];
}




                                   11
NSOperationQueueの作成

self.operationQueue = [[NSOperationQueue alloc] init];
[self.operationQueue setMaxConcurrentOperationCount:1];



   setMaxConcurrentOperationCountで同時に
   実行するオペレーションの数を指定




                              12
NSOperationの作成と実行

ENSearchOperation *searchOperation
              = [[ENSearchOperation alloc] init];


searchOperation.searchString = searchString;
searchOperation.tagNames = self.tagNames;
searchOperation.notebookName = self.notebookName;


[self.operationQueue addOperation:searchOperation];




                           13
NSOperationの継承クラス
• ENSaveNoteOperation (ノート作成)

• ENUpdateNoteOperation (ノート更新)

• ENGetNoteOperation (ノート取得)

• ENSearchOperation (検索)

• ENResourceLoaderOperation (画像などの取得)

• ENUpdateNotebooksOperation (ノートブック一覧の更新)

• ENUpdateTagsOperation (タグ一覧の更新)

• ENSyncOperation (同期処理)

                           14
GCD+Blocks
• GCD (Grand Central Dispatchの略)

• 手軽に使える

• キャンセルの仕組みが用意されていない

• シンプルな処理(短時間)に向いている


     エキスパートObjective-Cプログラミング
             坂本一樹(著) @splhack
                    15
GCD+Blocksの例
@implementation MSBlocks

+ (void)executeInBackground:(void(^)())block
{
    dispatch_queue_t mySerialDispatchQueue
              = dispatch_queue_create("com.setoh2000.gcd.Queue", NULL);

     dispatch_async(mySerialDispatchQueue, block);
}




                                      [MSBlocks executeInBackground:^{
    [self saveFavorites];                 [self saveFavorites];
                                      }];



                                     16
検索の高速化

• 必要最低限の結果をまず取得して表示 (10件
     →50件→100件→100件→...)

• プレビュー(本文、画像)もバックグラウンドで




              17
同期の高速化
• “SmartEver”タグが付いたノートのみ同期

• “SmartEver”タグで検索しノートが更新されて
 いればダウンロード

• しかし数が増えると遅くなる…


        getFilteredSyncChunk:
              18
getFilteredSyncChunk:とは

• 指定した時点から更新された情報だけを取得できる!

 指定した時点とは?

        USN
       (UpdateSequenceNumber)



                 19
USN: UpdateSequenceNumber
アカウント作成時からサーバーでのすべてのイベント
に付くシーケンス番号

  USN              イベント

  101          ノートA作成

  102        ノートAにタグX付加

  103          ノートB削除

  104   ノートCをノートブックYに移動
              20
getFilteredSyncChunk:の利点
• 更新された情報だけを取得できる

(何も更新されてなければ1回の呼びだしで済む)

• フィルターで欲しい種別のみ指定できる

     - 更新されたノート
     - 更新されたノートブック
     - 更新されたタグ
     - 削除されたオブジェクト
     - 保存された検索
              21
今後の課題

• 起動時にメタデータを全件読み込んでい
る→ 遅い

• やっぱりCoreDataか。。


             22
まとめ
     • 目標は高く(空気のように軽い・・)

     • 時間のかかる処理はバックグラウンドで
       (NSOperation, GCD+Blocks)

     • Evernoteの同期は getFilteredSyncChunk


23

軽量EvernoteクライアントSmartEverにおけるアプリ高速化の工夫と課題