woshidan's loose leaf

ぼんやり勉強しています

BitBucketにgitでアクセス、あるいは新しいサイトでssh認証するときの鍵の登録と確認の手順

https://qiita.com/yyosuke/items/986dabc9906674e2ea97 を参考にSSHの公開鍵をBitBucketに登録。

~/.ssh/configbitbucket.org に当該の秘密鍵を使ってアクセスするように設定する。

# サイトごとに鍵を分けた方が良い。。。
Host bitbucket.org
  HostName bitbucket.org
  IdentityFile ~/.ssh/bitbucket/id_rsa
  User git
  Port 22
  TCPKeepAlive yes
  IdentitiesOnly yes
$ ssh -T bitbucket.org
The authenticity of host 'bitbucket.org (104.192.143.2)' can't be established.
RSA key fingerprint is SHA256:UvlgyNccfRyg8jrD8dzU2lwwd4dDWYbx4NfILUjQkKL(この値はダミー).
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'bitbucket.org,104.192.143.2' (RSA) to the list of known hosts.
logged in as UserName.

You can use git or hg to connect to Bitbucket. Shell access is disabled.

あとはほぼGitHubと同じで、remote リポジトリを指定するときのホストが bitbucket.org になっているだけ。

`NS_SWIFT_NAME` マクロでObjective-CのコードがSwiftからどう見えるか規定できる

Objective-Cで書いたメソッドのシグネチャはSwiftから呼び出す時にメソッド名の一部の単語がパラメータ名の一部へ変換されるものがある。

// Objective-C
- (void)addToBox:(Item *)item;
// Swift 2.3
addToBox(item)

// Swift 3.0
add(toBox: item)

この変換具合がSwift2系と3系で結構違う上に前置詞などを使った動詞の塊が切り取られて引数のラベルみたいに扱われてしまう。

すると、主に一番最初の引数の意味が違って見えることがある。たとえば、 上記の例の Swfit 3.0 のシグネチャでは toBox というラベルがついてしまっているが、第一引数はItemのインスタンスであってBoxのインスタンスではないが、そういう風に見える。

なので、Objective-C + 複数のSwiftのバージョンに対応する必要がある場合はドキュメントなどのサンプルコードをどう書くか悩ましかったりする。

こういう場合、 NS_SWIFT_NAME を使って Swift ではこういうシグネチャで表示してほしい、という個別設定が可能。

- (void)addToBox:(Item *)item;
NS_SWIFT_NAME(addToBox(item:));

参考

qiita.com

Swift3でCountdownLatchを作る、あるいはSemaphoreのtimeoutをSwift3で書く

テストの都合でラッチが欲しかったので、GCDのSemaphoreのラッパークラスを書こうと思ったんですね。

それで、 https://github.com/zhuhaow/CountdownLatch を参考にすれば割と簡単では! と思ったんですが、GCDの記法がSwift3で変わりすぎていて死ぬかと思った。のでメモ。

// 参考元: https://github.com/zhuhaow/CountdownLatch
import Foundation

class CountDownLatch {
    var count: Int
    private let dispatchQueue = DispatchQueue(label: "CountdownQueue")
    // 参考: https://qiita.com/codelynx/items/56ce2f91cd3f4f409aeb
    let semaphore = DispatchSemaphore(value: 0)
    let timeInSec : Int
    
    init?(count: Int, timeInSec: Int) {
        guard count > 0 else {
            return nil
        }
        
        self.count = count
        self.timeInSec = timeInSec
    }
    
    func countdown() {
        dispatchQueue.async {
            self.count -= 1
            if self.count == 0 {
                self.semaphore.signal()
            }
        }
    }
    
    func await() -> Bool {
        // 参考: http://www.brilliantraven.com/code-snippets/grand-central-dispatch.html
        let result = semaphore.wait(timeout: DispatchTime.now() + DispatchTimeInterval.seconds(self.timeInSec))
        if (result == .success) {
            return true
        } else {
            return false
        }
    }
}

CouuntDownLatch を使う側のコードは以下

    func doTask() {
        let countDownLatch = CountDownLatch(count: 1, timeInSec: 30)!
        checkTimeoutBeforeCompletion(latch: countDownLatch)

        // なんか重い処理する

        countDownLatch.countdown()
    }

    func checkTimeoutBeforeCompletion(latch: CountDownLatch) {
        let queue = DispatchQueue(label: "background", attributes: .concurrent)
        queue.async {
            let processedOnTime = latch.await()
            if (processedOnTime) {
                NSLog("processed on time")
            } else {
                assertionFailure("遅いぞ!!!!")
            }
        }
    }

計数型セマフォについて

http://woshidan.hatenadiary.jp/entry/2017/08/27/005353 で使い方の勉強をした気がするんですが意味がよくわかってなかったので。

計数型セマフォは「チケットを配ってチケットをもらえたスレッドは処理を先へ進めることができる」みたいなもの。 ここから下はチケットを配ってもらえたスレッドにしか実行させない、みたいな箇所で

semaphore.await();
dispatch_semaphore_wait(semaphore, time);

のように、wait っぽい関数を置く。 (少なくともObjCの場合は) wait 関数から抜ける時にセマフォのカウンタ(比喩でいうとチケットの枚数)がデクリメントする。

初期化時にセマフォが何枚のチケットを持っているか指定して、チケットを配られたスレッドたちが実行する処理の中でチケットを返したり(Semaphoreのカウンタをインクリメントする)する。

ObjCの場合、Semaphoreのカウンタをインクリメントする処理は以下。

dispatch_semaphore_signal(semaphore)

なので、全体の処理としてはこんな感じになる。

// セマフォの用意
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);

// セマフォのところで待つ時間
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 1ull * NSEC_PER_SEC);

// ここからセマフォで用意したチケットの枚数ぶん以上のスレッドは実行してくれるなよ
long result = dispatch_semaphore_wait(semaphore, time);
// 上の行を通り過ぎるとセマフォのカウンタは1減っている

if (result == 0) {
    // セマフォのカウンタが1以上だった or 待機時間中にセマフォのカウンタが1以上になったので
    // 処理が進められる

    // 排他制御したかった処理

    // この処理の最後あたりでセマフォのカウンタを戻しておきましょう
    dispatch_semaphore_signal(semaphore)
} else {
    // 指定時間待機したけどセマフォのカウンタが0のままだった
}

現場からは以上です。

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

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

iOSのUIをコードで追加して配置する

5回ググって書く気が失せたのでBlogged.

// https://qiita.com/i_terasaka/items/2cf7d0f7146f32c3f2c1#%E5%8F%96%E5%BE%97%E6%96%B9%E6%B3%95
let button = UIButton(type: UIButtonType.system)
button.frame = CGRect(x: 180, y: 50, width: 100, height: 40)
button.setTitle("button", for: UIControlState.normal)
button.accessibilityIdentifier = "button" // XCUITest用
button.addTarget(self, action: #selector(ViewController.someAction), for: UIControlEvents.touchUpInside)

self.view.addSubview(button)

// https://qiita.com/on0z/items/9768d2bccc29cc4e1851
var wkWebView : WKWebView!
wkWebView = WKWebView(frame: CGRect(x: 100, y: 100, width: self.view.frame.size.width / 2, height: self.view.frame.size.height / 2))
self.view.addSubview(wkWebView)

// 初期化メソッドに差はない
var uiwebview : UIWebView!
uiwebview = UIWebView(frame: CGRect(x: 100, y: 120 + self.view.frame.size.height / 4 , width: self.view.frame.size.width / 2, height: self.view.frame.size.height / 4))
        self.view.addSubview(uiwebview)

参考

合わせて読みたい

StoryBoardを使わないでプロジェクト作成(Xcode8,Swift3) - Qiita

iOSでBundleファイルを扱う

  1. .bundle 拡張子のついたフォルダーを用意
  2. その下にファイルを置く
  3. .bundle 拡張子のついたファイルをXCode上で追加したいプロジェクトに追加
  4. 下記のように NSStringNSData, UIImage などの関数でデータを読み込む
NSString* filePath = [NSString stringWithFormat:@"%@/%@",  [[NSBundle mainBundle] pathForResource:@"test" ofType:@"bundle"], FILE_NAME];
NSString* content = [NSString stringWithContentsOfFile:filename encoding:NSUTF8StringEncoding error:nil];
NSLog(@"content: %@", content);

NSData *contentData = [NSData dataWithContentsOfFile:filePath
                                              options:NSDataReadingMappedIfSafe
                                                error:nil];

[UIImage imageNamed:filePath];

参考