我意识到Swift书籍提供了一个随机数生成器的实现。复制和粘贴这个实现是最佳实践吗?或者有没有这样的库,我们现在就可以使用?
当前回答
在Swift 4.2中,您可以通过调用random()方法在任何您想要的数字类型上生成随机数,提供您想要使用的范围。例如,这会生成一个范围为1到9的随机数,两边都包括在内
let randInt = Int.random(in: 1..<10)
其他类型也一样
let randFloat = Float.random(in: 1..<20)
let randDouble = Double.random(in: 1...30)
let randCGFloat = CGFloat.random(in: 1...40)
其他回答
编辑:为Swift 3.0更新
arc4random在Swift中工作得很好,但基本函数仅限于32位整数类型(Int在iPhone 5S和现代mac上是64位)。下面是一个泛型函数,用于表示可以用整型字面值表示的类型的随机数:
public func arc4random<T: ExpressibleByIntegerLiteral>(_ type: T.Type) -> T {
var r: T = 0
arc4random_buf(&r, MemoryLayout<T>.size)
return r
}
我们可以使用这个新的泛型函数扩展UInt64,增加边界参数并减少模偏置。(这是从arc4random.c直接引用的)
public extension UInt64 {
public static func random(lower: UInt64 = min, upper: UInt64 = max) -> UInt64 {
var m: UInt64
let u = upper - lower
var r = arc4random(UInt64.self)
if u > UInt64(Int64.max) {
m = 1 + ~u
} else {
m = ((max - (u * 2)) + 1) % u
}
while r < m {
r = arc4random(UInt64.self)
}
return (r % u) + lower
}
}
这样我们就可以将Int64扩展为相同的参数,处理溢出:
public extension Int64 {
public static func random(lower: Int64 = min, upper: Int64 = max) -> Int64 {
let (s, overflow) = Int64.subtractWithOverflow(upper, lower)
let u = overflow ? UInt64.max - UInt64(~s) : UInt64(s)
let r = UInt64.random(upper: u)
if r > UInt64(Int64.max) {
return Int64(r - (UInt64(~lower) + 1))
} else {
return Int64(r) + lower
}
}
}
为了让家庭更完整……
private let _wordSize = __WORDSIZE
public extension UInt32 {
public static func random(lower: UInt32 = min, upper: UInt32 = max) -> UInt32 {
return arc4random_uniform(upper - lower) + lower
}
}
public extension Int32 {
public static func random(lower: Int32 = min, upper: Int32 = max) -> Int32 {
let r = arc4random_uniform(UInt32(Int64(upper) - Int64(lower)))
return Int32(Int64(r) + Int64(lower))
}
}
public extension UInt {
public static func random(lower: UInt = min, upper: UInt = max) -> UInt {
switch (_wordSize) {
case 32: return UInt(UInt32.random(UInt32(lower), upper: UInt32(upper)))
case 64: return UInt(UInt64.random(UInt64(lower), upper: UInt64(upper)))
default: return lower
}
}
}
public extension Int {
public static func random(lower: Int = min, upper: Int = max) -> Int {
switch (_wordSize) {
case 32: return Int(Int32.random(Int32(lower), upper: Int32(upper)))
case 64: return Int(Int64.random(Int64(lower), upper: Int64(upper)))
default: return lower
}
}
}
在所有这些之后,我们终于可以做这样的事情:
let diceRoll = UInt64.random(lower: 1, upper: 7)
下面的代码将产生一个0到255之间的安全随机数:
extension UInt8 {
public static var random: UInt8 {
var number: UInt8 = 0
_ = SecRandomCopyBytes(kSecRandomDefault, 1, &number)
return number
}
}
你这样称呼它:
print(UInt8.random)
对于更大的数字,它会变得更复杂。 这是我能想到的最好的:
extension UInt16 {
public static var random: UInt16 {
let count = Int(UInt8.random % 2) + 1
var numbers = [UInt8](repeating: 0, count: 2)
_ = SecRandomCopyBytes(kSecRandomDefault, count, &numbers)
return numbers.reversed().reduce(0) { $0 << 8 + UInt16($1) }
}
}
extension UInt32 {
public static var random: UInt32 {
let count = Int(UInt8.random % 4) + 1
var numbers = [UInt8](repeating: 0, count: 4)
_ = SecRandomCopyBytes(kSecRandomDefault, count, &numbers)
return numbers.reversed().reduce(0) { $0 << 8 + UInt32($1) }
}
}
这些方法使用一个额外的随机数来确定有多少uint8将被用于创建随机数。最后一行将[UInt8]转换为UInt16或UInt32。
我不知道后两个是否还算真正的随机,但你可以根据自己的喜好进行调整:)
在某些版本的Xcode中没有arc4Random_uniform()(在7.1中运行,但对我来说不自动完成)。你可以这样做。
从0-5中生成一个随机数。 第一个
import GameplayKit
Then
let diceRoll = GKRandomSource.sharedRandom().nextIntWithUpperBound(6)
我想补充现有的答案,在Swift书中的随机数生成器的例子是一个线性同余生成器(LCG),这是一个非常有限的一个,不应该除了必须平凡的例子,其中随机性的质量根本不重要。LCG永远不应该用于加密目的。
Arc4random()要好得多,可以用于大多数目的,但不应该用于加密目的。
如果您想要保证加密安全的内容,请使用SecCopyRandomBytes()。请注意,如果您将随机数生成器构建到某个东西中,其他人可能最终(错误地)将其用于加密目的(例如密码、密钥或盐生成),那么无论如何您都应该考虑使用SecCopyRandomBytes(),即使您的需要并不完全需要这样做。
细节
xCode 9.1, Swift 4
面向数学的解(1)
import Foundation
class Random {
subscript<T>(_ min: T, _ max: T) -> T where T : BinaryInteger {
get {
return rand(min-1, max+1)
}
}
}
let rand = Random()
func rand<T>(_ min: T, _ max: T) -> T where T : BinaryInteger {
let _min = min + 1
let difference = max - _min
return T(arc4random_uniform(UInt32(difference))) + _min
}
溶液使用方法(1)
let x = rand(-5, 5) // x = [-4, -3, -2, -1, 0, 1, 2, 3, 4]
let x = rand[0, 10] // x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
面向程序员的解决方案(2)
不要忘记在这里添加面向数学的解决方案(1)代码
import Foundation
extension CountableRange where Bound : BinaryInteger {
var random: Bound {
return rand(lowerBound-1, upperBound)
}
}
extension CountableClosedRange where Bound : BinaryInteger {
var random: Bound {
return rand[lowerBound, upperBound]
}
}
溶液使用方法(2)
let x = (-8..<2).random // x = [-8, -7, -6, -5, -4, -3, -2, -1, 0, 1]
let x = (0..<10).random // x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
let x = (-10 ... -2).random // x = [-10, -9, -8, -7, -6, -5, -4, -3, -2]
完整的样品
不要忘记在这里添加溶液(1)和溶液(2)的代码
private func generateRandNums(closure:()->(Int)) {
var allNums = Set<Int>()
for _ in 0..<100 {
allNums.insert(closure())
}
print(allNums.sorted{ $0 < $1 })
}
generateRandNums {
(-8..<2).random
}
generateRandNums {
(0..<10).random
}
generateRandNums {
(-10 ... -2).random
}
generateRandNums {
rand(-5, 5)
}
generateRandNums {
rand[0, 10]
}
样品结果
推荐文章
- 我如何使一个enum可解码在Swift?
- HTTP请求在Swift与POST方法
- 获取用户当前位置/坐标
- 如何正确的种子随机数生成器
- 在SwiftUI中创建一个VStack填充屏幕宽度
- 移动文本字段时,键盘出现迅速
- 如何在swift中逆向循环迭代?
- Xcode 8 / Swift 3: "Expression of type UIViewController?未使用”警告
- 我如何使成员初始化公共,默认情况下,在Swift的结构?
- 如何停止不必要的UIButton动画标题变化?
- 如何使用Swift播放声音?
- 如何解散ViewController在Swift?
- 保存字符串到NSUserDefaults?
- JS生成随机布尔值
- 如何将JSON字符串转换为字典?