从自定义按钮执行转场操作

3
我创建了一个自定义按钮,以便在按钮中包含我所需的信息:
class CustomButton: UIButton {   
   var urlString: String?
   var documentType: String?
   var requestEntity: String?
   var requestSortBy: [NSSortDescriptor]?
   var requestPredicate: NSPredicate?
}

当我在collectionView(嵌入在tableView中)中创建单元格时,我会在我的自定义按钮documentTypeButton中包含信息。还要设置执行函数HomeTableViewController.documentTypeButtonTapped(_:)的目标以执行segue。

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

    let languageSelected = UserDefaults().value(forKey: "language") as! String

    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "allDocumentsItemCell", for: indexPath) as! AllDocumentsCollectionViewCell

    cell.documentTypeButton.documentType = Catalog.sharedInstance.allSections[allDocumentsSection!].singleItems[indexPath.row].name
    cell.documentTypeButton.requestEntity = Catalog.sharedInstance.allSections[allDocumentsSection!].singleItems[indexPath.row].entityName
    cell.documentTypeButton.requestSortBy = Catalog.sharedInstance.allSections[allDocumentsSection!].singleItems[indexPath.row].sortBy
    cell.documentTypeButton.requestPredicate = Catalog.sharedInstance.allSections[allDocumentsSection!].singleItems[indexPath.row].predicate
    cell.documentTypeButton.addTarget(nil, action: #selector(HomeTableViewController.documentTypeButtonTapped(_:)), for: .touchUpInside)


    return cell

}

HomeTableViewController中,当触摸按钮时,我有一个执行函数:

@objc func documentTypeButtonTapped(_ sender: CustomButton) {

    performSegue(withIdentifier: "goToDocumentList", sender: CustomButton())
    print(sender.documentType)
    print(sender.requestEntity)

}

func prepare(for segue: UIStoryboardSegue, sender: CustomButton) {

    let languageSelected = UserDefaults().value(forKey: "language") as! String

    if let destination = segue.destination as? DocumentListTableViewController {

        destination.titlePassed = sender.documentType!.localized(lang: languageSelected)
        destination.requestedEntity = sender.requestEntity
        destination.requestedSortBy = sender.requestSortBy
        destination.requestedPredicate = sender.requestPredicate

    }

}

上述打印语句能够正常输出信息。并且segue转到了DocumentListTableViewController

DocumentListTableViewControllerviewDidLoad中,我添加了以下内容:

override func viewDidLoad() {
    super.viewDidLoad()

    print(titlePassed)
    print(requestedEntity)

}

这两个打印语句会打印出nil

我猜问题应该在prepareForSegue方法中,可能和发送者有关... 我不知道。

任何帮助都将不胜感激。

3个回答

4
尝试像这样在performSegue()方法中传递sender参数:
@objc func documentTypeButtonTapped(_ sender: CustomButton) {

    performSegue(withIdentifier: "goToDocumentList", sender: sender)
    print(sender.documentType)
    print(sender.requestEntity)

}

问题是你正在实例化类型为CustomButton()的新对象,而不是传递“sender”。

在DocumentListTableViewController中,这两个打印语句仍然返回nil。 - jRuMoL
尝试在调用 prepare 方法时,如果分配语句被激活并具有适当的数据,请使用断点。 - bezoadam

2
问题在于你在performSegue调用中传递了一个新的(空)CustomButton实例,而不是动作的sender
但是,你设计的将自定义按钮作为数据容器的方法仍然很糟糕。请不要这样做。那太可怕了。
有一种更简单、更高效的解决方案:
AllDocumentsCollectionViewCell中创建一个回调闭包。
var callback : (()->Void)?

创建一个 IBAction 并将其连接到按钮上,当按钮被点击时,回调函数就会被调用。

@IBAction func documentTypeButtonTapped(_ sender: UIButton) {
    callback?()
}

HomeTableViewController 中将闭包分配给回调函数,在其中执行segue并传递数据源数组的项。 但是在每次调用collectionView时调用UserDefaults().value(并获取相同的索引路径4次的项目非常低效。永远不要使用value(forKey。在UserDefaults中有string(forKey
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

    let languageSelected = UserDefaults().string(forKey: "language")! 

    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "allDocumentsItemCell", for: indexPath) as! AllDocumentsCollectionViewCell
    cell.callback {
         let item = Catalog.sharedInstance.allSections[allDocumentsSection!].singleItems[indexPath.row]
         self.performSegue(withIdentifier: "goToDocumentList", sender: item)
    }
    return cell

}

prepare(for中获取数据源项目(我不知道它是什么类型),并从那里检索信息。您甚至可以将整个项目传递给目标视图控制器。
func prepare(for segue: UIStoryboardSegue, sender: CustomButton) {

    let languageSelected = UserDefaults().string(forKey: "language")! 

    if let destination = segue.destination as? DocumentListTableViewController {
        let item = sender as! WhatEverTheTypeIs // change this to the real type
        destination.titlePassed = item.name.localized(lang: languageSelected)
        destination.requestedEntity = item.entityName
        destination.requestedSortBy = item.sortBy
        destination.requestedPredicate = item.predicate

    }
}

非常感谢您的回答。当您说“在HomeTableViewController中为回调分配一个闭包,在那里执行segue并传递数据源数组的项目”时,我不知道如何做到这一点。我一直在搜索,但很难理解。 - jRuMoL

2
在你的performSegue调用中,你正在发送一个CustomButton的新实例。
performSegue(withIdentifier: "goToDocumentList", sender: CustomButton())

所以它的参数在下一个视图控制器中将会是nil,你需要发送发送者。

performSegue(withIdentifier: "goToDocumentList", sender: sender)

您需要重写prepareForSegue方法才能被调用,无需更改其签名,您可以像这样编写:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    let languageSelected = UserDefaults().value(forKey: "language") as! String

    if let destination = segue.destination as? DocumentListTableViewController {

        let myCustomButton = sender as! CustomButton

        destination.titlePassed = myCustomButton.documentType!.localized(lang: languageSelected)
        destination.requestedEntity = myCustomButton.requestEntity
        destination.requestedSortBy = myCustomButton.requestSortBy
        destination.requestedPredicate = myCustomButton.requestPredicate

    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接