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

Swift 4中如何实现NSObject的不区分大小写版responds(to: Selector)?

嘿,这个场景我之前做推送映射的时候也遇到过!刚好可以给你几个在Swift 4里实现不区分大小写检查NSObject属性/方法的方案,亲测好用~

方案1:扩展NSObject实现不区分大小写的responds(to:)替代方法

这个方法会遍历当前类及父类的所有实例方法,通过将方法名转小写后和目标字符串对比,实现不区分大小写的匹配:

import Foundation

extension NSObject {
    func respondsToSelectorIgnoringCase(_ selectorName: String) -> Bool {
        let lowercaseTarget = selectorName.lowercased()
        var methodCount: UInt32 = 0
        guard let methods = class_copyMethodList(type(of: self), &methodCount) else {
            return false
        }
        defer {
            free(methods) // 记得释放Runtime分配的内存
        }
        
        // 遍历当前类的所有方法
        for i in 0..<Int(methodCount) {
            let method = methods[i]
            let selector = method_getName(method)
            let selectorStr = String(cString: sel_getName(selector)).lowercased()
            if selectorStr == lowercaseTarget {
                return true
            }
        }
        
        // 当前类没找到的话,递归检查父类
        if let superclass = class_getSuperclass(type(of: self)) {
            guard let superInstance = superclass.init() as? NSObject else {
                return false
            }
            return superInstance.respondsToSelectorIgnoringCase(lowercaseTarget)
        }
        
        return false
    }
}
方案2:针对属性的精准检查(如果只关心属性而非所有方法)

如果你的需求只是检查属性(而不是所有Objective-C方法),可以用class_copyPropertyList直接遍历属性列表,这样更精准:

extension NSObject {
    func hasPropertyIgnoringCase(_ propertyName: String) -> Bool {
        let lowercaseTarget = propertyName.lowercased()
        var propertyCount: UInt32 = 0
        guard let properties = class_copyPropertyList(type(of: self), &propertyCount) else {
            return false
        }
        defer {
            free(properties)
        }
        
        // 遍历当前类的所有属性
        for i in 0..<Int(propertyCount) {
            let property = properties[i]
            let propNameStr = String(cString: property_getName(property)).lowercased()
            if propNameStr == lowercaseTarget {
                return true
            }
        }
        
        // 检查父类属性
        if let superclass = class_getSuperclass(type(of: self)) {
            guard let superInstance = superclass.init() as? NSObject else {
                return false
            }
            return superInstance.hasPropertyIgnoringCase(lowercaseTarget)
        }
        
        return false
    }
}
额外补充:获取匹配的Selector以便实际调用

如果检查通过后你还需要调用对应的方法/属性,可以扩展一个方法返回匹配的Selector:

extension NSObject {
    func selectorForNameIgnoringCase(_ name: String) -> Selector? {
        let lowercaseTarget = name.lowercased()
        var methodCount: UInt32 = 0
        guard let methods = class_copyMethodList(type(of: self), &methodCount) else {
            return nil
        }
        defer {
            free(methods)
        }
        
        for i in 0..<Int(methodCount) {
            let method = methods[i]
            let selector = method_getName(method)
            let selectorStr = String(cString: sel_getName(selector)).lowercased()
            if selectorStr == lowercaseTarget {
                return selector
            }
        }
        
        // 检查父类
        if let superclass = class_getSuperclass(type(of: self)) {
            guard let superInstance = superclass.init() as? NSObject else {
                return nil
            }
            return superInstance.selectorForNameIgnoringCase(lowercaseTarget)
        }
        
        return nil
    }
}
使用示例

假设你有一个User类:

class User: NSObject {
    @objc var userName: String = "Jack"
    @objc var age: Int = 28
}

let user = User()

// 检查是否存在小写的"username"对应的属性
print(user.respondsToSelectorIgnoringCase("username")) // 输出 true
print(user.hasPropertyIgnoringCase("age")) // 输出 true

// 获取Selector并调用属性
if let userNameSelector = user.selectorForNameIgnoringCase("username") {
    let userName = user.perform(userNameSelector)?.takeUnretainedValue() as? String
    print(userName) // 输出 "Jack"
}
注意事项
  1. 所有需要被检测的属性/方法必须加上@objc修饰,因为Swift的Runtime只能访问暴露给Objective-C的成员。
  2. 如果存在多个转小写后名字相同的方法/属性,会返回第一个匹配的结果(不过驼峰命名规范下这种情况很少见)。
  3. 递归检查父类的时候,我们创建了父类的实例,对于一些需要初始化参数的父类,可能需要调整逻辑(不过NSObject的子类大多支持无参初始化)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 06:40:18