##前提・実現したいこと
タップするとメッセージを送信するUIButtonの実装
##発生している問題
ビルドが通って実行されると、UIButtonの宣言(var sendBtn: UIButton = UIButton()の部分)で
Thread 1: EXC_BAD_ACCESS で落ちます。
正直原因が検討もつかないのでご助力いただけると幸いです。
BLEの練習を兼ねて、iOS同士のBLE片側通信でメッセージを送受信するプログラムを構築しています。
BLE関係を実装する前は
文字をTextFieldへ打ち込み
→UIButtonで送信
→TableViewへメッセージ反映 の流れで上手く動作していました。
裏でBLE関係の処理が行われていてそれが原因かもしれませんが、如何せん原因の検討がつかず確認の仕方もわかりません。
また、MainStoryBoardは削除しています。
StoryBoard側でエラーが発生している可能性はありません。
##該当のソースコード
Swift5
1 2// ViewController 3 4import Foundation 5import UIKit 6import CoreBluetooth 7 8class ViewController: UIViewController { 9 private let Log = Logger(category: "ViewCtrl" )! 10 11// /* 機種ごとの画面横幅と縦幅 */ 12// let width = view.frame.width 13// let height = view.frame.height 14 15 var sendMssView: UITableView = UITableView(frame: CGRect(x: 0,y: 0,width: 410,height: 600), style: UITableView.Style.plain) // 送信メッセージのテーブルビュー 16 var mssBox: UITextField = UITextField(frame: CGRect(x: 5, y: 750, width: 275, height: 25)) // 送信するメッセージを入力するフォーム 17 var sendBtn: UIButton = UIButton() 18 //type: UIButton.ButtonType.custom 19 20 21 let Peripheral: PeripheralService = PeripheralService() 22 23 override func viewDidLoad() { 24 super.viewDidLoad() 25 Log.i("viewDidLoad") 26 27 /* 28 TableViewの初期化 29 */ 30 sendMssView.delegate = self 31 sendMssView.dataSource = self 32 sendMssView.register(UITableViewCell.self, forCellReuseIdentifier: "myCell") //Cellを登録する 33 self.view.addSubview(sendMssView) 34 35 /* 36 TextField初期化 37 */ 38 mssBox.delegate = self 39 mssBox.text = "your message" // メッセージボックス内の文字 40 mssBox.borderStyle = .roundedRect // メッセージボックスのか枠線 41 mssBox.clearButtonMode = .whileEditing // 文字を全消しするボタン 42 self.view.addSubview(mssBox) 43 44 /* 45 Buttonの初期化 46 https://developer.apple.com/documentation/uikit/uibutton 47 */ 48 sendBtn.frame = CGRect(x: 300, y: 750, width: 60, height: 40) 49 sendBtn.backgroundColor = UIColor.cyan 50 sendBtn.setTitle("SEND", for: UIControl.State.normal) 51 sendBtn.setTitle("SEND", for: UIControl.State.highlighted) // ボタンを押した時の色 52 /* 53 .addTarget(self, action: #selector(sendBtnOnTap(sender:)), for: .touchUpInside) 54 self どのボタンに関するアクションか。selfなのでsendBtn 55 action: #selector(sendBtnOnTap(sender:)) 56 押された時の動作。#selecterはobjectCの書き方。対応する関数(sendBtnOnTap())の前に @objc をつける。 57 引数は冒頭冒頭Buttonの公式リファレンスListing 1参照 58 for: .touchUpInside ボタンの押され方 59 ”UIControl.Event”をつけて書いてるコードがネット上にあるけど動かないので消す 60 */ 61 sendBtn.addTarget(self, action: #selector(sendBtnOnTap(sender:)), for: .touchUpInside) 62 self.view.addSubview(sendBtn) 63 } 64 65} 66 67/* UITableViewの拡張 */ 68extension ViewController: UITableViewDelegate, UITableViewDataSource { 69 70 /* recvMssViewのセルの行数を指定する */ 71 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 72 return MessageList.sendMssList.count // リスト内の格納分を提供 73 } 74 75 /* sendMssViewのセルの中身を指定する */ 76 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 77 // 文字を表示するセルを取得する 78 let cell = tableView.dequeueReusableCell(withIdentifier: "myCell", for: indexPath) 79 // セルの中身を設定する 80 cell.textLabel!.text = MessageList.sendMssList[indexPath.row] 81 return cell 82 } 83 84 /* メッセージ画面を更新 */ 85 func addMssToView (){ 86 DispatchQueue.global(qos: .userInitiated).async { 87 DispatchQueue.main.async { 88 self.sendMssView.reloadData() 89 } 90 } 91 } 92 93 94 95} 96 97/* UITextFieldの拡張 */ 98extension ViewController: UITextFieldDelegate { 99 100 /* UITextFieldが編集された直前に呼ばれる */ 101 func textFieldDidBeginEditing(_ textField: UITextField) { 102 Log.i("mssBox Begin") 103 if textField == mssBox { 104 mssBox.text! = "" 105 MessageList.sendMss = textField.text! 106 } 107 } 108 109 /* UITextFieldが編集された直後に呼ばれる */ 110 func textFieldDidEndEditing(_ textField: UITextField) { 111 if textField == mssBox { 112 Log.i("mssBox End") 113 114 } 115 } 116 117 /* 改行ボタンが押された際に呼ばれる */ 118 func textFieldShouldReturn(_ textField: UITextField) -> Bool { 119 Log.i("textFieldShouldReturn (textField.text!)") 120 121 // 改行ボタンが押されたらKeyboardを閉じる処理. 122 mssBox.resignFirstResponder() 123 124 return true 125 } 126} 127 128/* UIButtonの拡張 */ 129extension ViewController { 130 /* ボタンが押された時のアクション,TextField内のメッセージを送信する */ 131 @objc func sendBtnOnTap(sender: UIButton){ 132 Log.i("SendBtn tapped") 133 if (sender == sendBtn) { 134 /* テーブルビューへメッセージを表示 135 配列が10以上の場合は一番古いものを削除 */ 136 if (MessageList.sendMssList.count > 9){ 137 MessageList.sendMssList.remove(at: 0) 138 } 139 MessageList.sendMss = mssBox.text! 140 MessageList.sendMssList.append(mssBox.text!) 141 Log.d(MessageList.sendMssList[MessageList.sendMssList.count - 1]) 142 143 /* ビューの更新 */ 144 addMssToView () 145 146 /* characteristicを書き換え、 147 書き換えを通知する */ 148 Peripheral.setCharacteristicValue() 149 150 /* 書き換え処理の非同期化 */ 151 DispatchQueue.global(qos: .userInitiated).async { 152 _ = self.Peripheral.updateValue(self.Peripheral.characteristic!.value!, 153 for:self.Peripheral.characteristic!, 154 onSubscribedCentrals: nil) 155 } 156 157 158 159 160 } 161 162 } 163 164} 165
Swift5
1 2// PeripheralService 3 4import Foundation 5import CoreBluetooth 6 7class PeripheralService: NSObject, CBPeripheralManagerDelegate { 8 private let Log = Logger(category: "Peripheral" )! 9 10 let VC: ViewController = ViewController() 11 12 var myPeripheralManager: CBPeripheralManager? 13 let advertisementData = [CBAdvertisementDataLocalNameKey: "Test Device"] // アドバタイズに乗せるデータ 14 static let serviceUUID: CBUUID = CBUUID(string: "566F2065-450F-4633-0123-456789ABCDEF") 15 static let characteristicUUID: CBUUID = CBUUID(string: "A1F86134-652D-1234-0123-456789ABCDEF") 16 static let descriptorUUID: CBUUID = CBUUID(string: "97A4D0DD-1556-4454-0123-456789ABCDEF") 17 static let charNotifyUUID: CBUUID = CBUUID(string: "A1F86134-652D-1234-FEDC-BA9876543210") 18 19 // サービスの設定、UUIDと 20 let service = CBMutableService(type: PeripheralService.serviceUUID, primary: true) 21 22 // プロパティの設定、このキャラクタリスティックに対して何ができるかを設定している 23 let readProperties: CBCharacteristicProperties = [.read] 24 25 // 認可の設定、キャラクタリスティックの読み取り、書き込み、暗号化の認可 26 let permissions: CBAttributePermissions = [.readable] 27 28 // キャラクタリスティックが属するサービスと、プロパティおよびその認可を設定 29 var characteristic: CBMutableCharacteristic? = nil 30 31 var requestList: [CBATTRequest] = [] 32 33 // 初期化 34 override init () { 35 super.init() 36 myPeripheralManager = CBPeripheralManager(delegate: self, queue: nil, options: nil) 37 } 38 39 40/******************************* 41 文字数が多いと怒られたので 42 アドバタイズ関係のコードを省略します 43********************************/ 44 45 46 func updateValue(_ value: Data, 47 for characteristic: CBMutableCharacteristic, 48 onSubscribedCentrals centrals: [CBCentral]?) -> Bool{ 49 50 Log.i("updateValue") 51 52 return true 53 } 54 55 56 func peripheralManagerIsReady(toUpdateSubscribers peripheral: CBPeripheralManager){ 57 Log.i("update Failed") 58 } 59 60 61 /* ViewControllerが直接characteristic.valueを書き換えたい時に呼ぶ */ 62 public func setCharacteristicValue(){ 63 Log.i("setCharacteristicValue") 64 var text: String = MessageList.sendMss 65 let data: [UInt8] = Array(text.utf8) 66 // characteristic!.value はData型。Stringを正しく代入する方法を考える 67 self.characteristic!.value = Data(bytes: data) 68 } 69 70} 71
##出現エラー
Thread 1: EXC_BAD_ACCESS (code=2, address=0x16fa83bc0)
デバックエリアへは
"warning: could not execute support code to read Objective-C class data in the process. This may reduce the quality of type information available."と出ます。
また、sendBtnはメモリアドレスが
"sendBtn = (UIButton) 0x0000000000000000"となっています。
UIButtonの初期化時に引数を与える方法も試しましたが、結果は変わりませんでした。
##使っているツールのバージョンなど補足情報
Swift 5.0
Xcode 11.0
iOS 12.3
MacOS Mojave 10.14.6
都合上、アップデートができません。
ご助力いただけますと幸いです。
回答1件
あなたの回答
tips
プレビュー