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则说明代理未设置成功。
- 如果是通过Storyboard跳转,需在
代理调用时机错误:当前
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
相关产品推荐
相关产品推荐

