2016/07/06

Swiftでランダム英数字の文字列生成(※arc4random()は使ってはいけない)

SwiftでセッションIDなどのランダム英数字を生成させたい時

ポイント

arc4random()ではなく、arc4random_uniform(UInt32)を使用するのがポイント

arc4random()を使うとクラッシュする

arc4random()は乱数を生成させる関数ですが、Intにキャストする際に32bit端末ではクラッシュします。iPhone5や4Sなど、初代iPad Air以前は32bit
arc4randomはunsigned 32 bit integerを返しますが、つまり0から4,294,967,295まで。
IntはiPhone5で32ビットの整数と5S上の64ビット整数です。arc4random()はiPhone5上のIntの倍の正の範囲を持っているUInt32型を返すので、クラッシュする可能性が50%あります。
また詳細は記述しませんが、ランダム性に少しバイアスがあるarc4random()のずれを補正し、int型に変換しても安全なのがarc4random_uniform()です。

実装

引数の数だけ、a-zの小文字大文字、0-9を組み合わせた文字列を生成します。
arc4random_uniformを使用
    func generate(length: Int) -> String {
        let base = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
        var randomString: String = ""

        for _ in 0..<length {
            let randomValue = arc4random_uniform(UInt32(base.characters.count))
            randomString += "\(base[base.startIndex.advancedBy(Int(randomValue))])"
        }
        return randomString
    }

参照

Objective-Cの乱数作成はarc4random_uniform
http://tanukichi566.blog.fc2.com/blog-entry-57.html
[Swift][iOS]64bit対応におけるarc4random()について
http://qiita.com/kiguchi/items/c75d6d3da05b3e8d80d9

2016/07/03

Swiftで半角英字のValidation(英字ニックネームなど)

半角アルファベットのみで入力させたい場合のバリデーション
extension String {

    var isAllHalfWidthCharacter: Bool {
        // 半角も全角も1文字でカウント
        let nsStringlen = self.characters.count
        let utf8 = (self as NSString).UTF8String
        // Cのstrlenは全角を2で判定する
        let cStringlen = Int(bitPattern: strlen(utf8))
        if nsStringlen == cStringlen {
            return true
        }

        return false
    }

    var isValidNickName: Bool {
        if rangeOfCharacterFromSet(.letterCharacterSet(), options: .LiteralSearch, range: nil) == nil { return false }
        if rangeOfCharacterFromSet(.decimalDigitCharacterSet(), options: .LiteralSearch, range: nil) != nil { return false }
        guard self.isAllHalfWidthCharacter else { return false }
        return true
    }
}

実用例

isValidNickNameでチェック
   if nickname.isValidNickName {
      // Set Data
   } else {
      // Alert
      let alertController = UIAlertController(
                title: "半角英字のみで入力してください",
                message: "",
                preferredStyle: .Alert)
            let otherAction = UIAlertAction(title: "OK", style: .Default) {
                action in
                self.navigationController?.popToViewController(self.navigationController!.viewControllers[0], animated: true)
            }

            alertController.addAction(otherAction)
            presentViewController(alertController, animated: true, completion: nil)
   }


NSStringではlengthでカウントできるのに、
String型ではcharacters.countって長い