Ios 设置后委托零

Ios 设置后委托零,ios,swift,delegates,Ios,Swift,Delegates,我正在使用delegate方法,但由于一些奇怪的原因,当我想调用delegate方法时,我的delegate变量似乎是nil。我一辈子都搞不清楚我做错了什么 protocol ProfileProtocol { func buttonTapped() } class ProfileView: UIView { var delegate: ProfileProtocol? @IBOutlet weak var button: UIButton! overri

我正在使用delegate方法,但由于一些奇怪的原因,当我想调用delegate方法时,我的delegate变量似乎是nil。我一辈子都搞不清楚我做错了什么

protocol ProfileProtocol {
    func buttonTapped()
}

class ProfileView: UIView {

    var delegate: ProfileProtocol?

    @IBOutlet weak var button: UIButton!

    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setup()
    }

    override func awakeFromNib() {
        configure()
    }

    func setup() {        

        ...
    }


    @IBAction func buttonTapped(_ sender: UIButton) {
        // delegate nil
        delegate?.buttonTapped()
    }

}
ProfileViewController(是,它符合ProfileProtocol):


每当我点击ProfileView中的按钮时,我的ProfileView控制器都应该执行一个序列,但是委托方法甚至没有被调用,因为当我点击按钮时委托为零。我喜欢将自定义视图模块化,并以编程方式进行操作,它避免了使用Xib

您应该将视图的职责和子视图保留给视图本身。最终,接收操作的视图应该负责调用委托的方法。另外,
nextView
是一个返回UIView的闭包:
(()->UIView?
不是UIView,对闭包中的函数的调用不是显式返回。您应该返回视图:
let view=createCardView()return view

ProfileView.swift

import UIKit

protocol ProfileProtocol {
    func buttonTapped()
}

class ProfileView: UIView {

    var delegate: ProfileProtocol?


    lazy var button: UIButton = {
        let button = UIButton()
        button.translatesAutoresizingMaskIntoConstraints = false
        button.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside)
        button.setTitle("Profile Button", for: .normal)
        button.backgroundColor = UIColor.black
        return button
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override func awakeFromNib() {

    }


    @objc func buttonTapped(_ sender: UIButton) {
        // Check for a nil delegate, we dont want to crash if one is not set
        if delegate != nil {
            delegate!.buttonTapped()
        } else {
            print("Please set ProfileView's Delegate")
        }
    }

    func setup() {
        //setup subviews
        self.addSubview(button)

        button.widthAnchor.constraint(equalToConstant: 150).isActive = true
        button.heightAnchor.constraint(equalToConstant: 50).isActive = true
        button.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
        button.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true

    }

}
import UIKit

class ViewController: UIViewController, ProfileProtocol {

    lazy var profileView: ProfileView = {
        let view = ProfileView()
        view.backgroundColor = UIColor.lightGray
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        profileView.delegate = self


        setup()
    }

    func buttonTapped() {
        print("Do Something")
    }


    func setup() {
        self.view.addSubview(profileView)
        profileView.widthAnchor.constraint(equalTo: self.view.widthAnchor).isActive = true
        profileView.heightAnchor.constraint(equalTo: self.view.heightAnchor, multiplier: 0.7).isActive = true
        profileView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
        profileView.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true

    }


    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}
您可以像创建任何其他UIView一样创建ProfileView,但请记住在创建后设置每个UIView的委托:

swipeableView.nextView = {
    let view = createProfileView() //set properties during creation?
    view.delegate = self 
    //set properties after creation?
    //view.backgroundColor = UIColor.red
    return view
 }
ViewController.swift

import UIKit

protocol ProfileProtocol {
    func buttonTapped()
}

class ProfileView: UIView {

    var delegate: ProfileProtocol?


    lazy var button: UIButton = {
        let button = UIButton()
        button.translatesAutoresizingMaskIntoConstraints = false
        button.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside)
        button.setTitle("Profile Button", for: .normal)
        button.backgroundColor = UIColor.black
        return button
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override func awakeFromNib() {

    }


    @objc func buttonTapped(_ sender: UIButton) {
        // Check for a nil delegate, we dont want to crash if one is not set
        if delegate != nil {
            delegate!.buttonTapped()
        } else {
            print("Please set ProfileView's Delegate")
        }
    }

    func setup() {
        //setup subviews
        self.addSubview(button)

        button.widthAnchor.constraint(equalToConstant: 150).isActive = true
        button.heightAnchor.constraint(equalToConstant: 50).isActive = true
        button.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
        button.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true

    }

}
import UIKit

class ViewController: UIViewController, ProfileProtocol {

    lazy var profileView: ProfileView = {
        let view = ProfileView()
        view.backgroundColor = UIColor.lightGray
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        profileView.delegate = self


        setup()
    }

    func buttonTapped() {
        print("Do Something")
    }


    func setup() {
        self.view.addSubview(profileView)
        profileView.widthAnchor.constraint(equalTo: self.view.widthAnchor).isActive = true
        profileView.heightAnchor.constraint(equalTo: self.view.heightAnchor, multiplier: 0.7).isActive = true
        profileView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
        profileView.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true

    }


    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

我喜欢将自定义视图模块化,并以编程方式进行操作,这样可以避免使用Xib

您应该将视图的职责和子视图保留给视图本身。最终,接收操作的视图应该负责调用委托的方法。另外,
nextView
是一个返回UIView的闭包:
(()->UIView?
不是UIView,对闭包中的函数的调用不是显式返回。您应该返回视图:
let view=createCardView()return view

ProfileView.swift

import UIKit

protocol ProfileProtocol {
    func buttonTapped()
}

class ProfileView: UIView {

    var delegate: ProfileProtocol?


    lazy var button: UIButton = {
        let button = UIButton()
        button.translatesAutoresizingMaskIntoConstraints = false
        button.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside)
        button.setTitle("Profile Button", for: .normal)
        button.backgroundColor = UIColor.black
        return button
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override func awakeFromNib() {

    }


    @objc func buttonTapped(_ sender: UIButton) {
        // Check for a nil delegate, we dont want to crash if one is not set
        if delegate != nil {
            delegate!.buttonTapped()
        } else {
            print("Please set ProfileView's Delegate")
        }
    }

    func setup() {
        //setup subviews
        self.addSubview(button)

        button.widthAnchor.constraint(equalToConstant: 150).isActive = true
        button.heightAnchor.constraint(equalToConstant: 50).isActive = true
        button.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
        button.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true

    }

}
import UIKit

class ViewController: UIViewController, ProfileProtocol {

    lazy var profileView: ProfileView = {
        let view = ProfileView()
        view.backgroundColor = UIColor.lightGray
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        profileView.delegate = self


        setup()
    }

    func buttonTapped() {
        print("Do Something")
    }


    func setup() {
        self.view.addSubview(profileView)
        profileView.widthAnchor.constraint(equalTo: self.view.widthAnchor).isActive = true
        profileView.heightAnchor.constraint(equalTo: self.view.heightAnchor, multiplier: 0.7).isActive = true
        profileView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
        profileView.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true

    }


    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}
您可以像创建任何其他UIView一样创建ProfileView,但请记住在创建后设置每个UIView的委托:

swipeableView.nextView = {
    let view = createProfileView() //set properties during creation?
    view.delegate = self 
    //set properties after creation?
    //view.backgroundColor = UIColor.red
    return view
 }
ViewController.swift

import UIKit

protocol ProfileProtocol {
    func buttonTapped()
}

class ProfileView: UIView {

    var delegate: ProfileProtocol?


    lazy var button: UIButton = {
        let button = UIButton()
        button.translatesAutoresizingMaskIntoConstraints = false
        button.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside)
        button.setTitle("Profile Button", for: .normal)
        button.backgroundColor = UIColor.black
        return button
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override func awakeFromNib() {

    }


    @objc func buttonTapped(_ sender: UIButton) {
        // Check for a nil delegate, we dont want to crash if one is not set
        if delegate != nil {
            delegate!.buttonTapped()
        } else {
            print("Please set ProfileView's Delegate")
        }
    }

    func setup() {
        //setup subviews
        self.addSubview(button)

        button.widthAnchor.constraint(equalToConstant: 150).isActive = true
        button.heightAnchor.constraint(equalToConstant: 50).isActive = true
        button.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
        button.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true

    }

}
import UIKit

class ViewController: UIViewController, ProfileProtocol {

    lazy var profileView: ProfileView = {
        let view = ProfileView()
        view.backgroundColor = UIColor.lightGray
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        profileView.delegate = self


        setup()
    }

    func buttonTapped() {
        print("Do Something")
    }


    func setup() {
        self.view.addSubview(profileView)
        profileView.widthAnchor.constraint(equalTo: self.view.widthAnchor).isActive = true
        profileView.heightAnchor.constraint(equalTo: self.view.heightAnchor, multiplier: 0.7).isActive = true
        profileView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
        profileView.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true

    }


    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

不相关,我假设您的协议必须定义为
协议。但是,请确保将
委托
属性定义为
变量,因为在这里,视图控制器和视图之间有一个强引用循环。同样,请确保
viewDidLoad
调用
super.viewDidLoad()
。也许你只是为了简洁而省略了它,但以防万一……我实际上不是100%确定类协议是什么,所以我不认为我是这样定义的。另外,感谢您指出ViewDidLoad在您的编辑中显示了
contentView
的创建,然后将其添加为
cardView
的子视图。但您仍然没有将其中任何一个添加到主视图层次结构中。您确定它是
cardView.addSubview(contentView)
而不是
view.addSubview(contentView)
?我使用的是与此框架无关的,我假设您的协议必须定义为
协议。但是,请确保将
委托
属性定义为
变量,因为在这里,视图控制器和视图之间有一个强引用循环。同样,请确保
viewDidLoad
调用
super.viewDidLoad()
。也许你只是为了简洁而省略了它,但以防万一……我实际上不是100%确定类协议是什么,所以我不认为我是这样定义的。另外,感谢您指出ViewDidLoad在您的编辑中显示了
contentView
的创建,然后将其添加为
cardView
的子视图。但您仍然没有将其中任何一个添加到主视图层次结构中。你确定它是
cardView.addSubview(contentView)
而不是
view.addSubview(contentView)
?我使用的是这个框架实际上这行
delegate?.buttonTapped()
不会崩溃,如果委托为零,它将什么也不做,因为委托被标记为可选的。没有必要显式检查它是否为零,除非您当然想标记这种情况。如果您100%正确,我将编辑我的答案以反映这一点。实际上,这一行
delegate?。buttonTapped()
不会崩溃,如果委托为零,它将什么也不做,因为委托被标记为可选的。没有必要显式检查它是否为零,除非您当然想标记这种情况。您是100%正确的,我将编辑我的答案以反映这一点。