月別アーカイブ: 2013年7月

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

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

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 を使うと簡単に並列処理もできますよ。
これは別の機会に書きますね。
(→書いてみました)

NSArrayのソート方法 (NSSortDescriptorを使って)

NSArrayのソート方法は色々あるんですけど、その中でNSSortDescriptorを使った方法をメモっておきます。
この方法はオブジェクトのプロパティ値の単純比較でソート出来る時に有効ですよ。

プロパティに「ValA」「ValB」があるオブジェクトを、ValAの昇順+ValBの降順でソートするサンプルです。


NSSortDescriptor* sortA = [[[NSSortDescriptor alloc]initWithKey:@"ValA" ascending:YES]autorelease];
NSSortDescriptor* sortB = [[[NSSortDescriptor alloc]initWithKey:@"ValB" ascending:NO]autorelease];

[_dataArray sortUsingDescriptors:@[sortA, sortB]];

※@[ A , B ] の記述はNSArrayを作成する記述です

この例のように “sortUsingDescriptors:” を使った場合にはレシーバー内の要素がソートされますし、”sortedArrayUsingDescriptors:” を使えばソート済のNSArrayが返されます。

[WPF]押下するとイメージが切り替わるボタンの作り方

押下時にイメージが切り替わるボタンって頻繁に使うと思うのですが、標準では無いですよね??
xamlいじればできるのはわかるのですが、これくらいは用意してくれてても。。とか思ったりして。
色々調べるの面倒っす。

愚痴はおいておいて、イメージが切り替わるボタンのサンプルです。
最初にxaml内にControlTemplateを定義します。

<Window.Resources>

<ControlTemplate x:Key="buttonTemplate" TargetType="Button">
    <Border Name="border" BorderThickness="0" BorderBrush="Transparent">
        <Border.Background>
            <ImageBrush ImageSource="普段のイメージ.png" />
        </Border.Background>
        <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
    </Border>
    <ControlTemplate.Triggers>
        <Trigger Property="IsPressed" Value="True">
            <Setter TargetName="border" Property="Background" >
                <Setter.Value>
                    <ImageBrush ImageSource="押下された時のイメージ.png" />
                </Setter.Value>
            </Setter>
        </Trigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

</Window.Resources>

ちょっと説明しますと、ボタンの表示をBorderコントロールで行うようにして、そのBackgroundイメージを
プロパティトリガーにより切り替えるようにしています。

で、これをButtonに設定すればOKです。
こんな感じですね。

<Button  Height="90" Width="90"  Template="{StaticResource buttonTemplate}"/>

Buttonのタグ内に直接記述する場合には下記のようになります。

<Button Height="90" Width="90" >
<Button.Template>

    <ControlTemplate  TargetType="Button">
        <Border Name="border" BorderThickness="0" BorderBrush="Transparent">
            <Border.Background>
                <ImageBrush ImageSource="普段のイメージ.png" />
            </Border.Background>
            <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
        </Border>
        <ControlTemplate.Triggers>
            <Trigger Property="IsPressed" Value="True">
                <Setter TargetName="border" Property="Background" >
                    <Setter.Value>
                        <ImageBrush ImageSource="押下された時のイメージ.png" />
                    </Setter.Value>
                </Setter>
            </Trigger>
        </ControlTemplate.Triggers>
    </ControlTemplate>

</Button.Template>
</Button>

スタイルを書き換えても対応出来そうだったのですが、どうしても上手くいかなかったので
テンプレートを使って対応しました。

あ、そうそう、「IsChecked」に対してのTriggerを追加すればトグルボタンになりますよ。

以上

隣接したQuadKeyを求める

googleマップ、Bingマップなどで使用するクアッドキー
大変良く出来たキー体系で、設計者の頭の良さが想像できますね。

さて、ちょっと地図情報を扱う上で、並んだQuadKeyを求める必要がありましたので
プログラムを書いてみました。

今回はjavaですが、簡単なソースなので他の言語へも適用しやすいと思います。

/**
 * 指定されたキーの隣にあたるQuadKeyを求める
 * @param srcKey 元のQuadKey
 * @param direction 0:左 1:右 2:上 3:下
 * @return
 */
private static String calcNextQuadKey(String srcKey,int direction)
{
     int lv = srcKey.length();

     long latbits = 0;
     long lonbits = 0;
     char c;
     int val;
     int bit;

     for (int i = 0; i < lv; i++) {
          c = srcKey.charAt(i);
          val = c - '0';

          // valの2ビット目を縦位置を示すlatbitsに格納
          bit = val >> 1;
          latbits += (bit << (lv - i - 1));

          // valの1ビット目を横位置を示すlonbitsに格納
          bit = val & 1;
          lonbits += (bit << (lv - i - 1));
     }

     // 隣接したQuadKeyを求めるためlat、lonを変更
     switch (direction) {
     case 0:// 左
          lonbits -= 1;
          break;
     case 1:// 右
          lonbits += 1;
          break;
     case 2:// 上
          latbits -= 1;
          break;
     case 3:// 下
          latbits += 1;
          break;
     }

     // lv以上の精度に繰り上がった場合には最上位ビットをクリアする
     long floodmask = 1 << lv;
     if ((lonbits & floodmask) != 0) lonbits ^= floodmask;
     if ((latbits & floodmask) != 0) latbits ^= floodmask;

     // latbits、lonbitsからクアッドキーを求める
     StringBuilder sb = new StringBuilder(lv);
     long mask = 1 << (lv - 1);
     boolean lonbit, latbit;
     for (int i = 0; i < lv; i++) {

          lonbit = ((lonbits & mask) != 0);
          latbit = ((latbits & mask) != 0);

          if (latbit) {
               c = lonbit ? '3' : '2';
          } else {
               c = lonbit ? '1' : '0';
          }
          sb.append(c);

          mask >>>= 1;
     }
     return sb.toString();

}

以上.