Swift调用协议扩展导致崩溃的解决

版权声明:大熊猫猪·侯佩原创或翻译作品.谢绝转载! hopy https://blog.csdn.net/mydo/article/details/85090323

本博向大家介绍Swift对象委托的一种变通方法,但遗憾的是该方法在Swift 4.2中会导致App崩溃,生活还要继续,且看本猫如何解决它喽.

什么是对象委托

简单的说对象委托就是对象A假装对象B,当然A和B的类完全不同.

用过Ruby的童鞋都知道,这很容易完成:

Class Account < ActiveRecord::Base  
   
    delegate :firstname, :to => :user  
    # firstname => user.firstname  
  
    delegate :firstname, :to => :user, :prefix => true  
    # user_firstname => user.firstname  
  
    delegate :firstname, :to => :user, :allow_nil => true, :prefix => true  
    # user_firstname => user.try(:firstname)  
   
    delegate :name, :to => "user.try(:editor)", :prefix => :editor  
    # editor_name => user.editor.name  
  
    delegate :name, :to => "user.try(:editor)", :prefix => :editor, :allow_nil => true  
    # editor_name => user.editor.try(:name)  
   
end 

如上,如果我们调用Account的firstname方法,实际调用的是user的firstname方法:

account.firstname => user.firstname

user对象是什么?他就是account假装的对象.

其实这样理解不完全准确,因为A并不想完全和B一样,只是某些方面一样!

Swift中的对象委托

如果不用非常手段(比如反射),我们只有用老实的方法在Swift中实现对象委托:

protocol HyImageCropPickerDelegate where Self:UIViewController{
    func didSelectCropedImage(_ image:UIImage)
}

class HyImageCropPicker:NSObject{
    var delegate: HyImageCropPickerDelegate!
    
    func display(){
        delegate.present(imagePicker, animated: true, completion: nil) 	//1
    }

虽然上面我特别声明了遵守HyImageCropPickerDelegate对象的类必须是UIViewController,但是注释1那句代码还是编译不过去.

为什么呢?答案在这篇猫博里:

Swift 4.1 协议的类型限定功能

为了调用delegate的present方法我们需要用协议扩展:

extension HyImageCropPickerDelegate{
	func present(_ viewControllerToPresent:UIViewController, animated: Bool, completion: (()->Void)?=nil){
        self.present(viewControllerToPresent, animated: animated, completion: completion)
    }
}

是的,在协议扩展里,编译器终于认为self也是一个UIViewController对象了…

这样实现对象委托应该说不是很漂亮,比Ruby丑很多…

在这里插入图片描述

不过至少我们完成了目的,right???

NO,YOU ARE WRONG !!!

别高兴的太早

编译没问题,不代表没问题,运行你会发现App还是会崩的…

从出错的描述来看(BAD_ACCESS),说实话我也不知道崩溃的原因是神马?这还得深入Swift的官文或逆向的汇编代码中去,但这篇博文里显然不想这么做.

PS:猜测一下,这是Swift协议扩展的限制造成的.

我们只想简单的解决这个问题!!!

变通之道

思路是让delegate同时显式满足两个条件:

  1. 它遵守HyImageCropPickerDelegate协议
  2. 同时它是一个UIViewController对象

可以做到么?

必须的!!!而且还很简单,我们首先将HyImageCropPickerDelegate声明中where子句删除,同时将HyImageCropPickerDelegate协议扩展统统删除.

接下来,将delegate定义代码改为如下即可:

var delegate:(UIViewController & HyImageCropPickerDelegate)

好了,生活又可以继续,我们又可以愉快的玩耍了…

在这里插入图片描述

没有更多推荐了,返回首页