私のアプリは、アプリのいくつかの異なる場所から私のウェブサイトからファイルをダウンロードする必要があるので、ダウンロードを一度達成し、独自のクラスに入れ、各ViewControllerからその関数を呼び出す関数を書くのが理にかなっているようです。これまでのところ、とてもうまくいっています。ダウンロードが行われており、ダウンロードしたファイルは正しくprint
になります。複数のView Controllerからファイルダウンロード機能を呼び出します。結果をVCに返す方法は?
ダウンロード機能が呼び出されたViewControllerに「成功」または「失敗」メッセージを送信して、VCがそれに応じて反応するようになると、問題が発生します。表示を更新し、ダウンロードダイアログを閉じます、 なんでも。それが起こるようにするには、私は立ち往生しています。私が持っているもの
:
(私のサーバーから別のファイルを要求する以外に今のところ同一である、)ViewControllerTwoとViewControllerThreeのそれぞれは、このようにダウンロード機能を呼び出します。
Downloader.load(url: urlForFileA!, to: localDestinationFileA, callingViewControllerNumber: 2)
ためのコード(現在同期しているが、最終的に非同期になります)ダウンローダ機能は、(独自のDownloader
クラスで)次のようになります。
class func load(url: URL, to localUrl: URL, callingViewControllerNumber: Int) {
let sessionConfig = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfig)
let request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalAndRemoteCacheData)
let task = session.downloadTask(with: request) { (tempLocalUrl, response, error) in
if let tempLocalUrl = tempLocalUrl, error == nil {
// Got a file, might be a 404 page...
if let statusCode = (response as? HTTPURLResponse)?.statusCode {
print("Success downloading: \(statusCode)")
if statusCode == 404 {
// ERROR -- FILE NOT FOUND ON SERVER
returnToCaller(sourceIdent: callingViewControllerNumber, successStatus: .fileNotFound, errorMessage: "File not Found, 404 error")
}
}
do {
try FileManager.default.copyItem(at: tempLocalUrl, to: localUrl)
// SUCCESS!
returnToCaller(sourceIdent: callingViewControllerNumber, successStatus: .success, errorMessage: "")
} catch (let writeError) {
returnToCaller(sourceIdent: callingViewControllerNumber, successStatus: .movingError, errorMessage: "\(writeError)")
}
} else {
returnToCaller(sourceIdent: callingViewControllerNumber, successStatus: .downloadFailed, errorMessage: "Grave Unexplained Failure")
}
}
task.resume()
}
この部分は動作します。
returnToCaller
機能を呼び出すのViewControllerに戻って何かを送信するために(大丈夫、非常に、非常に醜い)確かに醜い方法です:
class func returnToCaller(sourceIdent : Int, successStatus : downloadSuccessStatusEnum, errorMessage : String) {
switch sourceIdent {
case 2:
ViewControllerTwo().returnFromDownload(successStatus: successStatus, errorMessage: errorMessage)
case 3:
ViewControllerThree().returnFromDownload(successStatus: successStatus, errorMessage: errorMessage)
default:
fatalError("Unknown sourceIdent of \(sourceIdent) passed to func returnToCaller")
}
}
問題がでたときにそのreturnFromDownload
機能ということですオリジナルのViewControllerが呼び出され、ロードされているVCの何も認識しません。ラベルの背景色を変更して、ラベルがnil
であるランタイムエラーを取得します。ラベルは存在しますが、ViewControllerコードへのこの呼び出しは、実行中のインスタンス化されたVC自体から独立して行われます。 (おそらく間違ったボキャブラリーがあります。謝罪します。)コードは実行され、print
でも可能ですが、View自体の何かと対話するときにエラーが出る可能性があります。
私はこのことをよりうまく使うほど、私はここで正しい方向に向いていると自信がなくなり、Swiftでの私の限られた経験は、何が起こって、ダウンロード機能がすべての作業を「ここで」実行し、呼び出し元のVCに成功/失敗のメッセージを返して、VCがそれを処理できるようにします。
This question同様の質問をしているようです。そこにある1つの答えは、VCの内部で起こったことの結果を使って、提示されたVC内でコードを取得する方法の根本的な問題(自分の場合はマネージャの承認、私のダウンロード) 。
私のコードを書き直すように求めるのではなく(クイックフィックスでない限り)、正しい方向を指すようにする必要があります。どうもありがとう!
私がこれを正しく読んでいれば、その日に戻って欲しいのは、「疎結合」コードと呼ばれていました。プレスイフトの頃には、別の名前がKVCコーディングである可能性があります。基本的には、何かを非同期的にダウンロードしようとしています*、それを呼び出したVCに結果を返します。少なくとも2つの方法が考えられます。 (1)恐らく最も正しい方法は、デフォルトのNSNotificationCenter(http://stackoverflow.com/questions/24049020/nsnotificationcenter-addobserver-in-swift)にオブザーバーを追加することです。 (2)別の方法 - それほどエレガントではありませんが、仕事を終わらせるかもしれません - UIButtonのsendActionメソッドを使うことです。 – dfd