【Swift】パスワード生成アプリを作ってみた

完成図

 

 

解説

 

・tableViewのセルにパスワードを代入し、表示する

(セルの上にUILabelを設置する方法も考えたが、タップするとクリップボードにコピーされる処理を施せなかったので断念。)

 

・パスワード生成はパスワード生成画面で行われる

 

・パスワードを生成するには、

  1. 個数(ONの数:1)
  2. 文字数(1)
  3. 形態(1〜3)

を全て設定しなければならない。

 

・もし上記の条件を満たさないで"パスワード生成ボタン"を押すと、生成されず、何も起こらない

 

・パスワードが表示されたセルをタップすると、クリップボードにコピーされる

 

・UISwitchのON/OFFをコントロールするには、Actionに加えて、Outletで接続する必要がある

 

・今回の乱数の生成方法は、

  1. 用意した文字列の中からランダムに文字を選出
  2. 選出した文字を変数に”追加”する
  3. 設定した文字数になるまで上記をループ
  4. 設定した個数まで上記をループ

 

・同じ文字を含めない場合の生成方法は、

  1. 用意した文字列の中からランダムに文字を選出
  2. 選出した文字を変数に”代入”する
  3. 変数を配列1に格納する
  4. 配列1を重複チェック(重複している文字の数は1つになる)
  5. 配列1の要素数が設定した文字数になるまで上記をループ
  6. 配列1の全ての要素を連結し、セルに表示するための配列に格納

(ランダムに選出した文字を配列に入れ続け、重複チェックし、設定した文字数に達したら、配列内の要素(文字)を連結し、パスワード(文字列)に変換する)

 

・乱数を生成する方法を探すのが、1番苦労した

 

ストーリーボード

 

f:id:nekokichi_yos2:20181020124726p:plain

 

ソースコード

 

GitHub

github.com

 

「パスワード表示画面」

 

import UIKit

class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource{
    
    @IBOutlet weak var tableView: UITableView!
    
    //RNArrayの値を取得する配列
    var passwordArray = [String]()
    
    //UserDefaults
    let UD = UserDefaults.standard
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        //アプリ起動時にtableViewに表示されているパスワードを全て削除
        UD.removeObject(forKey: "passwordArray")
        
        //delegate宣言
        tableView.delegate = self
        tableView.dataSource = self
        
    }
    
    override func viewWillAppear(_ animated: Bool) {
        
        //UDから配列を取得
        //arrayはアンラップの為の変数
        if let array:[String] = UD.object(forKey: "passwordArray") as? [String] {
            passwordArray = UD.object(forKey: "passwordArray") as! [String]
        }
        
        //リロード
        tableView.reloadData()
        
    }
    
    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return passwordArray.count
    }
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 84
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        
        //当初はセルの上にLabelを置いていたが、コピーできなかった
        //セルのテキストにパスワードを表示
        cell.textLabel?.text = passwordArray[indexPath.row]
        
        //テキストを中央寄せにする
        cell.textLabel?.textAlignment = .center
        
        return cell
        
    }
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        
        //セルを呼び出す?
        let cell = tableView.cellForRow(at: indexPath)
        
        //タップするとクリップボードに保存する
        UIPasteboard.general.string = cell?.textLabel?.text
        
    }

}

 

 

「パスワード生成画面」


/*
※各スイッチの特徴 ・パスワードの個数:いずれかがONになると、それ以外はOFF ・パスワードの文字数:上記と同じ ・パスワードの形態:上記と同じ ・同じ文字を含めるか:ON:含める、OFF:含めない ・おまかせ:10文字の小文字大文字から成るパスワードを10個生成 ・カオス:20文字の小文字大文字記号から成るパスワードを20個生成 */ import UIKit class GenerateViewController: UIViewController { //5個 @IBOutlet weak var numberOfFive: UISwitch! //10個 @IBOutlet weak var numberOfTen: UISwitch! //15個 @IBOutlet weak var numberOfFifteen: UISwitch! //8文字 @IBOutlet weak var charEight: UISwitch! //10文字 @IBOutlet weak var charTen: UISwitch! //20文字 @IBOutlet weak var charTwenty: UISwitch! //小文字 @IBOutlet weak var charSmall: UISwitch! //大文字 @IBOutlet weak var charBig: UISwitch! //記号 @IBOutlet weak var charSymbol: UISwitch! //同じ文字を含めるか @IBOutlet weak var charSame: UISwitch! //おまかせ @IBOutlet weak var randomChar: UISwitch! //カオス @IBOutlet weak var chaosChar: UISwitch! //パスワードの数(5個,10個,15個) var numberOfPassword = 0 //文字数(8、10、20) var numberOfChar = 0 //文字の形態(0:小文字,1:大文字,2:記号) var formChar:[Int:Bool] = [0:false, 1:false, 2:false] //同じ文字を含めるか var permissionSameChar = false //乱数の材料となる文字列の長さ var len = 0 //実際に生成される文字列 var characters : String = "" //実際に格納される文字列 var randomCharacters = "" //実際に保存する文字列 var randomPassword = "" //ViewControllerに渡すための配列 var passwordArray = [String]() //UserDefaults let UD = UserDefaults.standard //戻る @IBAction func backButton(_ sender: Any) { dismiss(animated: true, completion: nil) } //5個 @IBAction func numberOfFive(_ sender: UISwitch) { //他の10個,15個のスイッチをOFFにする numberOfTen.isOn = false numberOfFifteen.isOn = false //ONなら5を、OFFなら0を代入 if sender.isOn == true { numberOfPassword = 5 } else { numberOfPassword = 0 } } //10個 @IBAction func numberOfTen(_ sender: UISwitch) { numberOfFive.isOn = false numberOfFifteen.isOn = false if sender.isOn == true { numberOfPassword = 10 } else { numberOfPassword = 0 } } //15個 @IBAction func numberOfFifteen(_ sender: UISwitch) { numberOfFive.isOn = false numberOfTen.isOn = false if sender.isOn == true { numberOfPassword = 15 } else { numberOfPassword = 0 } } //8文字 @IBAction func charEight(_ sender: UISwitch) { //10文字と20文字をOFF charTen.isOn = false charTwenty.isOn = false //ONなら8を、OFFなら0を代入 if sender.isOn == true { numberOfChar = 8 } else { numberOfChar = 0 } } //10文字 @IBAction func charTen(_ sender: UISwitch) { //8文字と20文字をOFF charEight.isOn = false charTwenty.isOn = false if sender.isOn == true { numberOfChar = 10 } else { numberOfChar = 0 } } //20文字 @IBAction func charTwenty(_ sender: UISwitch) { //8文字と10文字をOFF charEight.isOn = false charTen.isOn = false if sender.isOn == true { numberOfChar = 20 } else { numberOfChar = 0 } } //小文字 @IBAction func charSmall(_ sender: UISwitch) { //ONならtrue,OFFならfalseを代入 if sender.isOn == true { formChar[0] = true } else { formChar[0] = false } } //大文字 @IBAction func charBig(_ sender: UISwitch) { if sender.isOn == true { formChar[1] = true } else { formChar[1] = false } } //記号 @IBAction func charSymbol(_ sender: UISwitch) { if sender.isOn == true { formChar[2] = true } else { formChar[2] = false } } //同じ文字を含めるか @IBAction func charSame(_ sender: UISwitch) { if sender.isOn == true { permissionSameChar = true } else { permissionSameChar = false } } //おまかせ(小文字と大文字を含める) @IBAction func randomChar(_ sender: UISwitch) { //乱数の文字数 numberOfChar = 10 //パスワードの個数 numberOfPassword = 10 //乱数に含めたい文字を文字列として準備 characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" //指定された条件を基にパスワードを生成 //パスワードを配列に格納していく generatePasswordFunc() dismiss(animated: true, completion: nil) } //カオス(小文字と大文字と記号を含める) @IBAction func chaosChar(_ sender: UISwitch) { //文字数 numberOfChar = 20 //パスワードの数 numberOfPassword = 15 //乱数に含めたい文字を文字列として準備 characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%&()=~^|@[;:],./<>?+*}`{σΣαβγ" //指定された条件を基にパスワードを生成 //パスワードを配列に格納していく generatePasswordFunc() dismiss(animated: true, completion: nil) } //パスワードを生成するUIButton @IBAction func generatePassword(_ sender: Any) { //もし個数が設定されてなければ、生成しない if numberOfPassword == 0 { return } //もし文字数が設定されてなければ、生成しない if numberOfChar == 0 { return } //もし文字形態が1つも設定されてなければ、生成しない if formChar[0]==false && formChar[1]==false && formChar[2]==false { return } //どんな文字を含めたいかを設定 branchOfChar() //"同じ文字を含めるか"がON if permissionSameChar == true { //同じ文字が含まれないように生成 generatePasswordFunc() //"同じ文字を含めるか"がOFF } else { //文字が重複しないように生成 generateNotSamePasswordFunc() } dismiss(animated: true, completion: nil) } //同じ文字を含める場合のパスワードを生成関数 func generatePasswordFunc() { //指定した個数分だけ繰り返す for _ in 0..<numberOfPassword { //設定した文字数になるまで文字をランダムに生成し続ける for _ in 0..<numberOfChar { //charactersの要素番号をランダムに選出 len = Int(arc4random_uniform(UInt32(characters.count - 1))) //1文字目からlen番目の文字を追加 randomCharacters += String(characters[characters.index(characters.startIndex, offsetBy: len)]) } //配列に含める passwordArray.append(randomCharacters) //初期化 //次回のループを行うために randomCharacters = "" } //ViewControllerに渡すための配列に追加する UD.set(passwordArray, forKey: "passwordArray") //初期化処理 passwordArray = [String]() //遷移 dismiss(animated: true, completion: nil) } //パスワード生成の関数 func generateNotSamePasswordFunc() { //重複チェックを行うために、一旦文字を格納していく var sameCharArray = [String]() //重複チェック後の文字らを格納 var notsameCharArray = [String]() for _ in 0..<numberOfPassword { //重複を繰り返し、設定した文字数になるまで繰り返す while (notsameCharArray.count <= numberOfChar) { len = Int(arc4random_uniform(UInt32(characters.count - 1))) //1文字目からlen番目の文字を追加 randomCharacters = String(characters[characters.index(characters.startIndex, offsetBy: len)]) //生成した乱数文字を配列に格納 sameCharArray.append(randomCharacters) //重複チェック(重複した文字は1つだけになる) let orderSet = NSOrderedSet(array: sameCharArray) //重複のない配列 notsameCharArray = orderSet.array as! [String] //更新 sameCharArray = notsameCharArray } //配列を結合 randomPassword = notsameCharArray.joined() //配列に含める passwordArray.append(randomPassword) //初期化 randomCharacters = "" randomPassword = "" sameCharArray = [] notsameCharArray = [] } //ViewControllerに渡すための配列に追加する UD.set(passwordArray, forKey: "passwordArray") //初期化処理 passwordArray = [String]() //遷移 dismiss(animated: true, completion: nil) } //文字形態の条件分岐 func branchOfChar() { switch (formChar[0],formChar[1],formChar[2]) { case (true, false, false): //小文字 characters = "abcdefghijklmnopqrstuvwxyz" case (false, true, false): //大文字 characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" case (false, false, true): //記号 characters = "0123456789!#$%&()=~^|@[;:],./<>?+*}`{" case (true, true, false): //小文字と大文字 characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" case (true, false, true): //小文字と記号 characters = "abcdefghijklmnopqrstuvwxyz0123456789!#$%&()=~^|@[;:],./<>?+*}`{" case (false, true, true): //大文字と記号 characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%&()=~^|@[;:],./<>?+*}`{" case (true, true, true): //小文字と大文字と記号 characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%&()=~^|@[;:],./<>?+*}`{" default: break } } }