前提・実現したいこと
Swiftでオリジナルのキーボードを作成しようとしています。
こちらのサンプルプログラムをダウンロードし、Objective-Cで書かれていたのでSwiftに書き換えて改造しようとしました。
https://github.com/bjhstudios/iOSCustomKeyboard
発生している問題・エラーメッセージ
viewDidLoad関数から呼び出されたinitializeKeyboard関数の中のself.spaceButton.addGestureRecognizer(spaceDoubleTap)の部分において
Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
が発生します。
該当のソースコード
Swift
1// 2// KeyboardViewController.swift 3// keyboard 4// 5// Created by KAZUSHIGE SATO on 2018/06/06. 6// Copyright © 2018年 KAZUSHIGE SATO. All rights reserved. 7// 8 9import UIKit 10 11class KeyboardViewController: UIInputViewController { 12 13 var _shiftStatus : Int = 0 //0 = off, 1 = on, 2 = caps lock 14 15 //keyboard rows 16 @IBOutlet weak var numbersRow1View: UIView! 17 @IBOutlet weak var numbersRow2View: UIView! 18 @IBOutlet weak var symbolsRow1View: UIView! 19 @IBOutlet weak var symbolsRow2View: UIView! 20 @IBOutlet weak var numbersSymbolsRow3View: UIView! 21 22 //keys 23 // これはどうやって書き換えるのか? 24//@property (nonatomic, strong) IBOutletCollection(UIButton) NSArray *letterButtonsArray; 25 @IBOutlet weak var letterButtonsArray: NSArray! 26 @IBOutlet weak var switchModeRow3Button: UIButton! 27 @IBOutlet weak var switchModeRow4Button: UIButton! 28 @IBOutlet weak var shiftButton: UIButton! 29 @IBOutlet weak var spaceButton: UIButton! 30 31 override func updateViewConstraints() { 32 super.updateViewConstraints() 33 34 // Add custom view sizing constraints here 35 } 36 37 override func viewDidLoad() { 38 super.viewDidLoad() 39 40 DispatchQueue.main.async { 41 self.initializeKeyboard() 42 } 43 } 44 45 override func viewWillLayoutSubviews() { 46 super.viewWillLayoutSubviews() 47 48 } 49 50 func initializeKeyboard() { 51 //start with shift on 52 _shiftStatus = 1 53 //initialize space key double tap 54 let spaceDoubleTap = UITapGestureRecognizer(target: self, action: #selector(spaceKeyDoubleTapped)) 55 spaceDoubleTap.numberOfTapsRequired = 2 56 spaceDoubleTap.delaysTouchesEnded = false 57 self.spaceButton.addGestureRecognizer(spaceDoubleTap) 58 59 //initialize shift key double and triple tap 60 let shiftDoubleTap = UITapGestureRecognizer.init(target: self, action: #selector(shiftKeyDoubleTapped)) 61 let shiftTripleTap = UITapGestureRecognizer.init(target: self, action: #selector(shiftKeyPressed)) 62 63 shiftDoubleTap.numberOfTapsRequired = 2 64 shiftTripleTap.numberOfTapsRequired = 3 65 66 shiftDoubleTap.delaysTouchesEnded = false 67 shiftTripleTap.delaysTouchesEnded = false 68 69 self.shiftButton.addGestureRecognizer(shiftDoubleTap) 70 self.shiftButton.addGestureRecognizer(shiftTripleTap) 71 } 72 73 override func didReceiveMemoryWarning() { 74 super.didReceiveMemoryWarning() 75 // Dispose of any resources that can be recreated 76 } 77 78 override func textWillChange(_ textInput: UITextInput?) { 79 // The app is about to change the document's contents. Perform any preparation here. 80 } 81 82 override func textDidChange(_ textInput: UITextInput?) { 83 // The app has just changed the document's contents, the document context has been updated. 84 85 86 } 87 @IBAction func globeKeyPressed(sender: Any) { 88 //required functionality, switches to user's next keyboard 89 self.advanceToNextInputMode() 90 } 91 @IBAction func keyPressed(sender: UIButton) { 92 //inserts the pressed character into the text document 93 self.textDocumentProxy.insertText((sender.titleLabel?.text!)!) 94 95 //if shiftStatus is 1, reset it to 0 by pressing the shift key 96 if (_shiftStatus == 1) { 97 self.shiftKeyPressed(self.shiftButton) 98 } 99 } 100 @IBAction func backspaceKeyPressed(sender: UIButton) { 101 102 self.textDocumentProxy.deleteBackward() 103 104 } 105 @IBAction func spaceKeyPressed(_ sender: Any) { 106 self.textDocumentProxy.insertText(" ") 107 } 108 /* 109 func spaceKeyDoubleTapped(sender: UIButton) { 110 //double tapping the space key automatically inserts a period and a space 111 //if necessary, activate the shift button 112 self.textDocumentProxy.deleteBackward() 113 self.textDocumentProxy.insertText(". ") 114 115 if (_shiftStatus == 0) { 116 self.shiftKeyPressed(self.shiftButton) 117 } 118 } 119 */ 120 @IBAction func returnKeyPressed(sender: UIButton) { 121 self.textDocumentProxy.insertText("\n") 122 } 123 124 @objc func shiftKeyDoubleTapped(_ sender: UIButton) { 125 _shiftStatus = 2 126 127 self.shiftKeys() 128 } 129 @IBAction func shiftKeyPressed(_ sender: UIButton) { 130 //if shift is on or in caps lock mode, turn it off. Otherwise, turn it on 131 _shiftStatus = _shiftStatus > 0 ? 0 : 1; 132 133 self.shiftKeys() 134 } 135 func shiftKeys() { 136 137 //if shift is off, set letters to lowercase, otherwise set them to uppercase 138 if (_shiftStatus == 0) { 139 for letterButton in self.letterButtonsArray { 140 (letterButton as! UIButton).setTitle((letterButton as! UIButton).titleLabel?.text?.lowercased(), for:UIControlState.normal) 141 } 142 } else { 143 for letterButton in self.letterButtonsArray { 144 (letterButton as! UIButton).setTitle((letterButton as! UIButton).titleLabel?.text?.uppercased(), for:UIControlState.normal) 145 } 146 } 147 148 //adjust the shift button images to match shift mode 149 let shiftButtonImageName = String.init(format:"shift_%i.png", arguments: [_shiftStatus]) 150 self.shiftButton.setImage(UIImage(named: shiftButtonImageName), for:UIControlState.normal) 151 152 let shiftButtonHLImageName = String.init(format:"shift_%iHL.png", arguments: [_shiftStatus]) 153 self.shiftButton.setImage(UIImage(named: shiftButtonHLImageName), for:UIControlState.highlighted) 154 155 } 156 157 @objc func spaceKeyDoubleTapped(_ sender: UIButton) { 158 159 //double tapping the space key automatically inserts a period and a space 160 //if necessary, activate the shift button 161 self.textDocumentProxy.deleteBackward() 162 self.textDocumentProxy.insertText(". ") 163 164 if (_shiftStatus == 0) { 165 self.shiftKeyPressed(self.shiftButton) 166 } 167 168 } 169 170 @IBAction func switchKeyboardMode(sender :UIButton) { 171 172 self.numbersRow1View.isHidden = true 173 self.numbersRow2View.isHidden = true 174 self.symbolsRow1View.isHidden = true 175 self.symbolsRow2View.isHidden = true 176 self.numbersSymbolsRow3View.isHidden = true 177 178 //switches keyboard to ABC, 123, or #+= mode 179 //case 1 = 123 mode, case 2 = #+= mode 180 //default case = ABC mode 181 182 switch (sender.tag) { 183 184 case 1: 185 self.numbersRow1View.isHidden = false 186 self.numbersRow2View.isHidden = false 187 self.numbersSymbolsRow3View.isHidden = false 188 189 //change row 3 switch button image to #+= and row 4 switch button to ABC 190 self.switchModeRow3Button.setImage(UIImage(named:"symbols.png"), for:UIControlState.normal) 191 self.switchModeRow3Button.setImage(UIImage(named:"symbolsHL.png"), for:UIControlState.highlighted) 192 self.switchModeRow3Button.tag = 2 193 self.switchModeRow4Button.setImage(UIImage(named: "abc.png"), for:UIControlState.normal) 194 self.switchModeRow4Button.setImage(UIImage(named: "abcHL.png") , for:UIControlState.highlighted) 195 self.switchModeRow4Button.tag = 0; 196 197 198 case 2: 199 self.symbolsRow1View.isHidden = false 200 self.symbolsRow2View.isHidden = false 201 self.numbersSymbolsRow3View.isHidden = false 202 203 //change row 3 switch button image to 123 204 self.switchModeRow3Button.setImage(UIImage(named: "numbers.png"), for:UIControlState.normal) 205 self.switchModeRow3Button.setImage(UIImage(named: "numbersHL.png"), for:UIControlState.highlighted) 206 self.switchModeRow3Button.tag = 1 207 208 default: 209 //change the row 4 switch button image to 123 210 self.switchModeRow4Button.setImage(UIImage(named: "numbers.png"), for:UIControlState.normal) 211 self.switchModeRow4Button.setImage(UIImage(named: "numbersHL.png"), for:UIControlState.highlighted) 212 self.switchModeRow4Button.tag = 1 213 214 215 } 216 217} 218} 219 220
試したこと
サンプルプログラムには、キーボードのビューがKeyboard.storyboardが梱包されていたのでこちらを取り込みました。
https://github.com/bjhstudios/iOSCustomKeyboard
@IBOutletとstoryboardの接続がうまくできてないのかと思い、spaceButtonとの接続を解除→再接続してみたが、事象は再現してしまいました。
元のサンプルプログラム内ではUIButtonオブジェクトを生成しなくても実行できるのですが、私がSwiftに転記したバージョンでは、self.spaceButtonがnilになっているので、ここで実行時エラーになり止まってしまったようです。
補足情報(FW/ツールのバージョンなど)
Xcode 9.2を使用しています。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/08/01 09:40
2019/01/20 02:55