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

TTTAttributedLabel全选崩溃:Unrecognized selector sent to instance

这个崩溃问题很明确——你在canPerformAction里允许了selectAll操作,但你的CopyableLabel类并没有实现对应的selectAll(_:)方法,系统找不到这个方法就会抛出unrecognized selector异常。同时,要实现部分文本选择+复制,还需要开启TTTAttributedLabel本身的文本选择支持,否则即使加了全选方法,也没法选中文本。

下面是修改后的完整实现,我会一步步解释关键变动:

class CopyableLabel : TTTAttributedLabel {
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupLabel()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setupLabel()
    }
    
    // 初始化时配置文本选择所需的基础设置
    private func setupLabel() {
        isUserInteractionEnabled = true // 必须开启交互,否则无法响应触摸选择
        textSelectionEnabled = true     // 开启TTTAttributedLabel的文本选择功能
    }
    
    override var canBecomeFirstResponder: Bool { 
        return true 
    } 
    
    // 支持复制、全选操作,也可以根据需求添加剪切/粘贴(如果需要的话)
    override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool { 
        let supportedActions: [Selector] = [
            #selector(UIResponderStandardEditActions.copy),
            #selector(UIResponderStandardEditActions.selectAll(_:))
        ]
        return supportedActions.contains(action)
    } 
    
    // 实现系统要求的selectAll方法,完成全选逻辑
    @objc func selectAll(_ sender: Any?) {
        guard let textContent = self.text, !textContent.isEmpty else { return }
        // 设置选中范围为整个文本
        selectedRange = NSRange(location: 0, length: textContent.count)
        // 更新菜单状态,确保选中状态正确显示
        UIMenuController.shared.update()
    }
    
    // 重写copy方法,优先复制选中的部分文本,无选中则复制全部
    override func copy(_ sender: Any?) {
        let pasteboard = UIPasteboard.general
        if let selectedText = self.selectedText {
            pasteboard.string = selectedText
        } else {
            pasteboard.string = self.text ?? ""
        }
        // 复制完成后隐藏菜单
        UIMenuController.shared.setMenuVisible(false, animated: true)
    }
    
    // 触发菜单显示的方法(可以根据你的交互逻辑调用,比如长按手势)
    func showEditMenu() { 
        becomeFirstResponder() 
        let menu = UIMenuController.shared 
        if !menu.isMenuVisible { 
            menu.setTargetRect(bounds, in: self) 
            menu.setMenuVisible(true, animated: true) 
        } 
    } 
}

关键修改说明:

  1. 开启文本选择基础配置:
    在setupLabel里开启了isUserInteractionEnabled和textSelectionEnabled,这是TTTAttributedLabel支持文本触摸选择的必要前提,默认这些属性可能是关闭的。

  2. 实现selectAll(_:)方法:
    这是解决崩溃的核心——系统调用全选菜单时会触发这个方法,我们通过设置selectedRange为整个文本范围来完成全选操作,同时更新菜单状态确保选中效果正确显示。

  3. 优化复制逻辑:
    重写copy方法,优先使用selectedText(TTTAttributedLabel提供的选中文本属性)复制选中的部分,如果没有选中内容则复制全部文本,完美支持部分选择复制的需求。

  4. 代码结构优化:
    把初始化配置抽成单独的setupLabel方法,让代码更清晰;把原来的select方法改名为showEditMenu,语义更明确。

最后,记得给你的Label添加长按手势来触发showEditMenu方法(或者根据你的业务逻辑触发),这样用户长按就能调出编辑菜单,进行部分选择、全选和复制操作了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:59:21