【问题标题】:Function Overriding in iOSiOS 中的函数覆盖
【发布时间】:2017-02-03 12:52:08
【问题描述】:

我已经创建了BaseClassviewController,我所有的控制器都是从这个控制器派生的。我正在执行以下步骤:

  1. BaseClassViewController中设置自定义委托。
  2. 实现BaseClassViewController中协议的所有功能。
  3. 然后我推送从BaseClassViewController派生的HomeController
  4. 我再次推 DetailController 也源自 BaseClassViewController

现在,当调用委托函数时,我应该在 DetailController 中获得控制权,但我在 HomeController 中获得控制权。

所以我的问题是为什么它不在导航时调用顶部控制器,即DetailController,是否可以在两个控制器中调用委托函数?

P.S 我正在覆盖所有子控制器中的委托函数。

编辑:在阅读了答案和 cmets 之后,我想我还不是很清楚,所以添加以下代码 sn-p。

在助手类中:

@objc protocol SampleDelegate: class
{
    @objc optional func shouldCallDelegateMethod()
}

class SampleHelper: NSObject
{
    var sampleDelegate:SampleDelegate!
    static var sharedInstance = SampleHelper()

   //It is triggered 
   func triggerDelegateMethod()
   {
     sampleDelegate!.shouldCallDelegateMethod()
   }

   func apiCall()
   {
      let urlString = URL(string: "https://google.com")
      if let url = urlString {
      let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
      if error != nil {
         print(error)
      } else {
      if let usableData = data {
           self. triggerDelegateMethod()
           }
         }
       }
       task.resume()
     }
   }
}

在基类中

class BaseClassViewController: UIViewController,SampleDelegate{

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func viewWillAppear(_ animated: Bool)
    {
        super.viewWillAppear(true)
       SampleHelper.sharedInstance.delegate = self;
    }

    func shouldCallDelegateMethod()
    {
        //Override
    }


}

在 HomeController 中,即要推送的第一个控制器

class HomeViewController: BaseClassViewController{

        override func shouldCallDelegateMethod()
        {
            //
        }
}

在 DetailController 中,即第二个控制器从 HomeController 推到 HomeController 之后。

class DetailViewController: BaseClassViewController{
        override func viewDidLoad()
        {
           super.viewDidLoad()
           SampleHelper.sharedInstance.apiCall()
        }
        override func shouldCallDelegateMethod()
        {
            //
        }
}

现在我的问题是,当从助手类触发委托时,它在HomeViewController 中调用shouldCallDelegateMethod,但在DetailViewController 中没有。但DetailViewController 位于导航数组的顶部。

还有没有可能我可以只用委托在两个控制器中触发相同的功能?

【问题讨论】:

  • 请分享您声明和覆盖委托的代码 sn-p。
  • 它相当大的代码库以建设性的方式在这里展示。但我认为我已经在概念上以体面的方式解释了它..
  • @Aamir 如果您需要任何具体内容,请告诉我,我可以解释。
  • 很不清楚你在这里的意思。什么是“自定义委托”? (你的意思是你已经创建了自己的委托协议?)调用这个委托函数的是什么?为什么你认为它在DetailController 中“应该得到控制”(我不确定这意味着什么)?您认为应该将什么称为“导航中的顶级控制器”?这些类如何继承在这里几乎可以肯定是无关紧要的。您可能错误地接线了。目前尚不清楚您所说的“推动”是什么意思。您是使用故事板转场还是直接呈现?为什么它同时被标记为 ObjC 和 Swift?两者都有吗?
  • 将委托与单例一起使用是一种反模式。对单例使用完成回调,否则你会一直遇到问题。

标签: ios objective-c iphone swift


【解决方案1】:

BaseClassviewController 中,您应该有一个delegate 变量/属性。

HomeControllerDetailController 中,如果您希望该类监听委托回调,则需要将delegate 变量/属性设置为self

【讨论】:

    【解决方案2】:

    基本问题是您使用的是单例委托。

    viewWillAppear 中设置委托也不是一个好的解决方案。简而言之,当视图控制器被显示和隐藏时,你的单例上的委托将一直改变。

    不要将委托与单例一起使用。使用完成回调。否则你会一直遇到问题。

    func apiCall(onCompletion: (() -> Void)?) {
        let urlString = URL(string: "https://google.com")
        if let url = urlString {
            let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
                if error != nil {
                    print(error)
                } else if let usableData = data {
                    onCompletion?()
                }
            }
    
            task.resume()
         }
    }
    

    称为

    SampleHelper.apiCall {
        // do something
    }
    

    【讨论】:

    • 我同意你的观点,但它仍然没有回答我的问题,为什么它没有在 Home Controller 中详细调用 func。
    • 另外,如果你能详细说明你的观点,那将会很有帮助..
    • 但是可以从同一个类中的多个位置调用这个委托。例如 XMPP 的 createGroup 。在这种情况下,我也可以获得 API 响应以通知该组已经创建,并且我可以通过 XMPP 接收消息.. 所以我必须更新控制器来更新他们的 UI..
    • @KrishnaKumar viewDidLoadviewWillAppear 都不是注册任何东西的好地方。你将不得不使用viewDidAppear everywhere。尽管如此,这种架构还是会从根本上被打破。你为什么还要使用sharedInstance?为什么不让每个控制器都创建自己的助手?然后您的代表将正常工作。
    • 因为还有一个名为 Communicator 的层,它与所有帮助程序类交互,而控制器仅与通信器通信。此外,我将委托设置为 Baseviewcontroller,然后覆盖所有子控制器中的委托方法。我明白你的观点,我不应该在视图代表中设置代表..
    【解决方案3】:

    编辑 2

    在您发布代码后,我意识到您已经使用单例类进行委托。

    委托允许一个对象向另一个对象发送消息。

    答案是“否”。您不能使用委托同时在两个控制器中触发相同的功能。

    如果你真的想同时收听两个班级的事件,我建议你使用NSNotificationCenter 而不是委托。

    【讨论】:

    • 写 SampleHelper.sharedInstance.delegate = self;在 homeVC 和 DetailVC 的 viewWillappear 方法中。
    • 然后它超越了子类化的目的,而且我已经覆盖了所有子类中的方法..
    【解决方案4】:

    这不是实现这一目标的正确方法。我认为仅在各自的UIViewController 中设置委托而不是在BaseViewController 上实现该协议然后在子类中覆盖的正确方法。所以你的实现应该是这样的。

    在 HomeViewController 中

    class HomeViewController: BaseClassViewController {
    
      override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(true)
        SampleHelper.sharedInstance.delegate = self;
      }
    
      func shouldCallDelegateMethod() {
        // Provide implementation
      }
    
    }
    

    在DetailViewController中

    class DetailViewController: BaseClassViewController {
    
      override func viewWillAppear(_ animated: Bool) {
        super.viewDidLoad()
        SampleHelper.sharedInstance.delegate = self;
      }
    
      func shouldCallDelegateMethod() {
        // Provide implementation
      }
    
    }
    

    使用此实现,您将只有 一对一 通信设计模式,确保正确调用 UIViewController

    【讨论】:

    • 因为我们通过在BaseViewController 中实现协议来设置另一个级别的间接性,我们应该直接在各自的 ViewController 中实现它。
    • 但我需要在不同的控制器中实现它。而且我无法理解为什么它会增加间接级别,因为委托总是分配给 BaseClassViewController 而我们只是覆盖了这些功能..
    • 你想要一对多的委托模式吗?如果是这样,那么您需要使用 NSNotifications。
    • 我有点避免这种情况。但我仍然不清楚为什么在这种情况下只是覆盖函数不起作用。就委托而言,它会被调用..但是重写会产生问题,因为它在一个控制器中工作,但一次不在另一个控制器中工作..
    猜你喜欢
    • 2018-12-21
    • 1970-01-01
    • 2010-10-25
    • 2016-03-18
    • 1970-01-01
    • 2018-06-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多