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

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

ただいまの
回答率

90.47%

  • Swift

    8942questions

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

  • MacOS(OSX)

    2393questions

    MacOSとは、Appleの開発していたGUI(グラフィカルユーザーインターフェース)を採用したオペレーションシステム(OS)です。Macintoshと共に、市場に出てGUIの普及に大きく貢献しました。

  • Cocoa

    81questions

    CocoaはMac OS X用のアプリケーションを構築する為の主要なフレームワークのひとつです。

cocoaで、ディレクトリ内のファイルを1つずつ処理し、ラベルに現在処理中のファイル名を表示したい

解決済

回答 1

投稿

  • 評価
  • クリップ 1
  • VIEW 200

kweet

score 1

こんにちは
Swift初心者です。(長年、Microsoft Visual Basic5.0愛用してました)
選択したディレクトリ内の複数のファイルをそれぞれバイナリデータとして
1バイトずつ暗号化するcocoaアプリを作り、
暗号化の動作自体は問題なく出来てるのですが(なのでソフトしては使えてる)
途中経過として、今処理中のファイル名をラベルに表示したいのですが、
ラベルが更新されません。

調べたら、UIの更新はそもそもloop中はできないそうですが、
そうなるとディレクトリ内の複数のファイル名を順次どうやって表示するのか?
が、分からないでいます。
どなたか下記のコードでファイルの暗号化が1つ終わるごとに、
ラベルを更新できる方法を教えていただけないでしょうか?

まだ不慣れなので、実際のコードも全てボタンアクション内に記述してます

 該当のソースコード

@IBAction func Start(_ sender: Any) {

   let manager = FileManager()
   let list = try manager.contentsOfDirectory(atPath: Path)

       //ディレクトリ内のファイルを1つずつ処理
       for i in stride(from: 0, to: list.count, by: 1) {
           //入力ファイルの内容をバイナリデータとして読み込み
           do {
           let binaryData = try Data(contentsOf: URL, options: [])
           } catch {
             print("エラー")
           }
           //出力ファイルをオープン
           let stream = OutputStream(url: OutputFileURL, append: false)
           //今暗号化しているファイル名をラベルに表示・・・したい
           Label.stringValue = list[i]

           //バイナリデータを1バイトずつ暗号化
           for i2 in stride(from: 0, to: filesize, by: 1) {
               //ここに処理内容を記述してます。長いので割愛。
               }
           //終わったら開いたファイルへ出力
           stream!.write(outputDat, maxLength: outputData.count)
        }
 }

 試したこと

自分なりにこうすれば良いのかとラベル表示のコード部分を下記の様にやってみましたが
全然違う様でした。

DispatchQueue.main.async {
            Label.stringValue = list[i]
                    }

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

Xcode 10 swift 4

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

+1

正しく動いているのだとは思いますが、おそらく処理の間レインボーカーソルになっていると思います。
これはRunLoopが止まってしまっているからで、RunLoopが止まっている間は、イベント処理や描画が行われません。

RunLoopは大雑把に言うと

開始

イベント処理(システムイベントや、ユーザーアクションなど)

描画処理

Timer処理

その他の処理

初めに戻る

ということをしています。(実際の処理の順番は非公開のため不明)

@IBAction func Start(_ sender: Any)ということはおそらくボタンクリックなどでこの関数が呼ばれるように設定していると思いますので、この関数はRunLoopのタスクでいうイベント処理部分で実行されています。
見てわかるとおり、イベント処理が終わらない限り、描画処理は行われません。
これを何とかしなければなりません。


その1(僕はあまりお勧めしません)
RunLoopの中でRunLoopを回す

  Label.stringValue = list[i]

  RunLoop.current.run(until: Date())  // 追加

RunLoopの中でRunLoopを回すというと奇異に感じますが2重のforループのようにするということです。
また、終了時刻に現在の時刻を与えることで、ループが1度回っただけで処理が返ってきます。


その2
時間のかかる処理を別スレッドで行う

/// 暗号化
private func encrypt(_ completionHandler: () -> Void) {
  //
  // func Start(_ sender: Any)の中身だったもの
  //
  // ただしここ書き換え
  // Label.stringValue = list[i]
 // 描画にかかわりのある処理はメインスレッド上で実行しなければならない
  DispatchQueue.main.async { Label.stringValue = list[i] }

  //
  //

  // 追加
  // 暗号化処理が終わったら与えられた関数を実行する
  completionHandler()
}


@IBAction func Start(_ sender: Any) {

  // ボタンのクリックなどでアクションが呼ばれると仮定して
  // 処理中はそれを無効化する
  let control = sender as? NSControl
  control?.isEnable = false

  // 別スレッドで暗号化
  DispatchQueue.global().async {
    encrypt() {

      // 暗号化処理が終わったらこのクロージャが呼ばれる

      // 描画にかかわりのある処理はメインスレッド上で実行しなければならない
      DispatchQueue.main.async {
        // 有効に戻す
        control?.isEnable = true
      }
    }
  }
}

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/11/09 23:46

    非常に分かり易いご回答ありがとうございます!!
    その2を試したら一発で出来ました!!
    ファイル名が順次表示される様は壮観でした^^
    何日もググってたのにこんなに早く解決できるとは嬉しい限りです。
    今回の回答を元に他のコードについても色々改変すれば、さらにスキルアップ出来そうです。
    本当にありがとうございました!

    キャンセル

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

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

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

  • Swift

    8942questions

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

  • MacOS(OSX)

    2393questions

    MacOSとは、Appleの開発していたGUI(グラフィカルユーザーインターフェース)を採用したオペレーションシステム(OS)です。Macintoshと共に、市場に出てGUIの普及に大きく貢献しました。

  • Cocoa

    81questions

    CocoaはMac OS X用のアプリケーションを構築する為の主要なフレームワークのひとつです。