hachinoBlog

hachinobuのエンジニアライフ

Swiftのインスタンスから型メソッド(クラスメソッド)を呼び出す方法

背景

あるクラスのインスタンスから、そのクラスの型メソッド(クラスメソッド)を呼び出したいときにObjective-Cでは下記のようにやっていたけれどSwiftだとどう書くのか知りたかった

[[instance class] classMethod];

結論

dynamicTypeを使うことでインスタンスから型メソッド(クラスメソッド)へのアクセスが可能になる

class SampleClass() {

  //型メソッド(クラスメソッド)
  static func sampleClassMethod() {
    print("sampleClassMethod")
  }

}

//普通の型メソッド(クラスメソッド)の呼び出し方
SampleClass.sampleClassMethod()  //sampleClassMethod

//インスタンスからクラスメソッドへのアクセス
let sampleClass = SampleClass()
sampleClass.dynamicType.sampleClassMethod() //sampleClassMethod

dynamicTypeとはなんぞや?

dynamicTypeを使うとインスタンスのクラス自身(サブクラス化されていればサブクラス)が参照できるようです

let sampleClass = SampleClass()
print(sampleClass.dynamicType) //SampleClass

if sampleClass.dynamicType == SampleClass.self {
  print("true") //true
}

tableViewCell上にUISliderを載せてアニメーションしたらおかしくなる件

事象

カスタムのUITableViewCell上にUISliderをaddしてcellforRowで読み込まれると同時にSliderをアニメーションしてみたのだけれど、minimumTrackTintColorとmaximumTrackTintColor割合がおかしく、明らかに変なアニメーションをしだした。

解決方法

Sliderのアニメーションをdispatch_afterで遅らせてやるとうまくいった。

ちなみに[UIView animateKeyframesWithDuration...のdelay:をセットしてもダメだった。

下記サンプルではtag10にUISliderが紐付けられているものとする。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        UISlider *slider = (UISlider *)[cell viewWithTag:10];
        slider.value = 0;
        [UIView animateKeyframesWithDuration:1 delay:0 options:UIViewKeyframeAnimationOptionAllowUserInteraction animations:^{
            [slider setValue:0.8 animated:YES];
        } completion:^(BOOL finished) {
            
        }];
    });
    
    return cell;
}

うまくいかない時は遅延処理させると解決するのは結構あるけど、 delayじゃなくdispatch_after使わないとダメだったとは。。

かなりの時間を使ってしまったので久しぶりにメモ。

Android Studio0.8.14にしたらエラーしまくった

背景

Android Studioのverを0.8.14にしたらエラーになったので解決方法をメモ

解決方法

まず、アップデートしているとAndroid Studio配下にsdkフォルダを配置するなと怒られるので、sdkの場所をmvコマンドで適当な場所に移す。

sdkを移した後にリトライすれば0.8.14に上がる。

Android Studioを起動した際にsdkがないと言われるので、sdkを移動したパスを設定する。

その後に、新規プロジェクト作成したら今度はAndroid APIの最新である21を使うにはjdk1.7を使えというエラー。

OracleからJava SE Development Kit 7u71をダウンロードしてjdkをjdk1.7.0_71.jdk/Contents/Homeを使うように設定してようやく動いた。

Android Studioはまだbeta版だからいろいろと仕様が変わるのですね。

ありえん。。

追記 新規でAndroid Studio0.8.14をインストールする場合はここが大変参考になります。

NSLayoutConstraintを使ってAutoLayoutをコードで書く

背景

AutoLayoutをxib上で使っているのだけれどxibでは表現できるAutoLayoutに限界があると思いコードで書く方法を調べたのでメモ。

サンプル

1.self.viewから左20,上20のマージンをとった位置にwidth100,height100の赤いViewを配置

    UIView *redView = [[UIView alloc] init];
    redView.backgroundColor = [UIColor redColor];
    redView.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview:redView];
    NSLayoutConstraint *redLeftConstraint = [NSLayoutConstraint constraintWithItem:redView
                                                                         attribute:NSLayoutAttributeLeft
                                                                         relatedBy:NSLayoutRelationEqual
                                                                            toItem:self.view
                                                                         attribute:NSLayoutAttributeLeft
                                                                        multiplier:1
                                                                          constant:20];
    
    NSLayoutConstraint *redTopConstraint = [NSLayoutConstraint constraintWithItem:redView
                                                                     attribute:NSLayoutAttributeTop
                                                                     relatedBy:NSLayoutRelationEqual
                                                                        toItem:self.topLayoutGuide
                                                                     attribute:NSLayoutAttributeTop
                                                                    multiplier:1
                                                                      constant:20];
    
    NSLayoutConstraint *redWidthConstraint = [NSLayoutConstraint constraintWithItem:redView
                                                                       attribute:NSLayoutAttributeWidth
                                                                       relatedBy:NSLayoutRelationEqual
                                                                          toItem:nil
                                                                       attribute:NSLayoutAttributeNotAnAttribute
                                                                      multiplier:1
                                                                        constant:100];
    
    NSLayoutConstraint *redHeightConstraint = [NSLayoutConstraint constraintWithItem:redView
                                                                        attribute:NSLayoutAttributeHeight
                                                                        relatedBy:NSLayoutRelationEqual
                                                                           toItem:nil
                                                                        attribute:NSLayoutAttributeNotAnAttribute
                                                                       multiplier:1
                                                                         constant:100];
    
    [self.view addConstraints:@[redLeftConstraint, redTopConstraint, redWidthConstraint, redHeightConstraint]];

f:id:hachinobu:20141103191352p:plain

f:id:hachinobu:20141103191351p:plain

2.self.viewのbottom部分に幅=端末幅,高さ40の青いView配置

    UIView *blueView = [[UIView alloc] init];
    blueView.backgroundColor = [UIColor blueColor];
    blueView.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview:blueView];
    NSLayoutConstraint *blueLeftConstraint = [NSLayoutConstraint constraintWithItem:blueView
                                                                             attribute:NSLayoutAttributeLeft
                                                                             relatedBy:NSLayoutRelationEqual
                                                                                toItem:self.view
                                                                             attribute:NSLayoutAttributeLeft
                                                                            multiplier:1
                                                                              constant:0];
    NSLayoutConstraint *blueRightConstraint = [NSLayoutConstraint constraintWithItem:blueView
                                                                              attribute:NSLayoutAttributeRight
                                                                              relatedBy:NSLayoutRelationEqual
                                                                                 toItem:self.view
                                                                              attribute:NSLayoutAttributeRight
                                                                             multiplier:1
                                                                               constant:0];
    NSLayoutConstraint *blueHeightConstraint = [NSLayoutConstraint constraintWithItem:blueView
                                                                            attribute:NSLayoutAttributeHeight
                                                                            relatedBy:NSLayoutRelationEqual
                                                                               toItem:nil
                                                                            attribute:NSLayoutAttributeNotAnAttribute
                                                                           multiplier:1
                                                                             constant:40];
    NSLayoutConstraint *blueTopConstraint = [NSLayoutConstraint constraintWithItem:blueView
                                                                        attribute:NSLayoutAttributeTop
                                                                        relatedBy:NSLayoutRelationEqual
                                                                           toItem:self.view
                                                                        attribute:NSLayoutAttributeBottom
                                                                        multiplier:1
                                                                          constant:-blueHeightConstraint.constant];
    [self.view addConstraints:@[blueLeftConstraint, blueRightConstraint, blueTopConstraint, blueHeightConstraint]];

f:id:hachinobu:20141103202832p:plain

f:id:hachinobu:20141103202833p:plain

3.self.viewのcenter座標に幅=self.view.frame.width/2 高さ=self.view.frame.height/2 の黄色Viewを配置

    UIView *yellowView = [[UIView alloc] init];
    yellowView.backgroundColor = [UIColor yellowColor];
    yellowView.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview:yellowView];
    NSLayoutConstraint *yellowCenterXConstraint = [NSLayoutConstraint constraintWithItem:yellowView
                                                                            attribute:NSLayoutAttributeCenterX
                                                                            relatedBy:NSLayoutRelationEqual
                                                                               toItem:self.view
                                                                            attribute:NSLayoutAttributeCenterX
                                                                              multiplier:1
                                                                                constant:0];
    NSLayoutConstraint *yellowCenterYConstraint = [NSLayoutConstraint constraintWithItem:yellowView
                                                                               attribute:NSLayoutAttributeCenterY
                                                                               relatedBy:NSLayoutRelationEqual
                                                                                  toItem:self.view
                                                                               attribute:NSLayoutAttributeCenterY
                                                                              multiplier:1
                                                                                constant:0];
    NSLayoutConstraint *yellowWidthConstraint = [NSLayoutConstraint constraintWithItem:yellowView
                                                                             attribute:NSLayoutAttributeWidth
                                                                             relatedBy:NSLayoutRelationEqual
                                                                                toItem:self.view
                                                                             attribute:NSLayoutAttributeWidth
                                                                            multiplier:.5
                                                                              constant:0];
    NSLayoutConstraint *yellowHeightConstraint = [NSLayoutConstraint constraintWithItem:yellowView
                                                                              attribute:NSLayoutAttributeHeight
                                                                              relatedBy:NSLayoutRelationEqual
                                                                                 toItem:self.view
                                                                              attribute:NSLayoutAttributeHeight
                                                                             multiplier:.5
                                                                               constant:0];
    [self.view addConstraints:@[yellowCenterXConstraint, yellowCenterYConstraint, yellowWidthConstraint, yellowHeightConstraint]];

f:id:hachinobu:20141103203343p:plain

f:id:hachinobu:20141103203344p:plain

共通する部分としてViewのtranslatesAutoresizingMaskIntoConstraintsプロパティは必ずNOにすること。

これをしないとAutolayoutが適用されない。

Viewを作成する際にinitWithFrame:で幅と高さを指定しても意味はないのでNSLayoutConstraintのメソッドで幅と高さの制約を作る必要がある。

組み合わせや使い方によっては柔軟なものができそうであるが、それにしてもNSLayoutConstraintはマゾい

なので今度Masonryを試してみようと思う。

iOS7とiOS8でUIScreenのboundsのサイズが違うので対応する

背景

iOS8からUIScreenのboundsを取得すると端末の向きに応じてwidthとheightの値が変更されるようになりLandscape対応でちょっと困ったのでメモ

iOS7とiOS8で差分を埋める

+ (CGSize)mainScreenSize 
{
    CGSize screenSize = [UIScreen mainScreen].bounds.size;
    if ((NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1) &&  UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) {
        return CGSizeMake(screenSize.height, screenSize.width);
    }
    return screenSize;
}

これでiOS7でもiOS8と同様のサイズを返すです。

重複件数まで取得できるNSCountedSet

背景

例えばこんな問題があったとする。

インプットした文字列の単語の重複件数を求めなさい。

例) banana

答) b: 1 a: 3 n: 2

この問題を何か効率的に処理できる方法はないかと考えたときにNSCountedSetを見つけたので使い方をメモ。

使い方

NSCountedSetはNSMutableSetのサブクラスなので当然、格納した際に重複しているものは取り除かれるのだが、取り除く際に重複のcount数を保持している。

なので上記の問題に対応するコードをNSCountedSetを使用して書くとこうなる。

    NSString *text = @"banana";
    NSCountedSet *countSet = [NSCountedSet set];
    int total = [text length];
    for (int i = 0; i < total; i++) {
        [countSet addObject:[text substringWithRange:NSMakeRange(i, 1)]];
    }
    for (NSString *word in countSet) {
        NSLog(@"%@:%@", word, @([countSet countForObject:word]));
    }

出力結果

b:1
a:3
n:2

ちょっと便利な気がするー。

git clone --recursive をするとサブモジュールも一緒に持ってきてくれる

背景

SDWebImageのDemoを動かしたくてgit cloneして動かしたらfile not foundでエラーになった。

解決方法

SDWebImageはサブモジュールを使用しているので、それも一緒に入れてやる必要がある。

なのでgit clone する際に --recursive オプションをつけてやるとサブモジュールも一緒に入れてくれる。

git clone --recursive https://github.com/rs/SDWebImage.git

Cloning into 'SDWebImage'...
remote: Reusing existing pack: 2754, done.
remote: Total 2754 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (2754/2754), 3.64 MiB | 294.00 KiB/s, done.
Resolving deltas: 100% (1600/1600), done.
Checking connectivity... done.
Submodule 'Vendors/libwebp' (http://git.chromium.org/webm/libwebp.git) registered for path 'Vendors/libwebp'
Cloning into 'Vendors/libwebp'...
remote: Counting objects: 11978, done.
remote: Compressing objects: 100% (3941/3941), done.
remote: Total 11978 (delta 9284), reused 10570 (delta 8029)
Receiving objects: 100% (11978/11978), 4.53 MiB | 431.00 KiB/s, done.
Resolving deltas: 100% (9284/9284), done.
Checking connectivity... done.
Submodule path 'Vendors/libwebp': checked out '68e7901da53cbda6ec93ddf93e039346d3c6a531'

--recursiveを使っていきましょー。