swift 协议代理nil

2019-02-13 18:15:28 Future_One 阅读数 998

前言

    代理是一种设计模式。它允许类(或者Swift中结构体)将自身负责的功能委托给其他的类型的实例示例。

应用

接下来举一个列子

  1. 代理实现的VC
import UIKit

class ViewController: UIViewController,SecondVCDelegate{
   
    @IBOutlet weak var showNameL: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    @IBAction func nextBtnAction(_ sender: Any) {
        let nextVC : SecondVC = UIStoryboard.init(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "nextVC") as! SecondVC
        nextVC.delegate = self
        self.present(nextVC, animated: true, completion: nil)
        
    }
    
    @objc func saveName(_ nameStr: String) {
        self.showNameL.text = "请输入姓名:\(nameStr)"
        print("---------------------\(nameStr)")
    }
    
    
}

在这里插入图片描述

  1. SecondVC
import UIKit

class SecondVC: UIViewController {
    weak var delegate : SecondVCDelegate?
    @IBOutlet weak var inputName: UITextField!
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    @IBAction func btnSureAction(_ sender: Any) {
        if self.delegate != nil && (self.delegate?.responds(to: Selector.init(("saveName:"))))!{
            self.delegate?.saveName(inputName.text!)
        }
        
        self.dismiss(animated: true, completion: nil)
    }
    
}

protocol SecondVCDelegate : NSObjectProtocol {
    func saveName(_ nameStr : String)
}

在这里插入图片描述

Swift中Delegate细节注意

一、需要用weak修饰代理(weak var SecondVCDelegate?)

weak修饰声明的属性避免循环引用的问题(类似OC中的weak修饰)

二、代理方法的判断(respondsToSelector()在Swift中的使用)

原因是在OC的代码中, 用respondsToSelector()方法来判断是否实现了方法。
而在Swift中需要使用 (self.delegate?.responds(to: Selector.init((“saveName:”))))! 的方式判断是否实现这个方法。

在在代理执行的类中需要使用@objc 修饰saveName方法。(@objc 关键字来达到,Objective-C中使用#selector中使用)

Swift Delegate详解的: Demo地址
https://github.com/FlameDream/Delegate_Test

2017-08-21 16:28:28 Jason_chen13 阅读数 5090

ProtocolClass2.swift

//定义协议
@objc protocol ProClassDelegate {
    //代理函数
    func test2() //必需实现
    @objc optional func test(name:String,type:Int)  //可选
}

class ProtocolClass2: NSObject {
    
    //声明类的代理属性变量名
    var delegate:ProClassDelegate?

    func backDelegate() {
        
        //代理回调
        delegate?.test2()
        delegate?.test?(name: "back", type: 0)
    }
    

    

}


ViewController.swift
import UIKit


class ViewController: UIViewController,ProClassDelegate { //遵循代理
    
    
    
    override func viewDidLoad() {
        super.viewDidLoad()

        var proClass:ProtocolClass2? = ProtocolClass2()
        proClass?.delegate = self 
        proClass?.backDelegate()
        
    }

    
    func test2() {
        print("无参数代理回调")
    }
    
    
    func test(name: String, type: Int) {
        print("有参数代理回调")
        print("name = \(name)\n type = \(type)")
    }

}



以下译文

协议扩展

协议可以通过扩展来为遵循协议的类型提供属性、方法以及下标的实现。通过这种方式,你可以基于协议本身来实现这些功能,而无需在每个遵循协议的类型中都重复同样的实现,也无需使用全局函数。

例如,可以扩展 RandomNumberGenerator 协议来提供 randomBool() 方法。该方法使用协议中定义的 random() 方法来返回一个随机的 Bool 值:

extension RandomNumberGenerator {
    func randomBool() -> Bool {
        return random() > 0.5
    }
}

检查协议一致性

你可以使用类型转换中描述的 is 和 as 操作符来检查协议一致性,即是否符合某协议,并且可以转换到指定的协议类型。检查和转换到某个协议类型在语法上和类型的检查和转换完全相同:

  • is 用来检查实例是否符合某个协议,若符合则返回 true,否则返回 false
  • as? 返回一个可选值,当实例符合某个协议时,返回类型为协议类型的可选值,否则返回 nil
  • as! 将实例强制向下转换到某个协议类型,如果强转失败,会引发运行时错误。

为协议扩展添加限制条件

在扩展协议的时候,可以指定一些限制条件,只有遵循协议的类型满足这些限制条件时,才能获得协议扩展提供的默认实现。这些限制条件写在协议名之后,使用 where 子句来描述,正如Where子句中所描述的。

例如,你可以扩展 CollectionType 协议,但是只适用于集合中的元素遵循了 TextRepresentable 协议的情况:

extension Collection where Iterator.Element: TextRepresentable {
    var textualDescription: String {
        let itemsAsText = self.map { $0.textualDescription }
        return "[" + itemsAsText.joined(separator: ", ") + "]"
    }
}


2015-06-23 14:06:11 Riven_wn 阅读数 10833

2017.03.16更新简洁版

protocol ChildDelegate: class {
    func childDidSomething()
}
class Child {
    weak var delegate: ChildDelegate?
}
delegate?.childDidSomething()

-----------莫名其妙的分割线---------


具体的代码,详见Demo:链接: http://download.csdn.net/download/riven_wn/9401970


rootViewController

class ViewController: UIViewController,GetMessageDelegate
{
    var _button:UIButton?
    var _label:UILabel?

    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        self.title = "RootViewController"
        //创建label 用来接收传过来的值
        _label = UILabel(frame: CGRect(x: 50, y: 100, width: 220, height: 44))
        _label?.text = "get message from next page"
        
        _label?.textAlignment = NSTextAlignment.Center
        _label?.backgroundColor = UIColor.cyanColor()
        self.view.addSubview(_label!)
        
        //创建button 点击跳转到下一个界面
        _button = UIButton(frame:CGRect(x:60,y:200,width:200,height:44))
        _button?.setTitle("go to next page", forState: UIControlState.Normal)
        _button?.setTitleColor(UIColor.yellowColor(), forState: UIControlState.Normal)
        _button?.backgroundColor = UIColor.blueColor()
        _button?.addTarget(self, action: "nextPage", forControlEvents: UIControlEvents.TouchUpInside)
        self.view.addSubview(_button!)
    }

    //push
    func nextPage()
    {
        let nextVC = NextViewController()
        //指定代理
        nextVC.delegate = self
        self.navigationController!.pushViewController(nextVC,animated:true)
    }
    //接收传过来的值
    func getMessage(controller:NextViewController,string:String)
    {
        _label?.text = string
        if(string == "")
        {
            _label?.text = "null"
        }
 
    }


}

secondViewController

//创建协议
protocol GetMessageDelegate:NSObjectProtocol
{
    //回调方法 传一个String类型的值
    func getMessage(controller:NextViewController,string:String)
}
class NextViewController: UIViewController
{
    var delegate:GetMessageDelegate?
    var _textField:UITextField?
    override func viewDidLoad()
    {
        super.viewDidLoad()
        self.title = "SecondViewController"
        self.view.backgroundColor = UIColor.whiteColor()
        
        //创建textField 用来输入要传的值
        _textField = UITextField(frame: CGRect(x: 60, y: 100, width: 200, height: 44))
        _textField?.borderStyle = UITextBorderStyle.RoundedRect
        _textField?.placeholder = "input sth to send back"
        self.view.addSubview(_textField!)

        //创建返回的button
        var myButton = UIButton(frame:CGRect(x:60,y:200,width:200,height:44))
        myButton.center = CGPointMake(160,200)
        myButton.setTitle("send message back",forState:.Normal)
        myButton.addTarget(self,action:"goBack",forControlEvents:.TouchUpInside)
        myButton.backgroundColor = UIColor.blueColor()
        self.view.addSubview(myButton)
    }

    func goBack()
    {
        //调用代理方法
        if((delegate) != nil)
        {
            delegate?.getMessage(self,string:_textField!.text)
            self.navigationController?.popToRootViewControllerAnimated(true)
        }
        
    }
}


2018-10-25 10:54:30 wuyanan123456 阅读数 142

文章

Swift代理协议的安全使用

概述

在Swift下,使用代理协议,并且检验代理对象的存在和协议函数是否被实现。

前言

可空链式调用(Optional Chaining)是一种可以请求和调用属性、方法及下标的过程,它的可空性体现于请求或调用的目标当前可能为空(nil)。如果可空的目标有值,那么调用就会成功;如果选择的目标为空(nil),那么这种调用将返回空(nil)。多个连续的调用可以被链接在一起形成一个调用链,如果其中任何一个节点为空(nil)将导致整个链调用失败。

注意: Swift 的可空链式调用和 Objective-C 中的消息为空有些相像,但是 Swift 可以使用在任意类型中,并且能够检查调用是否成功。

空链式(Optional Chaining)的使用之一

在Swift中空链式的有个实用例子,就是编写代理的时候。当触发协议方法的时候,因为OC是消息型语言,所以必须要判断这个实例是否存在并且要判断当前方法是否被实现,不然没有实现的话,Runtime期间,就可能会报错。又因为OC几乎所以的类都是继承基类NSObject,而根类NSObject实现了其协议NSObject的协议方法respondsToSelector:,该方法可以判断某个方法实现的。如下

// 判断添加了代理对象,并且该对象实现了某个协议方法
if (self.delegate && [self.delegate respondsToSelector:@selector(protocalMethod)]) {
    [self.delegate protocalMethod];
}

而在Swift语言中,并未要求继承某个根类。并且也未提供某个方法去不判断某个方法是否被实现。其实因为Swift的语言一个特性–可选性,就很好解决这些问题了。正如上方的描述,如果其中任何一个节点为空(nil)将导致整个链调用失败。如下

self.delegate?.SwiftProtocolTest?()

当判读使用有代理对象的时候,只需在属性delegate添加"?“就行,而需要判断某个函数是否实现只需在函数名和()之间添加”?"就行。

提示:本文delegate在Swift和OC的对比可以查看 github 代码

友情提示:

2017-01-12 19:25:14 Mazy_ma 阅读数 2329

虽然 Swift 中闭包的功能非常强大, 但代理也不可替代, 各有各的好处, 合适的, 才是最好的!


个人总结, 代理的使用需要五个步骤:

  • 1.设置代理协议,定义可选或者必选方法
  • 2 声明一个delegate属性
  • 3 过滤代理,实现代理方法
  • 4 接收代理
  • 5 实现代理方法

具体实现步骤如下:

设置代理控制器需要做的事

1 设置代理协议,定义可选或者必选方法

@objc protocol XMTestDelegate {

   /// 定义可选方法
   @objc optional func sendDataToBack(str: String)

   /// 定义必选方法
   func sendData2Back(str: String)

}

2 声明一个delegate属性,用可选项代替”weak”,防止循环引用

    var delegate: XMTestDelegate?

3 过滤代理,实现代理方法

   if delegate != nil {

       delegate?.sendData2Back(str: "goodBye 2016")
       delegate?.sendDataToBack!(str: "hello 2017")

    }

接收代理控制器需要做的事

4 接收代理

     testVC.delegate = self

5 实现代理方法


extension XMTestViewController: XMTestDelegate {

    func sendDataToBack(str: String) {
        print(str) // hello 2017
    }

    func sendData2Back(str: String) {
        print(str) // goodBye 2016
    }

}

Swift 协议(十八)

阅读数 5641

swift 协议

阅读数 111