53661


このサイトを参考にtextViewがキーボードで隠れないようにしているのですがなかなかうまく行きません。  
[【Xcode】キーボードで隠れないようにスクロール](http://an.hatenablog.jp/entry/2015/10/04/194245)

コードはこのような感じです。

[code]

    class addScheduleVC: UIViewController {
        var tableView = UITableView()
        var lastKeyboardFrame: CGRect = CGRect.zero
        var editingPath: NSIndexPath!
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            tableView = UITableView(frame: self.view.frame, style: .grouped)
            tableView.delegate = self
            tableView.dataSource = self
    　 　}
    
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
        }
        override func viewWillAppear(_ animated: Bool) {
            tableView.reloadData()
            registerNotification()
        }
        override func viewWillDisappear(_ animated: Bool) {
            super.viewWillDisappear(animated)
            unregisterNotification()
        }
    
        func registerNotification() -> () {
            let center: NotificationCenter = NotificationCenter.default
            center.addObserver(self, selector: Selector(("keyboardWillShow:")), name: UIResponder.keyboardWillShowNotification, object: nil)
            center.addObserver(self, selector: Selector(("keyboardWillHide:")), name: UIResponder.keyboardWillHideNotification, object: nil)
        }
    
        func unregisterNotification() -> () {
            let center: NotificationCenter = NotificationCenter.default
            center.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil)
            center.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
        }
    
        func keyboardWillShow(notification: NSNotification) -> () {
            scrollTableCell(notification: notification, showKeyboard: true)
        }
    
        // Keyboard非表示前処理
        func keyboardWillHide(notification: NSNotification) -> () {
            scrollTableCell(notification: notification, showKeyboard: false)
        }
    
        // TableViewCellをKeyboardの上までスクロールする処理
        func scrollTableCell(notification: NSNotification, showKeyboard: Bool) -> () {
            if showKeyboard {
                // keyboardのサイズを取得
                var keyboardFrame: CGRect = CGRect.zero
                if let userInfo = notification.userInfo {
                    if let keyboard = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue {
                        keyboardFrame = keyboard.cgRectValue
                    }
                }
    
                // keyboardのサイズが変化した分ContentSizeを大きくする
                let diff: CGFloat = keyboardFrame.size.height - keyboardFrame.size.height
                let newSize: CGSize = CGSize(width: tableView.contentSize.width, height: tableView.contentSize.height + diff)
                tableView.contentSize = newSize
                lastKeyboardFrame = keyboardFrame
    
                // keyboardのtopを取得
                let keyboardTop: CGFloat = UIScreen.main.bounds.size.height - keyboardFrame.size.height;
    
                // 編集中セルのbottomを取得
                let cell: UITableViewCell = tableView.cellForRow(at: NSIndexPath(row: editingPath.row, section: editingPath.section) as IndexPath)!
                let cellBottom: CGFloat
                cellBottom = (cell.frame.origin.y) - tableView.contentOffset.y + cell.frame.size.height;
    
                // 編集中セルのbottomがkeyboardのtopより下にある場合
                if keyboardTop < cellBottom {
                    // 編集中セルをKeyboardの上へ移動させる
                    let newOffset: CGPoint = CGPoint(x: tableView.contentOffset.x, y: tableView.contentOffset.y + cellBottom - keyboardTop)
                    tableView.setContentOffset(newOffset, animated: true)
                }
            } else {
                // 画面を下に戻す
                let newSize: CGSize = CGSize(width: tableView.contentSize.width, height: tableView.contentSize.height - lastKeyboardFrame.size.height)
                tableView.contentSize = newSize
                tableView.scrollToRow(at: editingPath as IndexPath, at: UITableView.ScrollPosition.none, animated: true)
                lastKeyboardFrame = CGRect.zero;
            }
        }
    
[/code]

エラーコードは

[code]

    keyboardWillHide:]: unrecognized selector sent to instance 0x7fa9bb8b3800'
    
[/code]

このような感じです


CC BY-SA 4.0
2019-03-22T11:48:21.430
53656
2019-03-23T03:24:28.547
32274
question
swift ios swift4
textViewがキーボードで隠れてしまうのを防ぎたい


参考にされている記事が古すぎますね。Swift2時代のものでしょうか。

あなたのコードで致命的にまずいのは、ここです。

[code]

    center.addObserver(self, selector: Selector(("keyboardWillShow:")), name: UIResponder.keyboardWillShowNotification, object: nil)
    center.addObserver(self, selector: Selector(("keyboardWillHide:")), name: UIResponder.keyboardWillHideNotification, object: nil)
    
[/code]

Xcodeがこう書き直すよう提案したのかも知れませんが、`Selector(("..."))`という構文は「使っちゃいけないもの」と思っていた方が良いでしょう。

セレクタを渡さなければいけないメソッドでは、`#selector(...)`構文を使ってください。

[code]

    center.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
    center.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
    
[/code]

この修正を行うと、Xcodeがこうしろ、なんて示してくるはずです。

[code]

    @objc func keyboardWillShow(notification: Notification) -> () {
        scrollTableCell(notification: notification, showKeyboard: true)
    }
    
    // Keyboard非表示前処理
    @objc func keyboardWillHide(notification: Notification) -> () {
        scrollTableCell(notification: notification, showKeyboard: false)
    }
    
[/code]

現在のSwiftではセレクタ経由で呼ばれるメソッドには、ほとんどの場合に`@objc`を付けてやらないといけません。

この修正だけであなたの所望の動作をするようになるかどうかは何とも言えませんが、少なくとも`unrecognized selector sent to
instance`なんて実行時エラーは出なくなるので、先に進めるのではないかと思います。

* * *

その他にもあなたのコードには、現在のSwiftのコードとしては、とても我慢ならないものが大量に転がっています。

  * Swift では型名は大文字始まりにする

`addScheduleVC`なんて小文字始まりは良くないです。ついでに言うと`add`なんて動詞始まりもよくないんですが、そちらは日本人開発者同士では気にしない人の方が多いかも知れません。

  * プロパティの宣言で無駄なインスタンスを作っている

`var tableView =
UITableView()`のようなプロパティ宣言はやめた方が良いでしょう。`viewDidLoad()`の中で、`UITableView`のインスタンスを作って代入するんですから、プロパティ宣言の中ですぐに捨てられる無駄なインスタンスを作るべきではありません。

`var tableView: UITableView!`で良いでしょう。

  * `NSIndexPath`でなく、`IndexPath`を使うべき。

`NSIndexPath`なんてものを使っているせいで、`as IndexPath`なんて余計なコードがあちこちに必要になっています。Objective-
Cで`NSIndexPath`を使っていたAPIはSwiftには`IndexPath`として移入されます。初めから`IndexPath`を使いましょう。

  * 自動アンラップ型オプショナルの使い方がおかしい

`var editingPath:
NSIndexPath!`という宣言をしています。`editingPath`に値を入れる部分は今回示されていないようですが、プログラムの実行状態によっては、`editingPath`は未初期化、つまり`nil`である可能性が考えられます。そのような場合は通常のオプショナルを使用してください。

`var editingPath: IndexPath?`

もちろんこれによりあちこち修正が必要になります。

本題ではないので、この辺にしておきます。

* * *

Swiftは非常に速い速度で変化してきており、古いコードを持ってきてXcodeのおすすめ通りの変換していっても、動かなかったり、現在のSwiftのプログラムとしては奇妙奇天烈なコードが出来上がります。

Swiftの歴史を追体験したいというのでない限り、少なくともSwift
4以降用に書かれた解説記事を参考にされることをお勧めします。また、あまりにも古い記事では、iOS自体の動きが変わってしまっていて動かない場合もあります。

より新しい、より良いものを上手く見つけられるようにしてください。


CC BY-SA 4.0
2019-03-23T03:24:28.547
53661
2019-03-23T03:24:28.547
13972
53656
answer