Koichi Adachi

smart phone app development tips

Swiftでclass名取得

Swiftでクラス名を取得するとき、namespaceまでついてきちゃうので、困った。 ※NSStringFromClass(MyViewController)だと「ProjectName.MyViewController」になる。

ので、こんな方法で取得してみた。

NSStringFromClass(MyViewController).componentsSeparatedByString(".").last!

namespaceやclass名は、そのものズバリ!というメソッドくらいは用意してあった方がいいのだと思うけど。 暫定的にはこんな感じで対処。

SwiftでUITableView

Arrayに突っ込む方をTupleにしてみた。

import UIKit

class ViewController: UIViewController, UITableViewDelegate , UITableViewDataSource{
    typealias cellInfo = (value1 : String, value2 : String)
    
    let cellIdentifier = "Cell"
    @IBOutlet strong var tableView: UITableView = UITableView()
    
    var _dataSource : Array<cellInfo> = Array<cellInfo>()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        createDataSource();
        tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: cellIdentifier)
    }
    
    func createDataSource(){
        _dataSource.append(cellInfo(value2:"2", value1:"1"))
    }
    
    func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int{
        return _dataSource.count
    }
    func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell{
        var cell : AnyObject! = tableView.dequeueReusableCellWithIdentifier(cellIdentifier);
        cell.textLabel!.text = _dataSource[indexPath.row].value2
        return cell as UITableViewCell;
    }

}

Tupleを使うとEntityクラスっぽいのを作らなくて済むからスッキリする

先取り!Swift

先取り!Swift

Swift Tuple

Swift複数の値を持った戻り値を扱える。

class ExamTuple{
    class func execute()->(){
        
        var ret  = self.exam()
        println(ret.value1 + ret.value2)
        println("\(ret.value1 + ret.value2)")
        println(self.exam().0 + self.exam().1 )
    }
    class func exam()->(value1 : String, value2 : String, value3 : Int){
        return ("一個目", "2個目", 1)
    }
}

関数定義で戻り値それぞれに名前を付けることも出来るし

class ExamTuple{
    class func execute()->(){
        
        var ret  = self.exam() as (name : String, name2 : String, value : Int)
        println(ret.name + ret.name2)
        println("\(ret.name + ret.name2)")
        println(self.exam().0 + self.exam().1 )
    }
    class func exam()->(String, String, Int){
        return ("一個目", "2個目", 1)
    }
}

名前が無ければ、利用側で付けることも出来る

class ExamTuple{
    class func execute()->(){
        
        var ret  = self.exam() as (name : String, name2 : String, value : Int)
        println(ret.name + ret.value2)  //value2でコンパイルエラー
        println("\(ret.name + ret.name2)")
        println(self.exam().0 + self.exam().1 )
    }
    class func exam()->(value1 : String, value2 : String, value3 : Int){
        return ("一個目", "2個目", 1)
    }
}

利用側で上書きした場合は、関数定義で付けた名称は使えない

詳解 Objective-C 2.0 第3版

詳解 Objective-C 2.0 第3版

Remove all ads

Swiftで三項演算子

: Stringは省略可能 まだ目が慣れない〜

import Foundation

class ExamTernaryConditionalOperator{
    class func execute() -> (){
        self.innnerMethod(__FILE__)
    }
    
    class func innnerMethod(string :String?){
        let str:String = string!
        var ret = str.hasPrefix("aa")
        
        var v : String
            = ret == true
                    ? "真"
                    : "偽"
        println(v)
    }
}

詳解 Objective-C 2.0 第3版

詳解 Objective-C 2.0 第3版

Swiftのnil許容型を扱う

override func prepareForSegue(segue: UIStoryboardSegue?, sender: AnyObject?){
    if segue{
        println(segue!.identifier)
    }

    if let s = segue{
        println(s.identifier)
    }

    var s2 = segue!
    println(s2.identifier)

    let s3 = segue!
    println(s3.identifier)

    println(segue!.identifier)

}

if segue{ }で、segueが存在したら〜

if let s = segue{ }で、定数値sを定義して、segueをsに代入。sが存在したら〜

segue!をやるならvarでもletでもあんまり意味ない。

println(segue!.identifier) 短く書くなら、これでOK。

エキスパートObjective-Cプログラミング ?iOS/OS Xのメモリ管理とマルチスレッド?

エキスパートObjective-Cプログラミング ?iOS/OS Xのメモリ管理とマルチスレッド?

block構文で再帰処理を書いてみる(NSNullを削除)

いまのところの最新はこれ。 もうちょっとすっきり書きたいなぁ

    id (^func)(id);
    __block __weak id (^weak_func)(id) = func = (id) ^(id collection){
        __block id mutableDic = [@{} mutableCopy];
        [collection enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
            if(obj == [NSNull null]){
                return;
            }
            [mutableDic setObject:[obj isKindOfClass:[NSDictionary class]] ? weak_func(obj) : obj
                           forKey:key];
        }];
        return [NSDictionary dictionaryWithDictionary:mutableDic];
    };

実行してみる

    NSDictionary *source = @{@"k1": @"v1"
                             ,@"k2": @"v2"
                             ,@"k3": [NSNull null]
                             ,@"k4": @{@"k4-1": @"v1"
                                       ,@"k4-2": @"v2"
                                       ,@"k4-3": [NSNull null]
                                       ,@"k4-4": @"v4"
                                       }
                             };
    NSLog(@"加工前 %@", [source description]);
    id changdSource = func(source);
    NSLog(@"加工後 %@", [changdSource description]);

初期状態。アドバイスをもらって↑になった。

    __block __weak id (^weak_func)(id);
    id (^func)(id);
    weak_func = func = (id) ^(id dic){
        __block NSMutableDictionary *mutableDic = [dic mutableCopy];
        [mutableDic enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
            if(obj == [NSNull null]){
                [mutableDic removeObjectForKey:key];
            }else if([obj isKindOfClass:[NSDictionary class]]){
                obj = weak_func(obj);
                [mutableDic setObject:obj forKey:key];
            }
        }];
        return mutableDic;
    };

詳解 Objective-C 2.0 第3版

詳解 Objective-C 2.0 第3版

Block構文で記述した処理をインスタンスメソッドとして動的追加し、selectorで受けられるようにする

特定のクラスのインスタンスしか受けられないメソッドを、
新しくクラス定義せずに受けられるようにする方法。
さらにイマイチなことに、呼び出したいメソッドがコールバックにSEL型しか指定できなかったりする。
新しくクラス定義(.hと.m)を追加するのも微妙だったため、
「好きなように書いたblockをインスタンスメソッドとして動的に追加」することで解消してみた。

手順
①コールバック時に処理したい内容をブロック構文で作成
②トリガーとなる処理の中で代理インスタンスを生成
③クラスにメソッドを動的追加
④任意のメソッドに①を渡す

-(void)method1{
    void (^myBlock)(id, NSInteger, NSString *, NSInteger, NSInteger) = ^(id selfInstance, NSInteger value1, NSString *value2, NSInteger value3, NSInteger value4)
    {
        NSLog(@"myBlock : %@", value2);
    };
    
    UIViewController *vc = [[UIViewController alloc] init];
    SEL sel = NSSelectorFromString(@"value1:value2:value3:value4:");
    IMP imp = imp_implementationWithBlock(myBlock);
    class_addMethod([vc class], sel, imp, "vi:*:i:i");
    [AdSDK sendWithViewController:vc callback:sel];
}

init時、vcはセレクタを持っていないが、
AdSDK sendWithViewController:callback:
呼び出しまでの間に動的に加えているためにできる。

詳解 Objective-C 2.0 第3版

詳解 Objective-C 2.0 第3版