ios - 在 andom 索引处插入字符串无法快速工作

标签 ios arrays swift numbers generator

我正在研究一个随 secret 码生成器,我想要一个用户可以输入的基本字符串,并在基本字符串内部或周围生成随机字符。我的问题是,每当它使用基本字符串生成随机字符时,它们就会被插入到前面(第 0 个索引)。这是我的代码:

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var baseStringTextField: UITextField!
    @IBOutlet weak var lowerCaseSwitch: UISwitch!
    @IBOutlet weak var upperCaseSwitch: UISwitch!
    @IBOutlet weak var numberSwitch: UISwitch!
    @IBOutlet weak var numberOfCharactersSlider: UISlider!
    @IBOutlet weak var numberOfCharsLabel: UILabel!

    let lower = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t","u","v","w", "x", "y", "z"]
    let upper = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"]
    let numbers = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"]

    let lowerUpper = ["a", "b", "c", "d", "e", "f", "g",
        "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t",
        "u", "v", "w", "x", "y", "z","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z",]

    let lowerNumber = ["a", "b", "c", "d", "e", "f", "g",
        "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t",
        "u", "v", "w", "x", "y", "z","1", "2", "3", "4", "5", "6", "7", "8", "9", "0"]

    let upperNumber = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","1", "2", "3", "4", "5", "6", "7", "8", "9", "0"]

    let all = ["a", "A" ,"b", "B", "c", "C", "d", "D", "e", "E" , "f", "F", "g", "G",  "h", "H", "i", "I",  "j", "J" ,"k", "K", "l", "L" ,"m", "M" , "n", "N" ,"o", "O", "p", "P",  "q", "Q", "r", "R", "s", "S", "t", "T", "u", "U", "v", "V", "w", "W", "x","X", "y", "Y" , "z", "Z", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"]

    var generatedString = [""]


    func generateLower(){
        srandom(UInt32(time(nil)))
        var baseString:[String] = Array(arrayLiteral: baseStringTextField.text)
        for var i = 0; i < Int(roundf(numberOfCharactersSlider.value)) ; ++i{
            var char = lower[Int(arc4random_uniform(26))]
            var count_ = baseString.count
            var baseStringText = baseStringTextField.text
            var randIndex:Int = Int(arc4random_uniform(UInt32(count_ + count(baseStringText.utf16))))
            baseString.insert(char, atIndex: randIndex)
        }
        generatedString = baseString
        generatedStringLabel.text = "".join(generatedString)
    }

    func generateUpper(){
        srandom(UInt32(time(nil)))
        var baseString:[String] = Array(arrayLiteral: baseStringTextField.text)
        for var i = 0; i < Int(roundf(numberOfCharactersSlider.value)) ; ++i{
            var char = upper[Int(arc4random_uniform(26))]
            var count_ = baseString.count
            var baseStringText = baseStringTextField.text
            var randIndex:Int = Int(arc4random_uniform(UInt32(count_ + count(baseStringText.utf16))))
            baseString.insert(char, atIndex: randIndex)
        }
        generatedString = baseString
        generatedStringLabel.text = "".join(generatedString)
    }

    func generateNumber(){
        srandom(UInt32(time(nil)))
        var baseString:[String] = Array(arrayLiteral: baseStringTextField.text)
        for var i = 0; i < Int(roundf(numberOfCharactersSlider.value)) ; ++i{
            var char = numbers[Int(arc4random_uniform(10))]
            var count_ = baseString.count
            var baseStringText = baseStringTextField.text
            var randIndex:Int = Int(arc4random_uniform(UInt32(count_ + count(baseStringText.utf16))))
            baseString.insert(char, atIndex: randIndex)
        }
        generatedString = baseString
        generatedStringLabel.text = "".join(generatedString)
    }

    func generateLowerAndUpper(){
        srandom(UInt32(time(nil)))
        var baseString:[String] = Array(arrayLiteral: baseStringTextField.text)
        for var i = 0; i < Int(roundf(numberOfCharactersSlider.value)) ; ++i{
            var count_ = baseString.count
            var baseStringText = baseStringTextField.text
            var randIndex:Int = Int(arc4random_uniform(UInt32(count_ + count(baseStringText.utf16))))
                var char = lowerUpper[Int(arc4random_uniform(52))]
                baseString.insert(char, atIndex: randIndex)
        }
        generatedString = baseString
        generatedStringLabel.text = "".join(generatedString)
    }

    func generateLowerAndNumber(){
        var baseString:[String] = Array(arrayLiteral: baseStringTextField.text)
        srandom(UInt32(time(nil)))
        for var i = 0; i < Int(roundf(numberOfCharactersSlider.value)) ; ++i{
            var count_ = baseString.count
            var baseStringText = baseStringTextField.text
            var randIndex:Int = Int(arc4random_uniform(UInt32(count_ + count(baseStringText.utf16))))
                var char = lowerNumber[Int(arc4random_uniform(36))]
                baseString.insert(char, atIndex: randIndex)
        }
        generatedString = baseString
        generatedStringLabel.text = "".join(generatedString)
    }

    func generateUpperAndNumber(){
        srandom(UInt32(time(nil)))
        var baseString:[String] = Array(arrayLiteral: baseStringTextField.text)
        for var i = 0; i < Int(roundf(numberOfCharactersSlider.value)) ; ++i{
            var count_ = baseString.count
            var baseStringText = baseStringTextField.text
            var randIndex:Int = Int(arc4random_uniform(UInt32(count_ + count(baseStringText.utf16))))
                var char = upperNumber[Int(arc4random_uniform(36))]
                baseString.insert(char, atIndex: randIndex)
        }
        generatedString = baseString
        generatedStringLabel.text = "".join(generatedString)
    }

    func generateAll(){
        srandom(UInt32(time(nil)))
        var baseString:[String] = Array(arrayLiteral: baseStringTextField.text)
        for var i = 0; i < Int(roundf(numberOfCharactersSlider.value)) ; ++i{
            var count_ = baseString.count
            println(count_)
            var randIndex:Int = Int(arc4random_uniform(UInt32(count_)))
            var char = all[Int(arc4random_uniform(62))]
            baseString.insert(char, atIndex: randIndex)
        }
        generatedString = baseString
        generatedStringLabel.text = "".join(generatedString)
    }

    @IBAction func generateString(sender: UIButton) {
        if(lowerCaseSwitch.on && upperCaseSwitch.on && numberSwitch.on){
            generateAll()
        }else if(lowerCaseSwitch.on && upperCaseSwitch.on == false && numberSwitch.on == false){
            generateLower()
        }else if(upperCaseSwitch.on && lowerCaseSwitch.on == false && numberSwitch.on == false){
            generateUpper()
        }else if(numberSwitch.on && lowerCaseSwitch.on == false  && upperCaseSwitch.on == false){
            generateNumber()
        }else if(lowerCaseSwitch.on && upperCaseSwitch.on && numberSwitch.on == false){
            generateLowerAndUpper()
        }else if(lowerCaseSwitch.on && numberSwitch.on && upperCaseSwitch.on == false){
            generateLowerAndNumber()
        }else if(upperCaseSwitch.on && numberSwitch.on && lowerCaseSwitch.on == false){
            generateUpperAndNumber()
        }
    }

    @IBAction func copyButtonPressed(sender: UIButton) {
        UIPasteboard.generalPasteboard().string = "".join(generatedString)
}
    override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
        view.endEditing(true)
        super.touchesBegan(touches, withEvent: event)
    }
}

如有任何帮助,我们将不胜感激。谢谢!

最佳答案

您的代码将非常难以调试,因为它混合了许多不同的东西——从数组中获取随机元素、从随机元素构建字符串、更新 UI、从 UI 获取设置以控制代码。

如果您养成将需要做的事情分解为多个构建 block 的习惯,您会发现在第一次尝试时编写正确的代码并让自己摆脱调试 hell 要容易得多。

要构建哪些构建 block 只能通过实践来实现,但是如果您发现自己一遍又一遍地重复相同的相同代码但有细微的变化,这就是您遇到问题的一个好迹象,就像您在各种generateXXX 函数 – 这些是以有用的方式分解代码的示例。

例如,您需要一个函数来生成给定长度的密码,可以选择包含各种字符。为此,您需要一个从数组(或任何集合)中获取随机字符的函数。为此,您需要一个将系统生成的随机数转换为集合索引的函数。这些可能会成为很好的构建基 block 。

因此,转换 arc4random_uniform 的函数(顺便说一句,无需调用 srandarc4random 种子本身):

(以下所有代码都是 Swift 2.0 代码,但除非您计划在不到 3 个月内将某些东西投入生产,特别是如果您正在学习 Swift,我强烈建议您升级,因为它是 比 1.2 更容易使用,并且您最终将不得不升级,离开它的时间越长会很痛苦)

/// Version of arc4random that works for any integer type. Kinda ugly unfortunately.
func arc4random_uniform<In: _SignedIntegerType, Out: _SignedIntegerType>(upto: In) -> Out 
{
    precondition(upto < numericCast(UInt32.max),"Range too big for arc4random")
    return numericCast(Darwin.arc4random_uniform(numericCast(upto.toIntMax())))
}

然后是一个从集合中获取随机元素的函数。这通常适用于任何集合类型,但您可以只为数组编写它,因为如果这就是您所需要的,那么这样做会更容易:

/// Fetch a random element from any collection that supports random access
extension CollectionType where Index: RandomAccessIndexType {
    var randomElement: Generator.Element {
        guard !isEmpty else { fatalError("Collection cannot be empty") }
        return self[startIndex.advancedBy(arc4random_uniform(count))]
    }
}

然后,为您可能想要包含的不同类型的字符设置一个选项:

/// A set of options for controlling which characters to include in a password
struct CharacterOptions: OptionSetType {
    let rawValue: Int
    init(rawValue: Int) { self.rawValue = rawValue }

    static let LowerCase = CharacterOptions(rawValue: 1)
    static let UpperCase = CharacterOptions(rawValue: 2)
    static let Numbers = CharacterOptions(rawValue: 4)

    /// An array of the full set of characters based on the options set
    var characters: [Character] {
        let lower = Array("abcdefghijklmnop".characters)
        let upper = Array("ABCDEFGHIKKLMNOP".characters)
        let numbers = Array("1234567890".characters)

        // this could be done so much more efficiently if only
        // LazyRandomAccessCollection supported flatMap
        return (self.contains(.LowerCase) ? lower   : [])
             + (self.contains(.UpperCase) ? upper   : [])
             + (self.contains(.Numbers)   ? numbers : [])
    }
}

最后将它们组合成一个生成密码的函数:

func generatePassword(length: Int, options: CharacterOptions) -> String {
    let sources: [Character] = options.characters

    let characters = (0..<length).map { _ in
        sources.randomElement
    }

    return String(characters)
}

generatePassword(10, options: [.LowerCase, .UpperCase])

然后,当你构建了这个随 secret 码生成函数后,你应该从你的 View Controller 中调用它。但您不必这样做——您可以单独调用它,这样可以更轻松地测试和检查它是否正常工作以及调试。单机功能也可以独立测试。

关于ios - 在 andom 索引处插入字符串无法快速工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31222116/

相关文章:

javascript - .get() 在 jQuery API 中没有索引的原因?

ios - 如何使用 FBSDKCoreKit 向 Facebook 用户发布图片

ios - 核心数据 : "Cannot delete object that was never inserted."

iphone - 开发证书推送通知

ios - 如何在 iOS 中的 FlipBoard Animation 等 View 之间翻转?

javascript - 如何在 JavaScript 中连接字符串数组 - 连接时进行修改

ios - 我可以从左到右有两个 ECSlidingViewController Drawer 吗?

我的数组中的 javascript 无限循环错误

swift - 如何在swift中获取特定字符前后的特定字符串?

swift - 线程 1 : EXC_BREAKPOINT (code=1, 子代码 = 0x10136bb50) - swift