質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.35%

  • Swift

    7625questions

    Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

カスタムキーボード作成中に遭遇したUIButtonがnilで実行時エラー

受付中

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 181

sacakoro

score 1

 前提・実現したいこと

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)


が発生します。

 該当のソースコード

//
//  KeyboardViewController.swift
//  keyboard
//
//  Created by KAZUSHIGE SATO on 2018/06/06.
//  Copyright © 2018年 KAZUSHIGE SATO. All rights reserved.
//

import UIKit

class KeyboardViewController: UIInputViewController {

    var _shiftStatus : Int = 0 //0 = off, 1 = on, 2 = caps lock

    //keyboard rows
    @IBOutlet weak var numbersRow1View: UIView!
    @IBOutlet weak var numbersRow2View: UIView!
    @IBOutlet weak var symbolsRow1View: UIView!
    @IBOutlet weak var symbolsRow2View: UIView!
    @IBOutlet weak var numbersSymbolsRow3View: UIView!

    //keys
    // これはどうやって書き換えるのか?
//@property (nonatomic, strong) IBOutletCollection(UIButton) NSArray *letterButtonsArray;
    @IBOutlet weak var letterButtonsArray: NSArray!
    @IBOutlet weak var switchModeRow3Button: UIButton!
    @IBOutlet weak var switchModeRow4Button: UIButton!
    @IBOutlet weak var shiftButton: UIButton!
    @IBOutlet weak var spaceButton: UIButton!

    override func updateViewConstraints() {
        super.updateViewConstraints()

        // Add custom view sizing constraints here
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        DispatchQueue.main.async {
            self.initializeKeyboard()
        }
    }

    override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()

    }

    func initializeKeyboard() {
        //start with shift on
        _shiftStatus = 1
        //initialize space key double tap
        let spaceDoubleTap = UITapGestureRecognizer(target: self, action: #selector(spaceKeyDoubleTapped))
        spaceDoubleTap.numberOfTapsRequired = 2
        spaceDoubleTap.delaysTouchesEnded = false
        self.spaceButton.addGestureRecognizer(spaceDoubleTap)

        //initialize shift key double and triple tap
        let shiftDoubleTap = UITapGestureRecognizer.init(target: self, action: #selector(shiftKeyDoubleTapped))
        let shiftTripleTap = UITapGestureRecognizer.init(target: self, action: #selector(shiftKeyPressed))

        shiftDoubleTap.numberOfTapsRequired = 2
        shiftTripleTap.numberOfTapsRequired = 3

        shiftDoubleTap.delaysTouchesEnded = false
        shiftTripleTap.delaysTouchesEnded = false

        self.shiftButton.addGestureRecognizer(shiftDoubleTap)
        self.shiftButton.addGestureRecognizer(shiftTripleTap)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated
    }

    override func textWillChange(_ textInput: UITextInput?) {
        // The app is about to change the document's contents. Perform any preparation here.
    }

    override func textDidChange(_ textInput: UITextInput?) {
        // The app has just changed the document's contents, the document context has been updated.


    }
    @IBAction func globeKeyPressed(sender: Any) {
         //required functionality, switches to user's next keyboard
        self.advanceToNextInputMode()
    }
    @IBAction func keyPressed(sender: UIButton) {
        //inserts the pressed character into the text document
        self.textDocumentProxy.insertText((sender.titleLabel?.text!)!)

        //if shiftStatus is 1, reset it to 0 by pressing the shift key
        if (_shiftStatus == 1) {
            self.shiftKeyPressed(self.shiftButton)
        }
    }
    @IBAction func backspaceKeyPressed(sender: UIButton) {

        self.textDocumentProxy.deleteBackward()

    }
    @IBAction func spaceKeyPressed(_ sender: Any) {
    self.textDocumentProxy.insertText(" ")
    }
    /*
    func spaceKeyDoubleTapped(sender: UIButton) {
        //double tapping the space key automatically inserts a period and a space
        //if necessary, activate the shift button
        self.textDocumentProxy.deleteBackward()
        self.textDocumentProxy.insertText(". ")

        if (_shiftStatus == 0) {
            self.shiftKeyPressed(self.shiftButton)
        }
    }
 */
    @IBAction func returnKeyPressed(sender: UIButton) {
        self.textDocumentProxy.insertText("\n")
    }

    @objc func shiftKeyDoubleTapped(_ sender: UIButton) {
        _shiftStatus = 2

        self.shiftKeys()
    }
    @IBAction func shiftKeyPressed(_ sender: UIButton) {
        //if shift is on or in caps lock mode, turn it off. Otherwise, turn it on
        _shiftStatus = _shiftStatus > 0 ? 0 : 1;

        self.shiftKeys()
    }
    func shiftKeys() {

    //if shift is off, set letters to lowercase, otherwise set them to uppercase
    if (_shiftStatus == 0) {
        for letterButton in self.letterButtonsArray {
            (letterButton  as! UIButton).setTitle((letterButton as! UIButton).titleLabel?.text?.lowercased(), for:UIControlState.normal)
    }
    } else {
        for letterButton in self.letterButtonsArray {
            (letterButton  as! UIButton).setTitle((letterButton as! UIButton).titleLabel?.text?.uppercased(), for:UIControlState.normal)
        }
    }

    //adjust the shift button images to match shift mode
        let shiftButtonImageName = String.init(format:"shift_%i.png", arguments: [_shiftStatus])
        self.shiftButton.setImage(UIImage(named: shiftButtonImageName), for:UIControlState.normal)

        let shiftButtonHLImageName = String.init(format:"shift_%iHL.png", arguments: [_shiftStatus])
        self.shiftButton.setImage(UIImage(named: shiftButtonHLImageName), for:UIControlState.highlighted)

    }

    @objc func spaceKeyDoubleTapped(_ sender: UIButton) {

        //double tapping the space key automatically inserts a period and a space
        //if necessary, activate the shift button
        self.textDocumentProxy.deleteBackward()
        self.textDocumentProxy.insertText(". ")

        if (_shiftStatus == 0) {
            self.shiftKeyPressed(self.shiftButton)
        }

    }

    @IBAction func switchKeyboardMode(sender :UIButton) {

        self.numbersRow1View.isHidden = true
        self.numbersRow2View.isHidden = true
        self.symbolsRow1View.isHidden = true
        self.symbolsRow2View.isHidden = true
        self.numbersSymbolsRow3View.isHidden = true

    //switches keyboard to ABC, 123, or #+= mode
    //case 1 = 123 mode, case 2 = #+= mode
    //default case = ABC mode

    switch (sender.tag) {

    case 1:
    self.numbersRow1View.isHidden = false
    self.numbersRow2View.isHidden = false
    self.numbersSymbolsRow3View.isHidden = false

    //change row 3 switch button image to #+= and row 4 switch button to ABC
    self.switchModeRow3Button.setImage(UIImage(named:"symbols.png"), for:UIControlState.normal)
    self.switchModeRow3Button.setImage(UIImage(named:"symbolsHL.png"), for:UIControlState.highlighted)
        self.switchModeRow3Button.tag = 2
    self.switchModeRow4Button.setImage(UIImage(named: "abc.png"), for:UIControlState.normal)
    self.switchModeRow4Button.setImage(UIImage(named: "abcHL.png") , for:UIControlState.highlighted)
        self.switchModeRow4Button.tag = 0;


    case 2:
        self.symbolsRow1View.isHidden = false
        self.symbolsRow2View.isHidden = false
        self.numbersSymbolsRow3View.isHidden = false

        //change row 3 switch button image to 123
        self.switchModeRow3Button.setImage(UIImage(named: "numbers.png"), for:UIControlState.normal)
        self.switchModeRow3Button.setImage(UIImage(named: "numbersHL.png"), for:UIControlState.highlighted)
        self.switchModeRow3Button.tag = 1

    default:
        //change the row 4 switch button image to 123
        self.switchModeRow4Button.setImage(UIImage(named: "numbers.png"), for:UIControlState.normal)
        self.switchModeRow4Button.setImage(UIImage(named: "numbersHL.png"), for:UIControlState.highlighted)
        self.switchModeRow4Button.tag = 1


    }

}
}

 試したこと

サンプルプログラムには、キーボードのビューがKeyboard.storyboardが梱包されていたのでこちらを取り込みました。
https://github.com/bjhstudios/iOSCustomKeyboard

@IBOutletとstoryboardの接続がうまくできてないのかと思い、spaceButtonとの接続を解除→再接続してみたが、事象は再現してしまいました。

元のサンプルプログラム内ではUIButtonオブジェクトを生成しなくても実行できるのですが、私がSwiftに転記したバージョンでは、self.spaceButtonがnilになっているので、ここで実行時エラーになり止まってしまったようです。

 補足情報(FW/ツールのバージョンなど)

Xcode 9.2を使用しています。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

0

あくまで推測になってしまいますが、おそらくKeyboard.storyboardの取り込み方などでファイルの紐付けがうまくいっていないのかなと思います。
spaceButtonとの接続解除、再接続についてですが、storyboardから直接コードとの接続をしましたでしょうか。
(以下のような感じでswiftコードと直接つなげる。storyboard内でのつなぎだとobjective-c側とつながってしまっているようなことが起こるかも)
[Xcode][IB] IBOutletやIBActionをマウス操作で接続

また、storyboardについて一度削除をして、新しいプロジェクト内で新しく作ったstoryboardにいちから自分でファイルを作成してみる。もしくはstoryboardファイルのみプロジェクト内にコピーしてきてそこから入れ込むのようなかたちでもいけるかもしれません。
(取り込み方について、どのように取り込んだのかがわからないため、すでにそのようにして取り込んでいるかもしれませんが)
新しいstoryboardを作成する際には全部作成してから全部をつなぎこむと大変だと思いますので、spaceButtonのみ配置してつないでみる。(一番最初に呼ばれる部品がspaceButtonだと思いますので、そこをつないでnilになっていなければ一から作成すれば大丈夫と判断できる。)

カスタムキーボード作成についての内容はその他についてこちらに詳しい内容がのっていましたご参考までに(すでに参照済みかもしれませんが)
iOSカスタムキーボードの作り方

以上のようなことを試しても直らなかった場合、私の方でも実装試してみようと思いますのでコメントください。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/08/01 18:40

    もしくはプロジェクトごとどこかにあげていただければそちらの方で直してみようと思います。

    キャンセル

同じタグがついた質問を見る

  • Swift

    7625questions

    Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています