【问题标题】:Call method in another View Controller, but not segue to it?在另一个视图控制器中调用方法,但不继续它?
【发布时间】:2016-08-28 23:57:57
【问题描述】:

我有一个选项卡式应用程序。

标签 A:下载按钮。

选项卡 B:表格视图

我想要做的是当点击A中的按钮时,我想调用B中的下载功能。

现在我点击按钮后有几个场景:

  • 留在阿州
  • 如果我现在点击 B,我可以看到下载过程,或者如果完成,我可以在那里看到文件。

    +----------------+         +-----------------+
    |                |         |downloaded files |
    |                |         +-----------------+
    | +------------+ |         |                 |
    | | download   | |         +-----------------+
    | +------------+ |         |                 |
    |                |         |                 |
    +-------+--------+         +--------+--------+
    |now in |   B    |         |  A     | now in |
    |  A    |        |         |        |    B   |
    +-------+--------+         +--------+--------+
    

现在我在A中编写下载函数,并将所有文件保存在一个目录中,每当我点击选项卡B时,viewWillAppear函数将从目录中加载下载的文件,但问题是我想显示文件较大时的下载过程。

感谢任何建议和代码 sn-p。

【问题讨论】:

  • 您需要第三类 (C) 来管理您的下载。 A 和 B 都引用 this 的单个实例,或者通过使用单例,或者(最好)通过标签栏控制器提供对 A 和 B 的对象的引用。然后,A 可以调用 C 上的方法来启动下载B 可以向 C 查询下载状态。

标签: ios swift uiviewcontroller tabbarcontroller


【解决方案1】:

使用 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 调用,它会变得混乱。

最佳实践是创建一个包含 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
}

我希望这对某人有帮助

【讨论】:

  • @Mr.UB 我没有使用过 AFNetworking,我几乎总是推出自己的 URL 会话。当我不直接使用 URL 会话时,我通常使用 Alamofire。您可以将 Connect 代码替换为 Alamo 或 AF,它应该可以正常工作。
  • 哦,错了,我的意思是Alamofire。能举个小例子吗?
猜你喜欢
  • 2012-02-03
  • 1970-01-01
  • 1970-01-01
  • 2011-12-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-11
  • 1970-01-01
相关资源
最近更新 更多