統計情報(30日間)


最新情報をツイート


人気の投稿

数万の位置情報を高速に地図へプロットする方法

このエントリーをはてなブックマークに追加

大量の位置情報を地図上でうまく扱う為のデータ構造や描画方法の解説。



位置情報の格納がDBのレコードのような簡単な構造だと検索に時間がかかる。この時間を短縮する為に Quad Tree を採用している。

これは図のようにエリアを4分割して、それを再帰的に保持するデータ構造を持つ。構造体の定義はこう。
typedef struct TBQuadTreeNodeData {
    double x;
    double y;
    void* data;
} TBQuadTreeNodeData;
TBQuadTreeNodeData TBQuadTreeNodeDataMake(double x, double y, void* data);

typedef struct TBBoundingBox {
    double x0; double y0;
    double xf; double yf;
} TBBoundingBox;
TBBoundingBox TBBoundingBoxMake(double x0, double y0, double xf, double yf);

typedef struct quadTreeNode {
    struct quadTreeNode* northWest;
    struct quadTreeNode* northEast;
    struct quadTreeNode* southWest;
    struct quadTreeNode* southEast;
    TBBoundingBox boundingBox;
    int bucketCapacity;
    TBQuadTreeNodeData *points;
    int count;
} TBQuadTreeNode;
TBQuadTreeNode* TBQuadTreeNodeMake(TBBoundingBox boundary, int bucketCapacity);

最初が緯度・経度を持つ位置情報、2番めが境界、3番めがノード情報で自領域内の4つの子ノードを保持する。
1次元配列に比べて検索パスが激減するので効率よく目的の位置データを見つけ出せる。

その他、クラスタリングの方法(拡大レベルに応じて複数の位置情報を1つにまとめる)、アノテーション描画の最適化(1度置いたものを再利用)など、いろいろなテクニックについての解説がある。面白い。


乱数には arc4random_uniform ( ) を使え

このエントリーをはてなブックマークに追加

「arc4random() % N」は modulo bias があるので代わりに「arc4random_uniform (N)」を使うことが紹介されている。その他、NSArrayでのランダムなインデックス指定や、ランダムな並び替え、ランダムな文字列の生成方法など。




関連情報


また、実はarc4random()はランダム性に少しバイアスが掛かっています。arc4random()は0から2^32-1の値を返すため、それの法をとる際に微妙にランダム性が崩れるのです(modulo bias:0から10の値をとるランダム値のモジュロ7の法をとると、0-3の出現割合は4-6の二倍になりますね)。ただし、MAX_NUMが2の累乗であれば完全にランダムとなります。
なるほど。

UICollectionViewでエンドレススクロールを実現する方法

このエントリーをはてなブックマークに追加

タネは簡単で(1)先頭と最後にコンテンツの複製を作っておき追加(2)最後へスクロールしたら先頭へ移動・先頭へスクロールしたら最後へ移動する。


スクロール指示のタイミングは -[UIScroll scrollViewDidEndDecelerating:] でハンドリングする。
-(void)scrollViewDidEndDecelerating:(UIScrollview *)scrollview {

    // Calculate where the collection view should be at the right-hand end item
    float contentOffsetWhenFullyScrolledRight = self.collectionView.frame.size.width * ([self.dataArray count] -1);

    if (scrollView.contentOffset.x == contentOffsetWhenFullyScrolledRight) {

        // user is scrolling to the right from the last item to the 'fake' item 1.
        // reposition offset to show the 'real' item 1 at the left-hand end of the collection view

        NSIndexPath *newIndexPath = [NSIndexPath indexPathForItem:1 inSection:0];

        [self.collectionView scrollToItemAtIndexPath:newIndexPath atScrollPosition:UICollectionViewScrollPositionLeft animated:NO];

    } else if (scrollView.contentOffset.x == 0)  {

        // user is scrolling to the left from the first item to the fake 'item N'.
        // reposition offset to show the 'real' item N at the right end end of the collection view

        NSIndexPath *newIndexPath = [NSIndexPath indexPathForItem:([self.dataArray count] -2) inSection:0];

        [self.collectionView scrollToItemAtIndexPath:newIndexPath atScrollPosition:UICollectionViewScrollPositionLeft animated:NO];

    }
}
なおこの方法が使えるのは paging=YES のケースだけ。



Objective-CでJS風のメソッドチェーンを実装する

このエントリーをはてなブックマークに追加

@k_katsumi さんが VerbalExpressions の Objective-C向けライブラリを公開。



VerbalExpressions とは元々 JavaScript由来のもので、メソッドチェーンを組み合わせて正規表現相当を表現するテクニックらしい。

本家にマージされたとのこと(祝)。


こんな感じで書ける。Objective-Cというよりは本家のJavaScriptっぽい書き方。ドット記法で引数を取る書き方が新鮮。こんな風に記述できるのか。
// Create an example of how to test for correctly formed URLs
VerbalExpressions *verEx = [VerbalExpressions instantiate:^(VerbalExpressions *ve) {
    ve.startOfLine(YES)
    .then(@"http")
    .maybe(@"s")
    .then(@"://")
    .maybe(@"www")
    .anythingBut(@" ")
    .endOfLine(YES);
}];

実装のポイントは Blocksをプロパティ定義しているところ。
@interface VerbalExpressions : NSObject

@property (nonatomic, readonly) VerbalExpressions *(^startOfLine)(BOOL enable);
@property (nonatomic, readonly) VerbalExpressions *(^endOfLine)(BOOL enable);
@property (nonatomic, readonly) VerbalExpressions *(^find)(NSString *value);
@property (nonatomic, readonly) VerbalExpressions *(^then)(NSString *value);
@property (nonatomic, readonly) VerbalExpressions *(^maybe)(NSString *value);
@property (nonatomic, readonly) VerbalExpressions *(^anything)();
@property (nonatomic, readonly) VerbalExpressions *(^anythingBut)(NSString *value);
引数を取り、自身を返す Blocksをプロパティとして定義している。

そしてプロパティの実体を用意する。
- (VerbalExpressions *(^)(NSString *))maybe
{
    return ^VerbalExpressions *(NSString *value) {
        value = [self sanitize:value];
        self.add([NSString stringWithFormat:@"(%@)?", value]);
        return self;
    };
}
自身を返すことでメソッドチェーンを構成できる。

- - - -
ドット記法で引数を渡す表現ができるとは。眼から鱗。
この発想は無かった。面白い。


コードレビューリスト

このエントリーをはてなブックマークに追加

Objective-C のコードレビュー用チェックリストの翻訳。レビューだけでなく、コーディング時ににもとても有用。日本語訳もいい。


引数の非NULL属性を明示する nonnull やオーバライドを必須にする objc_requires_superなど初めて知った。
void foo(void *p) __attribute__((nonnull)) {
}
- (void)foo:(id)arg __attribute__((objc_requires_super)) {
}

他にも品質を上げる為の指針などが書かれていて参考になった。

なめらかな線を描く

このエントリーをはてなブックマークに追加

署名(クレカのサインなど)をなめらかに描く方法の解説。


タッチを単純に追うだけだとガクガク。


そこでサンプル点間の中間点を割り出し、BezierPathで描く。


コードは難しくない。
static CGPoint midpoint(CGPoint p0, CGPoint p1) {
    return (CGPoint) {
        (p0.x + p1.x) / 2.0,
        (p0.y + p1.y) / 2.0
    };
}

- (void)pan:(UIPanGestureRecognizer *)pan {
    CGPoint currentPoint = [pan locationInView:self];
    CGPoint midPoint = midpoint(previousPoint, currentPoint);

    if (pan.state == UIGestureRecognizerStateBegan) {
        [path moveToPoint:currentPoint];
    } else if (pan.state == UIGestureRecognizerStateChanged) {
        [path addQuadCurveToPoint:midPoint controlPoint:previousPoint];
    }

    previousPoint = currentPoint;

    [self setNeedsDisplay];
}

するとこうなる。

方法は単純だが効果的。

記事ではさらに筆跡を真似る為に線の太さを可変にする事にも触れられている。


ただCoreGraphicsでは可変幅の線は描けないので OpenGL ES を使って実装している。


この記事の中で紹介されていた square での署名描画記事。
こちらはAndroidでの実装。

CFStringFind は約9倍高速

このエントリーをはてなブックマークに追加

NSString#rangeOfString: と CFStringFind の速度比較。日本語文字列で大文字小文字区別有りの検索を1万回行った場合、最大で約9倍近い開きが出たとのこと。英語文字列の場合でも平均 2倍程度の差。
大量データを対象とした検索を行う場合は効果が出そう(そんなケースがもしあればだが)。



UICollectionViewLayoutでカバーフロー

このエントリーをはてなブックマークに追加

こういう感じ。


説明が詳細で分かりやすい。

GitHubでソースが公開されている。

今後 UICollectionViewLayout のバリエーションが増えると簡単にリッチなUIが作れそう。


1枚の画像から色のバリエーションを作る方法

このエントリーをはてなブックマークに追加

-[UIImage drawInRect:blendMode:alpha:]のブレンドモードを活用した色バリエーションの作り方。



こういうのをプログラムで色をつけて


こうする


やり方はシンプル

 1. image context を作成
 2. 指定の色で塗りつぶし
 3. ブレンドモードを指定して、画像を上書き。
 4. カレントcontextからUIImageを取り出す。

なお元となる画像はあらかじめ背景を透明にしてアルファチャンネルを持っておく(pngなどを使う)。

コードはこんな感じ。
- (UIImage *)tintedImageWithColor:(UIColor *)tintColor blendingMode:(CGBlendMode)blendMode
{
    UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0f);
    [tintColor setFill];
    CGRect bounds = CGRectMake(0, 0, self.size.width, self.size.height);
    UIRectFill(bounds);
    [self drawInRect:bounds blendMode:blendMode alpha:1.0f];

    if (blendMode != kCGBlendModeDestinationIn)
        [self drawInRect:bounds blendMode:kCGBlendModeDestinationIn alpha:1.0];

    UIImage *tintedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return tintedImage;
}

アプリアイコンにバージョン番号を入れるアイディア

このエントリーをはてなブックマークに追加

ImageMagicとghostscript(font)を利用してビルド時に自動的に黒字に白文字をアイコン画像に重ね合わせる方法が紹介されている。

こんな感じ。


テスト時に一目でバージョンが分かるのでこれはなかなか良いアイディア。



テーブルセルにコレクションビューを入れる

このエントリーをはてなブックマークに追加

UITableViewCell に UICollectionView を入れる記事。特に難しいことはやっていない(と思う)。


サンプルプログラム


実機で触ってみたが意外に悪くない。今後の定番テクニックになったりして。

UINavigationControllerのトランジションカスタマイズ

このエントリーをはてなブックマークに追加

pushViewController:animated:をオーバーライドしてカスタムなトランジションに置き換える方法が紹介されている。


UIViewをつかったものとCATransitionを使った方法など。丁寧な説明でわかりやすい。

UICollectionView のカスタマイズ例

このエントリーをはてなブックマークに追加

UICollectionView をカスタマイズするとこういうのもできるのか。面白い。

RouletteWheelCollectionViewDemo from kenshin03 on Vimeo.


UICollectionViewFlowLayout のカスタマイズ例として参考になる。



3行で書けるフィルタ

このエントリーをはてなブックマークに追加

Core Animation / レイヤーを使ったぼかし効果の作り方。面白い。



引用
たった3行で書ける、iPhoneでお手軽ガウシアンフィルタ
特別なライブラリやカテゴリを使わなくても、iOS標準のフレームワークだけで、超簡単にガウシアンフィルタ(ぼかし効果)をかけるテクニックを紹介します。
この方法を応用すれば、ごく短いコードで、さらにモザイクフィルタや、アニメーションにまで使えてしまう優れモノです。

記事では文字への適用や、モザイク、アニメーションへの応用など。

デバッグログをオーバレイするカスタムウィンドウ

このエントリーをはてなブックマークに追加

カスタムなUIWindowを用意してアプリの前面にデバッグログを表示する。





解説資料あり↓



なかなかいいアイディア。