一畳のくつろぎタイム

このブログでは紹介する商品画像をAmazonアソシエイトより借りています。画像やリンクにはアフィリエイト広告が含まれる事があります
ラベル Swift の投稿を表示しています。 すべての投稿を表示
ラベル Swift の投稿を表示しています。 すべての投稿を表示

2018年9月20日木曜日

UITabBarControllerでタブがありすぎる時の挙動

AppleのUITabBarControllerの説明に以下のようにある。

The tab bar has limited space for displaying your custom items. If you add six or more custom view controllers to a tab bar controller, the tab bar controller displays only the first four items plus the standard More item on the tab bar. Tapping the More item brings up a standard interface for selecting the remaining items.

かいつまんで日本語にすると、タブバーは6個目からは配置するスペースがないので、最初の4つだけ出て、他はMoreになるよ。
 ということである。もうちょっと書いてあるが、上3行ぐらいでとりあえず知りたいことはわかった。最後の行が何を言ってるのかよくわからなかったが試したらよくわかった。

 Moreをアクションシート的なものを想像していたら全然違ったので、記事にしています。

検証としてはタブを10個用意。
わかりやすいように背景色をランダムに生成し、ボタンを配置して画面の番号を表示しています。


 Moreを押すと、入りきらなかった画面4〜画面9タブの名前が入ったテーブルビューが登場。選ぶとその画面にいけるが、自動的にナビゲーションバーのようなものが付属する。
最初の4タブについては、余計なものはついてこない。しかもEdit機能があり最初の4タブとの入れ替えが可能だという。

使う機会はないと思うが、面白い挙動だった。

検証で使用したコードはこちら
https://github.com/snowfoxj/TabBarControllerTestCode

2018年9月5日水曜日

SwiftのOptionalがうざいところ

Swiftのオプショナルがうざい

なにがうざいかと言うと、なかったら作る処理が簡潔に書けない。

コードオンリーでUITableViewを作っていると、UITableViewCellを作るときにdequeueReusableCellメソッドがnilを返した場合に新しくインスタンスを作り、nilでなければメソッドより返された値を使う。
??演算子を使用すれば、それに近いことはできる。だがしかし、新たに作成したUITableViewCellの初期設定がしたいのだ。??の後ろが1行じゃ足りなくて、もう少し行が欲しい。
        let cell:UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "hoge") ?? UITableViewCell(style: .default, reuseIdentifier: "hoge")
Objective-Cの場合、至ってシンプルである。nilだったら作って設定すればいい。
- (nonnull UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath {
    
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"hoge"];
    
    // 再利用セルがない場合は
    if( cell == nil ) {
        // 作成する
        cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"hoge"];
        // ここで作ったcellの共通設定
    }
    
    // ここで内容の更新処理
     
    return cell;
}



Swiftの場合、guard文だと処理の中断が必須なため。guard文の中と外で2回内容の更新処理を書かなくてはならなくなる
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "hoge") else {

            let cell = UITableViewCell(style: .default, reuseIdentifier: "hoge")
            
            // 初期設定

            // 内容の更新処理
            
            return cell
        }


        // 内容の更新処理
        

       return cell
    }

オプショナルバインディングだと大した処理がないのに、代入のためだけのif-else両方が必要になる
        let cell:UITableViewCell
        
        if let unwrappedCell = tableView.dequeueReusableCell(withIdentifier: "hoge") {
            cell = unwrappedCell
        } else {
            cell = UITableViewCell(style: .default, reuseIdentifier: "hoge")
            // 初期設定
        }

        // 内容の更新処理

        return cell
外のスコープに変数を用意するぐらいだったら、オプショナルバインディングなどいらぬ。
以下のようにオプショナル構文を使わないで書いたって同じことだ。
        // セルの再利用可能か取得して見る
        let optCell:UITableViewCell? = tableView.dequeueReusableCell(withIdentifier: "hoge")
        
        let cell:UITableViewCell
        
        if optCell == nil {
            cell = UITableViewCell(style: .default, reuseIdentifier: "hoge")
            
            // 初期設定をする
            
        } else {
            // アンラップする
            cell = optCell!
        }
        
        // 内容の更新処理をする
        
        return cell
わずかではあるが、変数を2個用意しないで済むオプショナルバインディングを使った方が簡潔なのがなんか腹立たしい。

内容の更新処理をメソッド化すれば2回同じことは書かないで済むし、UITableViewCellのサブクラスを作れば??演算子でいけますが、だがObjective-Cと同じことができないのがなんかうざい。
??演算子の後ろにすぐ実行するUITableViewCellを戻り値とするクロージャ書いたらなんかできそうな気がするも、邪道な感じがして試したくもない。

とりあえず外のスコープの変数用意しておいて、オプショナルバインディグが正攻法かなと思う。



2018年6月18日月曜日

Swift3,Swift4で乗算のループ

Swift3以上?Swift4でObjective-Cで書いたfor文1000まで10倍の乗算ループを書こうとしたら
for( int i=1; i<1000; i*=10 ) {
    NSLog(@"Hello %d",i);
}
予想以上に面倒で困った、詳細は不明だが、こうかけば期待通りに動いた
参照先https://code-examples.net/ja/q/2636c3a
// 乗算ループの書き方
let num = 1000
for i in sequence(first: 1, next: { $0 * 10 }).prefix(while: { num/$0 > 0 }) {
    print(i)
}
while文が残っていて本当によかったと感じる、Swift4以降でもうちょっと簡単な構文を期待したい。
var i = 1

while( i <= 1000 ) {
    print(i)
    i *= 10
}