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

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

ただいまの
回答率

88.04%

テーブルビューのセルに置いたTextFieldへ入力して計算を行いたい

解決済

回答 3

投稿

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

score 50

swiftは素人です。
今日の午前に、ちょっとしたデータ管理アプリの制作にあたって躓いたところを質問させていただきました。
https://teratail.com/questions/194689

セルの中に置いたテキストフィールドとラベルの入力操作について、「UITextFieldDelegateか、notificationを使ってみてはどうか」というアドバイスを受け、それを参考に進めていきました。
そこで、通知を受け取ってfuncを走らせることができたのはいいものの、発生したエラーのために先に進められない状況です。

class TableviewCell, UITableViewCell, UITextFieldDelegate {

override func awakeFromNib() {
    super.awakeFromNib()

    NotificationCenter.default.addObserver(self, selector: #selector(self.changeText(sender:)), name: UITextField.textDidEndEditingNotification, ocject: nil)

}

@IBOutlet weak var x: UITextField!
@IBOutlet weak var y: UITextField!
@IBOutlet weak var total: UILabel!
.
.
.

func changeText(sender: Notification) {
   guard let textview = sender.object as? UITextField else {
      print("失敗")
      return
      } if textview != nil {
      print("一応成功")
      var Total: Int = Int(total.text!)!
      var X: Int = Int(x.text!)!
      var Y: Int = Int(y.text!)!
      Total = X + Y
      total.text = "\(Total)"
      }
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
     textField.resignFirstResponder()
     self.endEditing(true)
     return true
}

.
.
.

}

このように書いてシミュレーターを起動し、実際に入力してtotalの値が変わるのかどうかを確かめようとしたところ、入力し終わり、リターンキーを押してキーボードが閉じるタイミングでアプリがクラッシュし、var Totalが書かれた行に以下のようなエラー文が表示されました。

Thread 1: Fattal error: Unexpectedly found nil while implicitly unwrapping an Optional Value

コンソールを見たところ、確かにTotal,X,Yのところは =(int) 0 と表示されており、本来入っている値が入っていませんでした。

試してみたこと

・・・と、言っていいかわかりませんが、変数に入れる前のオブジェクトの中の文字列をprint文で出力してみると、一番上の行以外に入力しても必ず一番上の値になっていました。(一番上に入力した時は値が入力したものに変わっていました。)
イメージ説明

func changeText(sender: Notification) {
   guard let textview = sender.object as? UITextField else {
      print("失敗")
      return
      } if textview != nil {
      print("一応成功")
      print(total.text.debugDescription)   //必ずOptional("500")
      print(x.text.debugDescription)         //必ずOptional("250")
      print(y.text.debugDescription)         //必ずOptional("250")
      var Total: Int = Int(total.text!)!
      var X: Int = Int(x.text!)!
      var Y: Int = Int(y.text!)!
      Total = X + Y
      total.text = "\(Total)"
      }
}


拙い質問で恐縮ですが、なんとか突破口を見出したいです。
教えていただけると助かります。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 3

check解決した方法

0

質問からいろいろと調べて、とりあえずの解決はできたので自己解決として記します。

class TableviewCell, UITableViewCell, UITextFieldDelegate {

var delegate: CustomTableviewCellDelegate! = nil

override func awakeFromNib() {
    super.awakeFromNib()
}

@IBOutlet weak var x: UITextField!
@IBOutlet weak var y: UITextField!
@IBOutlet weak var total: UILabel!

func Calculation(Item: Entity) {
   x.text = Item.cell1?.stringValue
   y.text = Item.cell2?.stringValue
   total.text = Item.total.stringValue
}

func textFieldShouldReturn(_ textField: UITextField) -> Bool {
     textField.resignFirstResponder()
     self.endEditing(true)
     return true
}

//追加記述です
func textFieldDidBeginEditing(_ textField: UITextField) {
     delegate.textFieldDidBeginEditing(cell: self, TextField: textField)
}

//追加記述です
func textFieldDidEndEditing(_ textField: UITextField) {
     delegate.textFieldDidEndEditing(cell: self, TextField: textField)
}    
}

//追加記述です。
protocol CustomTableviewCellDelegate {
  func textFieldDidBeginEditing(cell: UITableViewCell, TextField: UITextField) -> ()
  func textFieldDidEndEditing(cell: UITableViewCell, TextField: UITextField) -> ()
}

テーブルビューセルでこのような記述をしてから、テーブルビューが置いてあるビューコントローラーにて以下のように記述しました。

class ViewContloller: UIViewController, UITableViewDataSource, UITableViewDelegate, CustomTableviewCellDelegate {

@IBOutlet weak var CalculationTable: UITableView!

func textFieldDidBeginEditing(cell: UITableViewCell, TextField: UITextField) {
        let row = CalculationTable.indexPathForRow(at: cell.convert(cell.bounds.origin, to: CalculationTable))!.row
        switch TextField.tag {
        case 0:
            CalculationTable.selectRow(at: IndexPath.init(row: row, section: 0), animated: true, scrollPosition: .middle)
        case 1:
             CalculationTable.selectRow(at: IndexPath.init(row: row, section: 0), animated: true, scrollPosition: .middle)
        default:
            break

カスタムセルのXibファイルに置いたテキストフィールドに、アトリビュートインスペクタでタグとして番号を振りました。
これにより、テキストフィールを押下したときにそのテキストフィールドがあるセルが選択状態となります。
エラーの原因はセルが選択されていなかったからのようでした。

続けて計算して、ラベルを変える処理です。

private var ItemRec: [Entity] = []

func textFieldDidEndEditing(cell: UITableViewCell, TextField: UITextField) {
   let items = ItemRec[CalculationTable.indexPathForSelectedRow!.row]
   let CurrentCell = CalculationTable.cellForRow(at: CalculationTable.indexPathForSelectedRow!) as! TableviewCell
   let X = CurrentCell.x.text!
   let Y = CurrentCell.y.text!
   let Total = { (x: Int, y: Int) -> Int in
       let total = x + y
       return total
      }
   let Result = Total(Int(X)!, Int(Y)!)

   items.cell1 = Int(X)!
   items.cell2 = Int(Y)!
   items.total = Result

 //ここで、変更したデータを保存します。

 //テーブルビューをリフレッシュします。
  CalculationTable.reloadData()
 //選択状態を解除して、処理が終了します。
  CurrentCell.isSelected = false
}


テーブルのデータは永続ストアから読み込んだものを流し込んでいるので、永続ストアに変更したデータを保存して、テーブルをリフレッシュすれば、ラベルに表示される数字が新しいものに変わります。

こんな感じでやりたかった操作を実現させました。
正直まだいろいろやり方はあるかもしれないと思うところもありますが・・・。

質問に答えてくださった方、ご協力ありがとうございました。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

0

話の流れは判っていませんが、突破口とのことですので、

Thread 1: Fattal error: Unexpectedly found nil while implicitly unwrapping an Optional Value

は基本的にはオプショナル変数の値がnilになっているものを(中がnilかどうかを確認せずに)無理やり使っている時にでます。

nilになっている変数を見つけるところから始めてください。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/07/01 14:51

    回答からお返事が遅くなってしまい、申し訳ありませんでした。コメントとても参考になりました。ありがとうございました!

    キャンセル

0

NotificationCenter.default.addObserver(self, selector: #selector(self.changeText(sender:)), name: UITextField.textDidEndEditingNotification, object: nil)

ですと、全てのUITextFieldから通知が届きます。

NotificationCenter.default.addObserver(self, selector: #selector(self.changeText(sender:)), name: UITextField.textDidEndEditingNotification, object: x)

のようにobjectに対象とするUITextFieldを指定すると、そのUITextFieldインスタンスからの通知のみが届きます。xとy、2回addObserverを記述してみてください。そのxインスタンスとyインスタンスからの通知のみが届くはずです。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/07/01 14:51

    回答からお返事が遅くなってしまい、申し訳ありませんでした。コメントとても参考になりました。ありがとうございました!

    キャンセル

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

  • ただいまの回答率 88.04%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

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