如何获取对已经实例化的 ViewController 的引用?

Posted

技术标签:

【中文标题】如何获取对已经实例化的 ViewController 的引用?【英文标题】:How to get reference to already instantiated ViewController? 【发布时间】:2015-11-14 12:43:28 【问题描述】:

这里是新手。我试图让我的简单核心位置应用程序在通过locationManager 获取坐标后自动检索数据。 我已经实现了单独的类,不让我的主视图控制器负责太多的任务,这里看起来像这样:

import Foundation
import CoreLocation

class CoreLocationController : NSObject, CLLocationManagerDelegate 

var locationManager = CLLocationManager()

var lastCoordinates: (lat: Double, lon: Double)?

override init()   
    super.init()
    self.locationManager.delegate = self
    self.locationManager.requestWhenInUseAuthorization()
    self.locationManager.distanceFilter  = 3000
    self.locationManager.desiredAccuracy = kCLLocationAccuracyKilometer



func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) 

    let location = locations.last! as CLLocation

    self.lastCoordinates = (location.coordinate.latitude, location.coordinate.longitude)
    print("didUpdateLocations:  \(location.coordinate.latitude), \(location.coordinate.longitude)")



func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) 
    print("didChangeAuthorizationStatus")

    switch status 
    case .NotDetermined:
        print(".NotDetermined")
        break

    case .AuthorizedWhenInUse:
        print(".AuthorizedWhenInUse")
        self.locationManager.startUpdatingLocation()
        break

    case .Denied:
        print(".Denied")
        break

    default:
        print("Unhandled authorization status")
        break

    


func locationManager(manager: CLLocationManager, didFailWithError error: NSError) 
   

当然我已经在 AppDelegate.swift 中初始化了

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate 

var window: UIWindow?

var coreLocationController: CoreLocationController?

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool 

    self.coreLocationController = CoreLocationController()
    return true

现在我的主要ViewController 在单击按钮后正在执行retrieveWeatherForecast,并将appDelegate 传递给它以获取对CoreLocationController.lastCoordinates 属性的引用。我得出的结论是,为了在启动后立即获取坐标后执行retrieveWeatherForecast,最好的方法是在locationManager func(带有didUpdateLocations 参数的那个)中运行此方法。为了做到这一点,我需要参考 ViewController 运行实例来执行类似的操作:

runningViewControlerinstance.retrieveWeatherForecast(runningViewControlerinstance.appDel)

ViewController代码:

import UIKit

class ViewController: UIViewController 

@IBOutlet weak var currentTemperatureLabel: UILabel?
@IBOutlet weak var currentHumidityLabel: UILabel?
@IBOutlet weak var currentPrecipitationLabel: UILabel?
@IBOutlet weak var currentWeatherIcon: UIImageView?
@IBOutlet weak var currentWeatherSummary: UILabel?
@IBOutlet weak var refreshButton: UIButton?
@IBOutlet weak var activityIndicator: UIActivityIndicatorView?

let appDel = UIApplication.sharedApplication().delegate! as! AppDelegate

private var forecastAPIKey: String?

override func viewDidLoad() 
    super.viewDidLoad()

    let path = NSBundle.mainBundle().pathForResource("APIkeys", ofType: "plist")
    let dict = NSDictionary(contentsOfFile: path!)

    self.forecastAPIKey = dict!.objectForKey("forecastAPIKey") as? String



override func didReceiveMemoryWarning() 
    super.didReceiveMemoryWarning()


func retrieveWeatherForecast(appDel: AppDelegate ) 
    let currentCoordinates :(lat: Double, lon: Double) =  (appDel.coreLocationController?.lastCoordinates)!

    let forecastService = ForecastService(APIKey: forecastAPIKey!)
    forecastService.getForecast(currentCoordinates.lat, lon: currentCoordinates.lon) 
        (let currently) in

        if let currentWeather = currently 

            dispatch_async(dispatch_get_main_queue()) 

                if let temperature = currentWeather.temperature 
                    self.currentTemperatureLabel?.text = "\(temperature)º"
                

                if let humidity = currentWeather.humidity 
                    self.currentHumidityLabel?.text = "\(humidity)%"
                

                if let precipitation = currentWeather.precipProbability 
                    self.currentPrecipitationLabel?.text = "\(precipitation)%"
                

                if let icon = currentWeather.icon 
                    self.currentWeatherIcon?.image = icon
                

                if let summary = currentWeather.summary 
                    self.currentWeatherSummary?.text = summary
                

                self.toggleRefreshAnimation(false)

            


        
    


@IBAction func refreshWeather() 
    toggleRefreshAnimation(true)
    retrieveWeatherForecast(appDel)


func toggleRefreshAnimation(on: Bool) 
    refreshButton?.hidden = on
    if on 
        activityIndicator?.startAnimating()
     else 
        activityIndicator?.stopAnimating()
    
 

我将非常感谢您 swift 社区的任何帮助、cmets 和建议,谢谢!

【问题讨论】:

【参考方案1】:

如果您有一个单独的类来处理位置服务(这是一个很好的设计模式)或应用程序委托,那么通知任何活动视图控制器的最佳方式是通过NSNotification

通过viewDidAppear 中的NSNotificationCenter 在视图控制器中注册,并在viewWillDisappear 中将自己移除为观察者。有很多文档可以解释细节。

控制器与异步进程的这种松散耦合比保留对 UI 对象的引用要安全得多。

【讨论】:

【参考方案2】:

“当然我已经在 AppDelegate.swift 中初始化了” 为什么?没有理由在那里初始化它,是吗?在您打算使用它的地方初始化它。您的 viewController 需要访问您的 CoreLocationController 才能使用、显示或编辑位置。所以初始化并在那里使用它,你不必将你的视图控制器传递给你的位置管理器。

【讨论】:

这可能会导致多个核心位置控制器。在这里,单例模式显然更可取。 好的。由于它是 swift ,所以在 CoreLocationController 中声明一个静态变量(这也是一个惰性变量)也是可能的。

以上是关于如何获取对已经实例化的 ViewController 的引用?的主要内容,如果未能解决你的问题,请参考以下文章

如何从 QML 中的 GridView 或 ListView 获取实例化的委托组件

从 SceneDelegate 获取 viewController 实例化的错误

在Typescript中,如何在工厂(ish)函数中实例化的类上获取方法的通用返回类型

如何从QML中的GridView或ListView获取实例化的委托组件

如何防止 onItemSelected 在新实例化的 Spinner 上触发?

不可实例化的超类