woshidan's loose leaf

ぼんやり勉強しています

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];

参考

今日のAWS

terraform ちょっとだけ触りました

qiita.com

qiita.com

resource "aws_s3_bucket", "woshidan-terrafom-test" { # 追加する種類のリソース, リソース名
    # s3の場合
    bucket = "woshidan-terrafom-test"
    path   = "/"
    acl = "private"
    # acl = "..." で設定しているのはAWS側によってあらかじめ定義された既定ACL
    # privateはデフォルト設定。所有者はすべての権限を持つが他のユーザにアクセス許可はない
    # http://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/acl-overview.html#canned-acl
    # 既定ACLに付け加えて記載するポリシー. JSON形式で書く
    policy = << POLICY
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "aws-portal:View*",
            "Resource": "*"
        }
    ]
}
POLICY
}

AWS S3のACL

http://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/acl-overview.html

AWS S3 アクセスコントロールリスト(ACL)では、バケットとオブジェクトへのアクセスを管理ができる。各バケットとオブジェクトにはサブリソースとしてACLが付与されていて、ACLには

  • 所有者
  • 被付与者(AWSアカウントまたはグループ)
  • 付与されたアクセス許可

の要素がある。

PolicyとPolicy Attachment

Policyのリソース( aws_iam_policy )は別個に定義することができて、下記のようにさらにAttachmentリソースの定義でユーザーやグループと結びつけることで、管理画面でやるようにユーザーが所属するグループの食い合わせによってそのユーザーが持っている権限が定義される、というような管理の仕方ができそう。

resource "aws_iam_policy" "WoshidanTerraformTestFullAccess" {
    name   = "WoshidanTerraformTestFullAccess"
    path   = "/"
    description = "terraform hello world"
    policy = <<POLICY
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "s3:List*",
      "Resource": "arn:aws:s3:::*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject*",
        "s3:DeleteObject*",
        "s3:PutObject*"
      ],
      "Resource": [
        "arn:aws:s3:::woshidan-terrafom-test/*"
      ]
    }
  ]
}
POLICY
}
resource "aws_iam_policy_attachment" "WoshidanTerraformTestFullAccess" {
  name = "WoshidanTerraformTestFullAccess"
  users = [...]
  roles = []
  policy_arn = "${aws_iam_policy.WoshidanTerraformTestFullAccess.arn}"
}

Cocos2d-x用の日本語対応フォントファイルをGlyph Designer2を使って書き出し

Glyph Designer 2 の入手

Glyph Designer - A Bitmap Font Generator for Mac · 71Squared

よりDLした後、ライセンス(月900円~)を購入してアクティベイトキーを入力。

日本語フォントの追加

【cocos2d/unity3d】簡単に日本語表示用のフォントが作れる「GlyphDesigner」の使い方 | albatrus.comを参考にしつつ、 Font Systems のアプリケーションから利用したいフォントのフォルダを開いて、フォントファイル (.otf)を Glyph Designer 2 から開くことができるパスへコピーします。

f:id:woshidan:20171023013506p:plain

f:id:woshidan:20171023013514p:plain

なお、今回利用させていただいたフォントはこちらのりぃ手書きNです。

f:id:woshidan:20171023013527p:plain

そのフォントを Glyph Designer 2 のメニューの File > Load Font で開きます。

すると以下のように利用可能なフォントとして追加されます。

f:id:woshidan:20171023013622p:plain

設定ファイル上で日本語を利用できるようにする

このままでは設定ファイルは以下の文字しか対応していません。ゲーム上で利用した場合、日本語は利用できなくなっています。

それでは困るので、フォントの設定にひらがなとカタカナを利用可能な文字として追加することにします。

f:id:woshidan:20171023013655p:plain

f:id:woshidan:20171023013809p:plain

f:id:woshidan:20171023013825p:plain

真ん中の目のアイコンを押すとプレビュー画面が開き、実際にフォントを利用した場合の様子を試すことができます。

f:id:woshidan:20171023013905p:plain

設定ファイルのexport

f:id:woshidan:20171023013925p:plain