Rodhos Soft

備忘録を兼ねた技術的なメモです。Rofhos SoftではiOSアプリ開発を中心としてAndroid, Webサービス等の開発を承っております。まずはご相談下さい。

無限ループ

UICollectionViewを継承したクラスをつくり、layoutsubViewsで中心からコンテンツが1/4程度外れていたらContentOffSetを中央へ移動させるようにすれば良い。

                
        let totalContentWidth = CGFloat(cellCount) * cellWidth
        let centerOffsetX = totalContentWidth / 2 -  self.bounds.width / 2
        let distFromCentre = centerOffsetX - contentOffset.x
        
        if (fabs(distFromCentre) > totalContentWidth / 4) {
                        
            let moveOffsetX = CGFloat(centerRow()) * cellWidth
            
            if contentOffset.x < centerOffsetX {
                self.contentOffset = CGPoint(x: moveOffsetX , y:contentOffset.y)
            } else if contentOffset.x > centerOffsetX {
                self.contentOffset = CGPoint(x: moveOffsetX , y:contentOffset.y)
            }
        }

centerRow()は

    func centerRow()->Int {        
        guard contentCount > 0 else {
            return 0
        }
        let row = Int(cellCount/2/contentCount) * contentCount
        return row
    }

contentCountはコンテンツの数
cellカウントはセルの数(コンテンツの数の倍数ないし無限)

BehaviorSubject

BehaviorSubjectは最後の値を覚えていてsubscribeで即座に値が返ってくる。最初の値はこちらで指定できる。

class Temperature {
    private let behaviorSubject = BehaviorSubject(value:0)
    
    var behavior : BehaviorSubject<Int> {
        return behaviorSubject
    }
    
    func doSomething(x:Int) {
        behavior.onNext(x)
    }
}

のように初期値入りで定義しておく。

Observableと同様に登録すると、即座に最後の値(今回は初期として渡された0)を返してくる。

        _ = temperature.behavior.subscribe(
            onNext:{ label2.text = "\($0)"},
            onError: {_ in },
            onCompleted: { print("end")},
            onDisposed: { print("disposed")})

UITextViewの縦方向の中央寄せ

contentSizeをオブザーブして

        textView.addObserver(self, forKeyPath: "contentSize", options: .new, context: nil)

contentSizeに変化があれば、中身を調節する。

    
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if let textView = object as? UITextView {
            var topCorrect = (textView.bounds.size.height - textView.contentSize.height * textView.zoomScale) / 2
            topCorrect = topCorrect < 0.0 ? 0.0 : topCorrect;
            textView.contentInset.top = topCorrect
        }
    }

    deinit {
        textView.removeObserver(self, forKeyPath: "contentSize")
    }

Observable

次のようなクラスを定義する。

class Temperature {
    private let eventSubject = PublishSubject<Int>()
    var event: Observable<Int> {
        return eventSubject
    }
    
    func doSomething(x:Int) {
        eventSubject.onNext(x)
    }
    
}

テキストフィールドの編集が終わったタイミングで数を数えるということにしてみた。正しい書き方かはわからない。

        _ = textFiled?.rx.controlEvent(UIControlEvents.editingDidEnd).subscribe { event in
            self.temperature.doSomething(x: self.textFiled!.text!.lengthOfBytes(using: .utf16))
        }
        
        disposeTemp = temperature.event.subscribe(
            onNext: {print("\($0)")}
            , onError: {_ in },
              onCompleted: { print("end")},
              onDisposed: { print("diposed")}
        )

とめたいときはdisposeTempをdispose()すれば良い。

RXSwift

RxSwiftを試してみた。

CocoaPodでインストールした上で以下をインポート

import RxSwift
import RxCocoa

使い方は

        textFiled!.rx.text
            .map {
                guard let text = $0, text.lengthOfBytes(using:.utf16) > 0 else {
                    return ""
                }
                return "\(text)!"
            }
            .bindTo(label!.rx.text)
            .addDisposableTo(disposeBag)

これだけでラベルにテキストフィールドの値を加工したものが即時反映される。

継続モナド

継続モナドはSwiftで段階的に作れる。

1. まず継続渡しの関数を作る。

func getA(complete:(String)->Void) {
    complete("X")
}

2. 継続渡しの関数を引数にとるクラスを作る。

typealias Func<T> = (T)->Void

public struct RDFuture<T> {
    
    public var f:(Func<T>)->()
    
    public func result(_ complete:(T) -> Void) -> Void {
        f(complete)
    }
    
    init(_ f:@escaping (Func<T>)->()) {
        self.f = f
    }
}

これで骨組みはできた。

このように使う

func test() {
    let f = RDFuture(getA)
    
    f.result {
        print($0)
    }
}

これに、bind的な実装をつけることになる。

Realm

Realmを試してみた。便利だ。。

import Foundation
import RealmSwift

class Man : Object { // ObjectはRealmのクラス
    dynamic var name = "" // dynamicはobjective-Cのランタイムを利用して値にアクセスする
    dynamic var age = 10
    let cats = List<Cat>()  // ListはRealmのクラス
    
}

class Cat : Object {
    dynamic var name = ""
    let owners = LinkingObjects(fromType: Man.self, property: "cats")
}

class Test {
    func test() {
        let man = Man()
        man.name = "ho"
        man.age = 5
        
        
        let cat = Cat()
        cat.name = "mi"
        
        
        let realm = try! Realm()
        
        try! realm.write {
            realm.deleteAll()
            realm.add(man)
            realm.add(cat)
            let man = realm.objects(Man.self).filter("name == 'ho'").first!
            man.cats.append(cat)


        }
        

        
        let babies = realm.objects(Man.self).filter("age < 2")
        print("\(babies.count)")
        
        DispatchQueue(label: "background").async {
            autoreleasepool {
                let realm = try! Realm()
                let men = realm.objects(Man.self)
                let man = realm.objects(Man.self).filter("age == 5").first!
                try! realm.write {
                    man.age = 10
                }
                let cat = realm.objects(Cat.self).filter("name == 'mi'").first!
                
                print("\(man.cats.first?.name)")
                print("\(cat.owners.count)")

                let babies = realm.objects(Man.self).filter("age == 10")
                print("\(babies.count)")
                

            }
        }
    }
}

proxy

export USERNAME=
export PASSWORD=
export HOST=
export PORT=
export PROXY=$USERNAME:$PASSWORD@$HOST:$PORT
export http_proxy=http://$PROXY
export https_proxy=https://$PROXY
export ftp_proxy=ftp://$PROXY
export HTTP_PROXY=http://$PROXY
export HTTPS_PROXY=https://$PROXY
export FTP_PROXY=ftp://$PROXY
export no_proxy=
export NO_PROXY=$no_proxy

以下を参照した。
プロキシ下でLinuxを使う際のメモ - Λlisue's blog

viewWillLayoutSubviews

viewWillLayoutSubviewsはviewのlayoutSubviewsの前に呼ばれる。
ちなみにlayoutSubviewsはレイアウト更新タイミング、制約つけたいときはupdateConstraints。

viewWillLayoutSubviewsは結果的にViewWillAppearとViewWillDidAppearの中間で呼ばれることになる。