You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

UIKit中Delegate Protocol未触发:LoginVC向StoreVC传值失败求助

问题:代理协议实现后方法未触发

尝试从LogInViewController向StoreViewController传递数据,已实现Delegate Protocol,但代理方法未触发。断点已命中self.delegate?.LoggedIn(userId: 88 ?? 11, token: tokenField.text ?? "nill"),但StoreVC端的对应方法未执行。

LogInViewController代码:

import UIKit

protocol RefreshCommercialInfo: AnyObject {
    func LoggedIn(userId: Int, token: String)
}

class LogInViewController: UIViewController {
    
    weak var delegate: RefreshCommercialInfo?
    
    private let userNameField = CustomTextField(fieldType: .username)
    private let passwordField = CustomTextField(fieldType: .password)
    private let tokenField = CustomTextField(fieldType: .username)
    private let singInButton = CustomButton(title: "Sign In", hasBackground: true, fontSize: .med)
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.setUpUI()
        self.singInButton.addTarget(self, action: #selector(didTapSignIn) , for: .touchUpInside)
    }
    
    @objc private func didTapSignIn() {
        let defaults = UserDefaults.standard
        print("DEBUG PRINT: did tap Sign In")
        guard let Nametext = self.userNameField.text else { return }
        guard let Passwordtext = self.passwordField.text else { return }
        print("\(Nametext) account password is \(Passwordtext)")
        
        AuthenticationService().login(username: Nametext, password: Passwordtext) { result in
                    switch result {
                    case .success(let token):
                        defaults.setValue(token.access_token, forKey: "jsonwebtoken")
                        defaults.setValue(token.user_Id, forKey: "userId")
                        DispatchQueue.main.async {
                            self.tokenField.text = token.access_token!
                        }
                    case .failure(let error):
                        print(error.localizedDescription)
                    }
                }
        self.delegate?.LoggedIn(userId: 88 ?? 11, token: tokenField.text ?? "nill")
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        self.navigationController?.navigationBar.isHidden = true
    }
    
    private func setUpUI() {
        self.view.backgroundColor = .systemBackground
        
        self.view.addSubview(userNameField)
        self.view.addSubview(passwordField)
        self.view.addSubview(tokenField)
        self.view.addSubview(singInButton)
        
        userNameField.translatesAutoresizingMaskIntoConstraints = false
        passwordField.translatesAutoresizingMaskIntoConstraints = false
        tokenField.translatesAutoresizingMaskIntoConstraints = false
        singInButton.translatesAutoresizingMaskIntoConstraints = false
        
        NSLayoutConstraint.activate([
            self.userNameField.topAnchor.constraint(equalTo: self.view.layoutMarginsGuide.topAnchor, constant: 12),
            self.userNameField.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
            self.userNameField.heightAnchor.constraint(equalToConstant: 55),
            self.userNameField.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.85),
            
            self.passwordField.topAnchor.constraint(equalTo: userNameField.bottomAnchor, constant: 12),
            self.passwordField.centerXAnchor.constraint(equalTo: userNameField.centerXAnchor),
            self.passwordField.heightAnchor.constraint(equalToConstant: 55),
            self.passwordField.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.85),
            
            self.tokenField.topAnchor.constraint(equalTo: passwordField.bottomAnchor, constant: 12),
            self.tokenField.centerXAnchor.constraint(equalTo: passwordField.centerXAnchor),
            self.tokenField.heightAnchor.constraint(equalToConstant: 55),
            self.tokenField.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.85),
            
            self.singInButton.topAnchor.constraint(equalTo: tokenField.bottomAnchor, constant: 12),
            self.singInButton.centerXAnchor.constraint(equalTo: tokenField.centerXAnchor),
            self.singInButton.heightAnchor.constraint(equalToConstant: 55),
            self.singInButton.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.85)
        ])
    }
}

StoreViewController代码:

class StoreViewController: UIViewController, FurnitureListViewDelegate, RefreshCommercialInfo {
    
    func LoggedIn(userId: Int, token: String) {
        self.title = "NotStore"
        DispatchQueue.main.async {
            self.tokentext = token
            self.setUpView()
            self.GetTrendingProducts()
            self.GetCategories()
            self.populateAllProductsWithCategories()
        }
    }
    
    private var tokentext: String = ""
    private var ProductCategorizedDict: [Int : [FurnitureItem]] = [Int : [FurnitureItem]]()
    private var isUpdated: Bool = false
    private var ProductsUpdated: Bool = false
    private var trendingProducts : [TrendingFurnitureProduct] = [TrendingFurnitureProduct]()
    private var categories: [Category] = [Category]()
    
    private let furnitureListView = FurnitureListView()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .systemBackground
        title = "Store"
        setUpView()
        let defaults = UserDefaults.standard
        guard let tokentxt = defaults.string(forKey: "jsonwebtoken") else { return }
        self.tokentext = tokentxt
    }
    
    private func setUpView() {
        view.addSubview(furnitureListView)
        furnitureListView.delegate = self
        NSLayoutConstraint.activate([
            furnitureListView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
            furnitureListView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor),
            furnitureListView.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor),
            furnitureListView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
        ])
    }
    
    func rmFurnitureListView(_ furnitureListView: FurnitureListView, didSelectFurniture furniture: TrendingFurnitureProduct) {
        print("choosing furniture event handler")
        let viewModel = FurnitureDetailViewViewModel(furniture: furniture)
        
        DispatchQueue.main.async { [weak self] in
            let vc = FurnitureDetailViewController()
            vc.configure(with: viewModel)
            self?.navigationController?.pushViewController(vc , animated: true)
        }
    }
    
    func GetTrendingProducts() {}
    func GetCategories() {}
    func populateAllProductsWithCategories() {}
}

排查方向
  • 代理对象未正确赋值:确认StoreViewController是否在合适的时机给LogInViewController的delegate属性赋值。比如:

    • 如果是通过Storyboard跳转,需在prepare(for:sender:)方法中获取LogInViewController实例并设置loginVC.delegate = self;
    • 如果是代码初始化跳转,需在创建LogInViewController后立即设置delegate。
      可在调用代理前添加打印print("delegate status: \(delegate)"),若输出nil则说明代理未设置成功。
  • 代理调用时机错误:当前self.delegate?.LoggedIn(...)是在异步登录请求的回调外部调用的,此时登录请求尚未完成,更关键的是:若StoreViewController是登录成功后才跳转创建的,此时delegate仍为nil,导致调用失效。需将代理调用移到登录成功的回调块内,且确保此时delegate已被正确赋值:

    AuthenticationService().login(username: Nametext, password: Passwordtext) { result in
        switch result {
        case .success(let token):
            defaults.setValue(token.access_token, forKey: "jsonwebtoken")
            defaults.setValue(token.user_Id, forKey: "userId")
            DispatchQueue.main.async {
                self.tokenField.text = token.access_token!
                // 移到此处调用代理
                self.delegate?.LoggedIn(userId: token.user_Id ?? 11, token: token.access_token ?? "nil")
            }
        case .failure(let error):
            print(error.localizedDescription)
        }
    }
    
  • 代理方法签名不一致:检查RefreshCommercialInfo协议中的方法签名与StoreViewController的实现是否完全一致(包括方法名大小写、参数名称、参数类型),哪怕细微差异都会导致方法无法匹配。

  • 代理对象被提前释放:由于delegate使用了weak修饰,若StoreViewController被提前释放,delegate会变为nil。可检查页面跳转逻辑,确认StoreViewController的生命周期是否正常,是否在代理调用前已被销毁。


内容的提问来源于stack exchange,提问作者zstm284

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 07:17:05