在另一个 View Controller 中调用方法,但不继续调用它?
Call method in another View Controller, but not segue to it?
我有一个标签式应用程序。
选项卡 A:下载按钮。
选项卡 B:表格视图
我想做的是点击A中的按钮时,调用B中的下载函数
现在点击按钮后有几种情况:
- 留在A
如果我现在点击B,我可以看到下载过程,或者如果完成,我可以在那里看到文件。
+----------------+ +-----------------+
| | |downloaded files |
| | +-----------------+
| +------------+ | | |
| | download | | +-----------------+
| +------------+ | | |
| | | |
+-------+--------+ +--------+--------+
|now in | B | | A | now in |
| A | | | | B |
+-------+--------+ +--------+--------+
现在我把下载函数写在A里,把所有文件都保存在一个目录下,每当我点击B标签时,viewWillAppear
函数会从目录中加载下载的文件,但问题是如果文件很大,我想显示下载过程。
欢迎任何建议和代码片段。
Using Swift 3
在我提供解决方案之前,我会向您指出@Paulw11 的评论,他是 100% 正确的。正确的约定是将您的连接逻辑拉出您的视图控制器。您应该在视图控制器中拥有的唯一代码是显示视图所需的代码。连接到服务器并管理结果与在视图中实际呈现结果数据无关。
如果您真的觉得有必要直接从另一个视图调用函数,您不应该通过创建视图控制器的新实例来做到这一点。相反,您应该像这样获取现有实例:
let app = UIApplication.shared.delegate! as! AppDelegate
if let viewControllers = app.window?.rootViewController?.childViewControllers {
viewControllers.forEach { vc in
if let view = vc as? AnotherViewController {
view.downloadIt()
}
}
}
就我个人而言,无论哪种方式,我都建议将此逻辑从您的视图控制器中提取出来。如果您试图保持最小化,或者如果这是您进行的唯一 Web 服务调用,您可以简单地执行如下操作:
添加一个新的 Swift 文件,其中包含协议和该协议的扩展名:
protocol Downloadable : class { }
extension Downloadable {
func downloadStuff() -> String {
// Add your download logic here
return "downloading"
}
}
然后,在您希望能够使用此下载功能的任何视图中,只需将协议添加到您的视图控制器,如下所示:
class ViewController: UIViewController, Downloadable {}
然后你可以像这样很容易地得到你下载的数据:
@IBAction func handleDownloadTapped(_ sender: UIButton) {
let result = downloadStuff()
print(result)
}
同样,您不应该养成这样做的习惯,因为如果您处理几个不同的 api 调用,它会变得混乱。
最佳做法是创建一个 class 包含您的 Web 服务内容,我个人喜欢 objc.io 方法。您可以在此处找到教程。
https://talk.objc.io/episodes/S01E01-networking
基本上您将创建这样的服务
public typealias JSONDict = [String: AnyObject]
struct Resource<A> {
let url: URL
let parse: (NSData) -> A?
}
let url = URL(string: "https://url")!
let myResource = Resource<[JSONDict]>(url: url) { data in
let json = try? JSONSerialization.jsonObject(with: data as Data, options: [])
return json as? [JSONDict]
}
final class Connect {
class func load<A>(resource: Resource<A>, completion: @escaping (A?) -> Void) {
URLSession.shared.dataTask(with: resource.url) { (data, _, _ ) in
if let data = data {
completion(resource.parse(data as NSData))
} else {
completion(nil)
}
}.resume()
}
}
你可以在任何需要的地方调用它:
Connect.load(resource: myResource) { result in
// do stuff with result
}
我希望这对某人有所帮助
我有一个标签式应用程序。
选项卡 A:下载按钮。
选项卡 B:表格视图
我想做的是点击A中的按钮时,调用B中的下载函数
现在点击按钮后有几种情况:
- 留在A
如果我现在点击B,我可以看到下载过程,或者如果完成,我可以在那里看到文件。
+----------------+ +-----------------+ | | |downloaded files | | | +-----------------+ | +------------+ | | | | | download | | +-----------------+ | +------------+ | | | | | | | +-------+--------+ +--------+--------+ |now in | B | | A | now in | | A | | | | B | +-------+--------+ +--------+--------+
现在我把下载函数写在A里,把所有文件都保存在一个目录下,每当我点击B标签时,viewWillAppear
函数会从目录中加载下载的文件,但问题是如果文件很大,我想显示下载过程。
欢迎任何建议和代码片段。
Using Swift 3
在我提供解决方案之前,我会向您指出@Paulw11 的评论,他是 100% 正确的。正确的约定是将您的连接逻辑拉出您的视图控制器。您应该在视图控制器中拥有的唯一代码是显示视图所需的代码。连接到服务器并管理结果与在视图中实际呈现结果数据无关。
如果您真的觉得有必要直接从另一个视图调用函数,您不应该通过创建视图控制器的新实例来做到这一点。相反,您应该像这样获取现有实例:
let app = UIApplication.shared.delegate! as! AppDelegate
if let viewControllers = app.window?.rootViewController?.childViewControllers {
viewControllers.forEach { vc in
if let view = vc as? AnotherViewController {
view.downloadIt()
}
}
}
就我个人而言,无论哪种方式,我都建议将此逻辑从您的视图控制器中提取出来。如果您试图保持最小化,或者如果这是您进行的唯一 Web 服务调用,您可以简单地执行如下操作:
添加一个新的 Swift 文件,其中包含协议和该协议的扩展名:
protocol Downloadable : class { }
extension Downloadable {
func downloadStuff() -> String {
// Add your download logic here
return "downloading"
}
}
然后,在您希望能够使用此下载功能的任何视图中,只需将协议添加到您的视图控制器,如下所示:
class ViewController: UIViewController, Downloadable {}
然后你可以像这样很容易地得到你下载的数据:
@IBAction func handleDownloadTapped(_ sender: UIButton) {
let result = downloadStuff()
print(result)
}
同样,您不应该养成这样做的习惯,因为如果您处理几个不同的 api 调用,它会变得混乱。
最佳做法是创建一个 class 包含您的 Web 服务内容,我个人喜欢 objc.io 方法。您可以在此处找到教程。
https://talk.objc.io/episodes/S01E01-networking
基本上您将创建这样的服务
public typealias JSONDict = [String: AnyObject]
struct Resource<A> {
let url: URL
let parse: (NSData) -> A?
}
let url = URL(string: "https://url")!
let myResource = Resource<[JSONDict]>(url: url) { data in
let json = try? JSONSerialization.jsonObject(with: data as Data, options: [])
return json as? [JSONDict]
}
final class Connect {
class func load<A>(resource: Resource<A>, completion: @escaping (A?) -> Void) {
URLSession.shared.dataTask(with: resource.url) { (data, _, _ ) in
if let data = data {
completion(resource.parse(data as NSData))
} else {
completion(nil)
}
}.resume()
}
}
你可以在任何需要的地方调用它:
Connect.load(resource: myResource) { result in
// do stuff with result
}
我希望这对某人有所帮助