Ios 从单元格中显示UIAlertController

Ios 从单元格中显示UIAlertController,ios,swift,uitableview,protocols,uialertcontroller,Ios,Swift,Uitableview,Protocols,Uialertcontroller,我想通过点击单元格上的菜单按钮来演示UIAlertController class FeedViewCell: UITableViewCell { // some code... lazy var menuButton: UIButton = { let btn = UIButton() btn.addTarget(self, action: #selector(menuTapped), for: .touchUpInside) return

我想通过点击单元格上的菜单按钮来演示UIAlertController

class FeedViewCell: UITableViewCell {
// some code...

 lazy var menuButton: UIButton = {
        let btn = UIButton()
        btn.addTarget(self, action: #selector(menuTapped), for: .touchUpInside)
        return btn
    }()

@objc func menuTapped() {
        let actionSheet = UIAlertController(title: "", message: "", preferredStyle: .actionSheet)
        
        actionSheet.addAction(UIAlertAction(title: "Dismiss", style: .cancel, handler: { action in
            print("tap dismiss")
        }))
        
        actionSheet.addAction(UIAlertAction(title: "Follow", style: .default, handler: { action in
            print("tap follow")
        }))

     present(actionSheet, animated: true)
    }
}
这是一个FeedViewController:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cellid", for: indexPath) as! FeedViewCell
        return cell
    }
但是,我收到错误“在范围中找不到“present”


我不知道如何使用委托和协议来表示它。请帮助我解决问题

对于单元内的当前警报,您应该获得父控制器。警报控制器只能出现在其他父控制器上

让我们做吧。首先,添加扩展名。它允许使用以下方式获取视图的控制器:

公共扩展视图{
var viewController:UIViewController{
弱var parentResponder:UIResponder?=自身
而parentResponder!=零{
parentResponder=parentResponder!。下一步
如果让viewController=parentResponder作为?UIViewController{
返回视图控制器
}
}
归零
}
}
现在您可以在单元内部获取控制器。让我们这样做:

@objc func menutaped(){
//你在这里添加了警报,你的代码
guard let parentController=self.viewController else{return}
parentController.present(操作表,动画:true)
}

所有这些。

对于单元内的当前警报,您应该获得父控制器。警报控制器只能出现在其他父控制器上

让我们做吧。首先,添加扩展名。它允许使用以下方式获取视图的控制器:

公共扩展视图{
var viewController:UIViewController{
弱var parentResponder:UIResponder?=自身
而parentResponder!=零{
parentResponder=parentResponder!。下一步
如果让viewController=parentResponder作为?UIViewController{
返回视图控制器
}
}
归零
}
}
现在您可以在单元内部获取控制器。让我们这样做:

@objc func menutaped(){
//你在这里添加了警报,你的代码
guard let parentController=self.viewController else{return}
parentController.present(操作表,动画:true)
}

所有这些。

Ivan寻找UIViewController响应者链的方法都是可行的,但我建议采用另一种方法

修改您的
FeedViewCell
类以具有可选的viewController属性:

class FeedViewCell: UITableViewCell {
    // Note that the pointer to the view controller should be weak
    // To avoid a retain cycle, as pointed out by Matt.
    weak var viewController: UIViewController? = nil
    // some code...
}

并修改IBAction方法:

@IBAction func menuTapped() {
        // Make sure `viewController` is not nil.
        guard let viewController = viewController else {
           print("No view controller found. Exiting.")
           return
        }
        let actionSheet = UIAlertController(title: "", message: "", preferredStyle: .actionSheet)
        
        actionSheet.addAction(UIAlertAction(title: "Dismiss", style: .cancel, handler: { action in
            print("tap dismiss")
        }))
        
        actionSheet.addAction(UIAlertAction(title: "Follow", style: .default, handler: { action in
            print("tap follow")
        }))
     // Change your code to send the `present(_:animated:)` message to 
     // the cell's `viewController`.
     viewController.present(actionSheet, animated: true)
    }
}
然后在配置FeedViewCell单元格的视图控制器中,设置单元格的viewController属性:

func tableView(_ tableView: UITableView, 
  cellForRowAt indexPath: IndexPath) -> UITableViewCell {
   // Replace with the correct reuse identifier
    guard let cell = tableView.dequeueReusableCell(withIdentifier: yourIdentifier) as? FeedViewCell else {
       return UITableViewCell()
    }
    cell.viewController = self // Or, if the data source is not the main view controller for the window, pass in some other view controller.
}

Ivan寻找UIViewController响应者链的方法是可行的,但我建议采用另一种方法

修改您的
FeedViewCell
类以具有可选的viewController属性:

class FeedViewCell: UITableViewCell {
    // Note that the pointer to the view controller should be weak
    // To avoid a retain cycle, as pointed out by Matt.
    weak var viewController: UIViewController? = nil
    // some code...
}

并修改IBAction方法:

@IBAction func menuTapped() {
        // Make sure `viewController` is not nil.
        guard let viewController = viewController else {
           print("No view controller found. Exiting.")
           return
        }
        let actionSheet = UIAlertController(title: "", message: "", preferredStyle: .actionSheet)
        
        actionSheet.addAction(UIAlertAction(title: "Dismiss", style: .cancel, handler: { action in
            print("tap dismiss")
        }))
        
        actionSheet.addAction(UIAlertAction(title: "Follow", style: .default, handler: { action in
            print("tap follow")
        }))
     // Change your code to send the `present(_:animated:)` message to 
     // the cell's `viewController`.
     viewController.present(actionSheet, animated: true)
    }
}
然后在配置FeedViewCell单元格的视图控制器中,设置单元格的viewController属性:

func tableView(_ tableView: UITableView, 
  cellForRowAt indexPath: IndexPath) -> UITableViewCell {
   // Replace with the correct reuse identifier
    guard let cell = tableView.dequeueReusableCell(withIdentifier: yourIdentifier) as? FeedViewCell else {
       return UITableViewCell()
    }
    cell.viewController = self // Or, if the data source is not the main view controller for the window, pass in some other view controller.
}

你的整个方法是错误的;一个细胞在周围指挥视图控制器是不合适的。但是,如果您坚持,请使用此实用程序:

extension UIResponder {
    func next<T:UIResponder>(ofType: T.Type) -> T? {
        let r = self.next
        if let r = r as? T ?? r?.next(ofType: T.self) {
            return r
        } else {
            return nil
        }
    }
}

你的整个方法是错误的;一个细胞在周围指挥视图控制器是不合适的。但是,如果您坚持,请使用此实用程序:

extension UIResponder {
    func next<T:UIResponder>(ofType: T.Type) -> T? {
        let r = self.next
        if let r = r as? T ?? r?.next(ofType: T.self) {
            return r
        } else {
            return nil
        }
    }
}

只有视图控制器才能显示警报。添加回调闭包,将操作移动到控制器中,并从那里显示警报。下面是一个示例:使用视图控制器执行此操作。在cellForRowAt委托方法中添加闭包。您可以在下面的链接中找到一些方法:只有视图控制器才能显示警报。添加回调闭包,将操作移动到控制器中,并从那里显示警报。下面是一个示例:使用视图控制器执行此操作。在cellForRowAt委托方法中添加一个闭包。您可以在下面的链接中找到一些方法:这种方法通常是有效的,但它是脆弱的。如果视图控制器层次结构中有多个父视图控制器,则代码可能会选择错误的父视图控制器。最好给单元格一个viewController属性并让父视图控制器填充它。我不同意。它不易碎。我们知道所需的类。这种方法通常是有效的,但它是脆弱的。如果视图控制器层次结构中有多个父视图控制器,则代码可能会选择错误的父视图控制器。最好给单元格一个viewController属性并让父视图控制器填充它。我不同意。它不易碎。我们知道想要的类。在这里保留循环?这是真的。是的,返回视图控制器的指针应该很弱。在这里保留循环?这是真的。是的,返回视图控制器的指针应该很弱。