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

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

ただいまの
回答率

90.48%

  • Swift

    7485questions

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

  • Swift 2

    1334questions

    Swift 2は、Apple社が独自に開発を行っている言語「Swift」のアップグレード版です。iOSやOS X、さらにLinuxにも対応可能です。また、throws-catchベースのエラーハンドリングが追加されています。

multipeerconectivityを使ったアプリの動作が遅い

解決済

回答 1

投稿

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

afuroda

score 25

前提・実現したいこと

swiftのmultipeerconectivityを使ってクイズアプリを作っているのですが、下記のコードでエラーも出ずに動くのですが、実機で試すと動作がものすごく遅く、didChangeStateのところのUIButtonの表示が画面を触らなければ表示されず、触ったところのUIだけ表示されたりしてしまいます。これは何か原因があるのでしょうか?

該当のソースコード

class ViewController: UIViewController,MCSessionDelegate,MCNearbyServiceBrowserDelegate,MCNearbyServiceAdvertiserDelegate{

    //タグ
    let BTN_ADV = 0
    let BTN_BRW = 1

    //各変数
    let service = "p2p"
    var button1 = UIButton()
    var button2 = UIButton()
    var peerID : MCPeerID?
    var session : MCSession?
    var browser : MCNearbyServiceBrowser?
    var advertis : MCNearbyServiceAdvertiser?

    var text = UILabel()
    var button5 = UIButton()
    var button6 = UIButton()
    var button3 = UIButton()
    var button4 = UIButton()
    var answer : String?
    var count = 0




    override func viewDidLoad() {

        //MCPeerIDの設定
        peerID = MCPeerID(displayName: UIDevice.currentDevice().name)

        //MCSessionの設定
        session = MCSession(peer: peerID!)
        session!.delegate = self


        //MCNearbyServiceBrowser,MCNearbyServiceAdvertiserの設定
        self.browser = MCNearbyServiceBrowser(peer: peerID!, serviceType: service)
        self.browser!.delegate = self
        self.advertis = MCNearbyServiceAdvertiser(peer: peerID!, discoveryInfo: nil, serviceType: service)
        self.advertis?.delegate = self

        //button1,button2の設定
        button1.tag = BTN_BRW
        button2.tag = BTN_ADV
        button1.frame = CGRectMake(0, 0, 300, 100)
        button2.frame = CGRectMake(0, 0, 300, 100)
        button1.backgroundColor = UIColor.cyanColor()
        button2.backgroundColor = UIColor.redColor()
        button1.layer.position = CGPoint(x: self.view.frame.width/2, y: self.view.frame.width/1.2)
        button2.layer.position = CGPoint(x: self.view.frame.width/2, y: self.view.frame.width/0.9)
        self.view.addSubview(button1)
        self.view.addSubview(button2)
        button1.setTitle("browse", forState: .Normal)
        button2.setTitle("advertis", forState: .Normal)
        button1.addTarget(self, action: #selector(self.onclick(_:)), forControlEvents: .TouchUpInside)
        button2.addTarget(self, action: #selector(self.onclick(_:)), forControlEvents: .TouchUpInside)

        //クイズ画面のUI設定
        text.frame = CGRectMake(0, 0, 300, 150)
        button5.frame = CGRectMake(0, 0, 300, 100)
        button6.frame = CGRectMake(0, 0, 300, 100)
        button3.frame = CGRectMake(0, 0, 300, 100)
        button4.frame = CGRectMake(0, 0, 300, 100)

        //ボタンの位置を指定する
        text.layer.position = CGPoint(x: self.view.frame.width/2, y: self.view.frame.width/4)
        button5.layer.position = CGPoint(x: self.view.frame.width/2, y: self.view.frame.width/1.2)
        button6.layer.position = CGPoint(x: self.view.frame.width/2, y: self.view.frame.width/0.9)
        button3.layer.position = CGPoint(x: self.view.frame.width/2, y: self.view.frame.width/0.7)
        button4.layer.position = CGPoint(x: self.view.frame.width/2, y: self.view.frame.width/0.6)


        //ボタンにイベントを追加する
        button5.addTarget(self, action: #selector(self.button1push), forControlEvents: .TouchUpInside)
        button6.addTarget(self, action: #selector(self.button2push), forControlEvents: .TouchUpInside)
        button3.addTarget(self, action: #selector(self.button3push), forControlEvents: .TouchUpInside)
        button4.addTarget(self, action: #selector(self.button4push), forControlEvents: .TouchUpInside)




       super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    //ブラウズとアドバタイズの関数
    func onclick(sender: UIButton){
        if sender.tag == BTN_ADV{
            self.advertis!.startAdvertisingPeer()
            _ = UIAlertController(title: "アドバタイズを開始しました", message: "招待しました", preferredStyle: .Alert)
        }
        else if sender.tag == BTN_BRW{
            self.browser!.startBrowsingForPeers()
        }
    }


    //MCNearbyServiceBrowserのメソッド
    func browser(browser: MCNearbyServiceBrowser, foundPeer peerID: MCPeerID, withDiscoveryInfo info: [String : String]?) {
        print("[MCNearbyServiceBrowserDelegate] browser:foundPeer:withDiscoveryInfo:")

        browser.invitePeer(peerID, toSession: self.session!, withContext: nil, timeout: 10)
    }

    func browser(browser: MCNearbyServiceBrowser, lostPeer peerID: MCPeerID) {

    }

    //MCNearbyServiceAdvertiserのメソッド
    func advertiser(advertiser: MCNearbyServiceAdvertiser, didReceiveInvitationFromPeer peerID: MCPeerID, withContext context: NSData?, invitationHandler: (Bool, MCSession) -> Void) {


        let alert = UIAlertController(title: "招待を受けました", message: "from \(peerID.displayName)", preferredStyle: .Alert)
        alert.addAction(UIAlertAction(title: "参加", style: .Default) { action in
            invitationHandler(true, self.session!)
            })
        alert.addAction(UIAlertAction(title: "拒否", style: .Cancel) { action in
            invitationHandler(false, self.session!)
            })
        self.presentViewController(alert, animated: true, completion: nil)
    }


    //MCSessionのメソッド
    func session(session: MCSession, peer peerID: MCPeerID, didChangeState state: MCSessionState) {
        button1.removeFromSuperview()
        button2.removeFromSuperview()
        //ボタンを画面に表示させる
        self.view.addSubview(text)
        self.view.addSubview(button5)
        self.view.addSubview(button6)
        self.view.addSubview(button3)
        self.view.addSubview(button4)
        print("ボタン交換")
        qizu1()


    }
    func session(session: MCSession, didReceiveData data: NSData, fromPeer peerID: MCPeerID) {
        print("receivedData")
        self.view.backgroundColor = UIColor.cyanColor()
        self.qizu1()

    }

    func session(session: MCSession, didReceiveStream stream: NSInputStream, withName streamName: String, fromPeer peerID: MCPeerID) {
        print("didReceiveStream")
    }

    func session(session: MCSession, didStartReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, withProgress progress: NSProgress) {
        print("didStartReceivingResourceWithName")
    }

    func session(session: MCSession, didFinishReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, atURL localURL: NSURL, withError error: NSError?) {
        print("didStartReceivingResourceWithName")
    }




    //各ボタンの不正解の判定
    func button1push(sender: UIButton){

        if answer == "1"{
            self.view.backgroundColor = UIColor.redColor()
           send(button5)
        }
        else {
            self.view.backgroundColor = UIColor.blueColor()
                    }
    }
    func button2push(sender: UIButton){
        if answer == "2"{
            self.view.backgroundColor = UIColor.redColor()
         send(button6)

        }
        else {
            self.view.backgroundColor = UIColor.blueColor()

        }

    }
    func button3push(sender: UIButton){
        if answer == "3"{
            self.view.backgroundColor = UIColor.redColor()
            send(button3)
        }
        else {
            self.view.backgroundColor = UIColor.blueColor()

        }

    }
    func button4push(sender: UIButton){
        if answer == "4"{
            self.view.backgroundColor = UIColor.redColor()
            send(button4)

        }
        else {
            self.view.backgroundColor = UIColor.blueColor()

        }

    }

    //正解だった場合のデータ送信
    func send(sender: UIButton){
        let str = "text"
        let data = (str as NSString).dataUsingEncoding(NSUTF8StringEncoding)
        do{
            try self.session?.sendData(data!, toPeers: (self.session?.connectedPeers)!, withMode: .Reliable)
                print("send data")
            self.count += 1
            self.qizu1()
            if self.count == 5{

            }
        }catch _ as NSError{
            print("sned error")
        }
    }

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

}

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

xcode ver7.3.1 , swift2イタリックテキストを使っています。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

0

まず、didChangeStateの中がメインスレッドかどうか調べます。

//MCSessionのメソッド
func session(session: MCSession, peer peerID: MCPeerID, didChangeState state: MCSessionState) {
    print(NSThread.isMainThread()) //※追加
    :

falseが出力されたらメインスレッドではないということなので、UIに関する処理をメインスレッドで実行するようにします。

dispatch_sync(dispatch_get_main_queue()) {
    button1.removeFromSuperview()
    button2.removeFromSuperview()
    //ボタンを画面に表示させる
    self.view.addSubview(text)
    self.view.addSubview(button5)
    self.view.addSubview(button6)
    self.view.addSubview(button3)
    self.view.addSubview(button4)
    print("ボタン交換")
    qizu1() //※これは入れなくていいかも知れません
}

ちょっと古い記事ですが、
UIKit とスレッドのお約束 / Fenrir Developer's Blog

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/01/06 14:02

    ありがとうございます。解決しました。
    つけていただいた記事についてはUI部品は基本的にメインスレッドで処理するというイメージでよろしいのでしょうか?

    キャンセル

  • 2017/01/06 14:06

    「基本的」ではなく、必ずメインスレッドで実行しないといけません。

    キャンセル

  • 2017/01/06 14:31

    と、勢いで書いてしまいましたが、UIKit全体ということであれば「基本的に」で正しいです。

    https://developer.apple.com/reference/uikit
    このドキュメントの冒頭に、

    >> For the most part, use UIKit classes only from your app’s main thread.
    >> This is particularly true for classes derived from UIResponder
    >> or that involve manipulating your app’s user interface in any way.

    と書いてあります。
    UIResponderを継承していたらダメ = UIViewを継承しているクラスは全部ダメということになります。(「必ず」と書いた理由はこれです)

    キャンセル

  • 2017/01/10 15:59

    ありがとうございます。
    覚えておきます。

    キャンセル

関連した質問

  • 解決済

    Swift2, SpriteKitのSKActionについて質問です

    問題を出題して、違う答えをタップしたら ×と表示させて、その後消える。 と言った動きをしたいのですが、上手くいきません。 最初の一回目は上手くできるのですが、2回目以降が上手く

  • 解決済

    swift Button タップ スワイプ

    現在、タップとスワイプの二つを一つのボタンで行おうとしています。 ボタンをタップしたらUIViewを出して ボタンをスワイプしたらそのボタンが指に沿って移動する・・・

  • 解決済

    Swiftの座標取得ができないです...

    座礁取得をするコード(コピペなのですが) を記述してみたら Cannot call value of non-function type '((UIView?) -> CG

  • 解決済

    swift スワイプ 座標判定 XY

    前提・実現したいこと 毎度毎度すみません・・・ 現在swiftで作っていて、場所Aにオブジェクトをスワイプし オブジェクトが場所Aに少しでも入っていたら、 オブジェクトを消

  • 解決済

    swift AppDeldateについて

    ボタンをクラス1で作り、タップ機能があり クラス2ではスワイプしたらの機能を作っていて スワイプし終わり、ある場所以外は元の位置に戻る・・・ と言うものを作っていて、クラ

  • 解決済

    [Swift]カスタムビューで作成したUIButtonにaddTargetする方法

    現在iOSのアプリケーションを作成しております。 経験がとても浅いため、苦労しております。 何卒皆様のお力をお貸し貰えると助かります。 前提として、ストーリーボードを利用

  • 受付中

    classからUIButtonを作成したい

    viewcontrollerに複数のボタンを作成したいため、classを使って制御をしようと思いこのサイトを参考に作成しましたが、 self.view.addSubview(my

  • 解決済

    CAGradiationLayerの動作が遅い

    はじめまして、質問をご覧頂いてありがとうございます。 現在、iOS8・Xcode7.3、swift2という環境でStoryBoardを利用せずにiOSアプリの開発を行っています。

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

  • Swift

    7485questions

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

  • Swift 2

    1334questions

    Swift 2は、Apple社が独自に開発を行っている言語「Swift」のアップグレード版です。iOSやOS X、さらにLinuxにも対応可能です。また、throws-catchベースのエラーハンドリングが追加されています。