「RouteDesigner」ver1.11を公開しました。

ランニング・ジョギングコース作成アプリ「RouteDesigner」を更新しました。

今回はKMLファイルのエクスポート機能を改善しています。
RouteDesignerから直接「Google Earth」や「Cyclemeter」など対応アプリにルートを受け渡すことが出来るようになりました。

アップデートをお願いいたします。

「RouteDesigner」ver1.10.2を公開しました。

ランニング・ジョギングコース作成アプリ「RouteDesigner」を更新しました。

今回は、
GarminConnectからエクスポートしたKMLファイルをインポートした時に、
不要な情報をインポートしてしまう不具合を修正しています。

アップデートをお願い致します。

ランニングコース作成アプリ「RouteDesigner」 ver1.10

「RouteDesigner」ver1.10をAppleに提出しました。

今回の修正内容は

曲線のルートを複数の直線に分割する機能を追加しました!

言葉で書くと何のことか分かりにくいですね。

例えばカーブに沿ったルートを作成して、このアイコンをタップすると
img20150908_1

カーブが複数の直線区間に分割されます。
img20150908_2

これってどのような時に使うかというと、「route」モードで引いた”道なり”のルートを少し左右に寄せる時に便利なのです。
例えば、レースの折り返し地点等、同じ道を往復する場合がありますよね。
そのような場合、単純に道に沿ったルートを作成すると道が重なってしまって、往復している事が分かりにくいです。

そんな時はこの機能で分割した上で、ピンを少し調整すると。
img20150908_3

こんな感じでわかり易くなりました。
img20150908_4

※ルートの調整後に余計なピンは削除しても大丈夫です。調整したルートはそのまま残りますよ。

今までも直線ルートを刻む事で対応は出来たんんですけど、
より便利にお使い頂けると思います。

NSNotificationCenterを使った通知のサンプル

オブジェクト間で通信、通知を行いたい事って頻繁にありますよね。
解決方法として色んなパターンがあると思いますが、cocoaフレームワークには大変便利な通知システムが用意されています。

使い方も簡単で、しかもオブジェクト間の関連性が薄いので大変使いやすいです。

通知は文字列の名称を使って識別されますので、ヘッダに定数を宣言しておきます。
通知を発行するクラスのヘッダに書くのが良いのではないでしょうか?

#define kDataManagerFinishLoading @"DataManagerFinishLoadingMsgKey"

通知を発行する側はこんな感じで簡単に通知できます。

// 引き渡しパラメータの作成
// Dictionaryでなんでも渡せます
NSDictionary* info = @{ 
  @"date":[NSDate date],
  @"title":@"目くじら", 
  @"count":[NSNumber numberWithInt:12] 
};

// 通知                    
[[NSNotificationCenter defaultCenter] 
    postNotificationName:kDataManagerFinishLoading  
    object:self 
    userInfo:info];

通知を受け取る側のコードはこんな感じです

最初に、NSNotificationCenter に通知の監視を登録します。
self.dataManagerってのが通知を発行するオブジェクトで、通知を受け取るオブジェクトがselfだとすると。

[[NSNotificationCenter defaultCenter] 
    addObserver:self 
    selector:@selector(handleDataManagerFinishLoading:) //←通知を受け取るセレクタ
    name:kDataManagerFinishLoading 
    object:self.dataManager];

受け取った時の処理を書いておきます

// kDataManagerFinishLoading の通知ハンドラ
-(void)handleDataManagerFinishLoading:(NSNotification *)aNotification
{
    //userInfoはDictionaryなので色んな情報を受け取る事ができます。   
    NSDate* date = [[aNotification userInfo] objectForKey:@"date"];
    NSString* title = [[aNotification userInfo] objectForKey:@"title"];
    NSNumber* count = [[aNotification userInfo] objectForKey:@"count"];
    
    //なにかしら処理

}

通知が不要になったら解除しておきます。
dealloc等に書いておくのがよいのではないでしょうか?

[[NSNotificationCenter defaultCenter] removeObserver:self];

以上

GCDを使って並列処理

Grand Central Dispatch(GCD)を使って並列処理を行うサンプルです。

ポイント
・dispatch_group_tを作成
・dispatch_queue_tの廃棄を行う為にdispatch_group_notifyを仕込む
・UIの変更等はメインスレッドで実行
・共通変数へのアクセスは @synchronized を使ってロックする
・dispatch_group_asyncのブロック内に autoreleasepool を作る

//GCDで複数のジョブを並列で実行してみるサンプル
-(void)gcdTest1
{
    dispatch_queue_t queue_main = dispatch_get_main_queue();
    dispatch_queue_t queue_job = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_t group = dispatch_group_create();
  
    NSObject* syncRoot = [[NSObject new]autorelease];//スレッド間の同期用
    __block int counter = 0;
  
    for (int i=0; i<5; i++) {
   
        dispatch_group_async(group, queue_job, ^{
          @autoreleasepool{
              if (i==0)
              {
                  //グループの終了処理を登録しておく
                  //ここではqueue_mainを渡していますが、mainでこのスレッドを待機しているような状況では
                  //デッドロックが起こりますので、その場合はqueue_jobを渡して下さい。
                  dispatch_group_notify(group, queue_main, ^{
                      //dispatch_group_tをリリース
                      dispatch_release(group);
                  
                      //なにか処理を実行(メインスレッドで実行される)
                      NSLog(@"finish group job counter = %d",counter);
                  
                  });
              }
          
              //(ジョブを実行する)
          
              @synchronized(syncRoot){ //共通変数などへのアクセスは@synchronizedを使ってロックする
                  counter += i;
              }
          }
        });
    }
  
    //終了を待機する時は下記のコードで待ちます
    //待機させる時は dispatch_group_notify でリリースさせる必要はなく、
    // ※1でリリースすればOK
    //NSLog(@"waiting...");
    //dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    //dispatch_release(group); //※1
}

上記ではdispatch_group_asyncを複数回発行して並列処理をさせていますが、単純にforを置き換えるような使い方であれば dispatch_apply を使ったら簡単に並列処理が可能です。
ただ、dispatch_applyは処理をロックしてしまいますので、完全に非同期で実行する場合には dispatch_async、dispatch_group_asyncのブロック内でdispatch_applyを実行する事が必要です。

外からは読み込み専用で内からは読み書き可能なプロパティ

まぁ、表題の通りなんですけど、たまにこういう内と外でスコープが異なるプロパティ必要ですよね。

C#とかだとアクセサにスコープを設定できるので簡単なんですけど、objective-cだとどうするのか?
色々調べたんですけど、超簡単に出来る事が分かりました。

要約すると
・interfaceではプロパティをreadonlyで宣言しておく
・implementationではプロパティを同じ名前、型でreadwriteで宣言する
そんだけです。

ヘッダファイルにはこんな感じに書いて


@interface Hoge : NSObject
{
}

@property (nonatomic,readonly) NSString* accountName;

@end

ソースファイルには上のプロパティを無名カテゴリで再宣言します

@interface Hoge ()

@property (nonatomic,readwrite,retain) NSString* accountName;

@end

@implementation Hoge

-(void)dealloc
{    
    [_accountName release];
    
    [super dealloc];
}

@end


こんな事出来るんですねぇ
objective-c、、自由過ぎる(笑)

objective-cでマルチスレッド処理(GCD)

Grand Central Dispatch(以下GCD)を使うと、マルチスレッド処理が非常に簡単に行えちゃいます。

使用方法やシチュエーションは色んなパターンがあるのですが、一番利用するであろう重たい処理を別スレッドで実行させるパターンをメモっておきます。
重たい処理をメインスレッドで実行すると再描画が行われなくなったりユーザ操作に反応しなくなるので必須ですよ。


//GCDで非同期処理実行
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),^{

  //スレッド内では個別の autoreleasepool を作成する
  @autoreleasepool{

    // [重たい処理を実行する]

    dispatch_sync(dispatch_get_main_queue(), ^{

      // [メインスレッドでUIの更新を行う]

    });
  }
});

このほかにも dispatch_apply や dispatch_group_wait を使うと簡単に並列処理もできますよ。
これは別の機会に書きますね。
(→書いてみました)