🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Bluetooth

Bluetoothとは短距離の間でデータを交換するための無線通信規格である。固定・モバイル両方のデバイスから、短波の電波送信を行うことで、高いセキュリティをもつパーソナルエリアネットワーク(PAN)を構築する。

Swift

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

Q&A

解決済

1回答

1666閲覧

UIButtonでThread 1: EXC_BAD_ACCESSエラー

saku_panda

総合スコア20

Bluetooth

Bluetoothとは短距離の間でデータを交換するための無線通信規格である。固定・モバイル両方のデバイスから、短波の電波送信を行うことで、高いセキュリティをもつパーソナルエリアネットワーク(PAN)を構築する。

Swift

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

0グッド

0クリップ

投稿2019/10/28 05:01

編集2019/10/28 05:43

##前提・実現したいこと
タップするとメッセージを送信する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

都合上、アップデートができません。
ご助力いただけますと幸いです。

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fuzzball

2019/10/28 05:07 編集

Q1. >>ビルドすると、UIButtonの宣言でThread 1: EXC_BAD_ACCESS で落ちます。 ビルドしただけでそのようなエラーが出て落ちないと思いますが、実行後にエラーが発生したのでしょうか?
fuzzball

2019/10/28 05:07

Q2. 「UIButtonの宣言」というのはどこのことでしょうか? Q3. なぜタイトルに「無限再帰」と書いたのか理由教えて下さい。(何か心当たりがあるのかどうか) Q4. Consoleにエラーメッセージは出力されていないでしょうか?
saku_panda

2019/10/28 05:35

A1. ビルドが通って実行されてからの間違いです。修正します。 A2. var sendBtn: UIButton = UIButton() の部分です。 A3. これといった心当たりはありません。 私が調べた時に、Thread 1: EXC_BAD_ACCESS は無限再帰エラーの場合に出ると見たので無条件でそのまま書いてしまいました。ご指摘を受け調べなおしましたが、正しくは無限ループ時なんですかね。修正します。 A4. コンソールにはViewController の各種プロパティとそのメモリアドレス?が表示されています。 ただしsendBtnは"UIButton 0x0000000000000000"となっております。 また、"warning: could not execute support code to read Objective-C class data in the process. This may reduce the quality of type information available."が出ています。
guest

回答1

0

ベストアンサー

swift

1//ViewController 2let Peripheral: PeripheralService = PeripheralService()

swift

1//PeripheralService 2let VC: ViewController = ViewController()

お互いがお互いのインスタンスを生成しているため無限ループに陥っています。
PeripheralServiceのVCは不要なら削除して下さい。

投稿2019/10/28 05:51

fuzzball

総合スコア16733

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

saku_panda

2019/10/28 05:57

とてもお早い回答ありがとうございます。 該当箇所を修正したところ、無事起動しました。 今後気をつけます。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問