如何在Swift 2.3中使用 #undef 指令

5

我希望能够在Swift 2.3中取消定义或覆盖NSLocalizedString,我搜索了很多关于此的内容,最终我发现在Objective C中有以下方法。

#undef NSLocalizedString
#define NSLocalizedString(key,_comment) your_function_name

我希望在Swift中实现这个功能。我只知道NSLocalizedString是Objective C中NSBundle.h中的宏。所以我们可以重新定义它,但是在Swift中我们无法实现这一点。我只想重新定义或覆盖Swift中的NSLocalizedString函数。请帮我解决这个问题。任何帮助都将不胜感激。


你考虑过方法混淆吗?这里有一个在Swift中如何实现的例子:http://kostiakoval.github.io/posts/methods-swizzling-in-swift - Samer Murad
我们可以使用 swizzling 来交换类和实例方法。但是,如何交换全局函数呢?在 Swift 中,NSLocalizedString 就像一个全局函数,可以在没有任何类或对象引用的情况下调用。 - Sumit Jangra
这个需求非常“不寻常”。你想要实现什么? - Daniel
你是对的,我的错,完全忽略了那一部分。 - Samer Murad
3个回答

0

NSLocalicedString 是 Swift 中的全局方法。

全局函数无法被覆盖,但可以重新定义。要重新定义该方法,只需声明一个新版本即可。所选函数将基于作用域。例如:

func NSLocalizedString(_ key: String, tableName: String? = nil, bundle: Bundle = Bundle.main, value: String = "", comment: String) -> String {
    return "redefined version in the project"
}

class Test {
    func NSLocalizedString(_ key: String, tableName: String? = nil, bundle: Bundle = Bundle.main, value: String = "", comment: String) -> String {
        return "redefined version in Test"
    }

    func getLocalizedString() -> String{
        return NSLocalizedString("test", comment: "t")
    }
}

class Test2 {
    func NSLocalizedString(_ key: String, tableName: String? = nil, bundle: Bundle = Bundle.main, value: String = "", comment: String) -> String {
        return "redefined version in Test2"
    }

    func getLocalizedString() -> String{
        return NSLocalizedString("test", comment: "t")
    }
}

NSLocalizedString("test", comment: "t") //will return "redefined version in the project"
Test().getLocalizedString() //will return "redefined version in Test"
Test2().getLocalizedString() //will return "redefined version in Test2"

在项目中重新定义新版本的位置 - Sumit Jangra
它是一个全局函数还是协议方法或其他什么东西。 - Sumit Jangra
我需要在已经调用该方法的每个类中重新定义它吗? - Sumit Jangra
你的解决方案在闭包和属性初始化器中调用NSLocalizedString方法时也无法工作,你需要传递该类的引用来调用此方法。 - Sumit Jangra
@SumitDhariwal 在任何类之外的项目中定义新版本。它是一个全局函数。如果您想使用新实现,您将不得不在类中重新定义它(仅在需要新实现时,否则它将只取最接近的范围)。该解决方案也适用于闭包,它获取最接近块定义的范围内的函数。 - Daniel
显示剩余5条评论

0

发现this,只有在类内使用NSLocalizedString时才有用。 在Swift 4上进行了以下调整并进行了测试

extension NSObject {
    func NSLocalizedString(_ key: String, comment: String) -> String {
        return "My custom localization"
    }

    static func NSLocalizedString(_ key: String, comment: String) -> String {
        return "My custom localization"
    }
}
class ViewController: UIViewController {

    @IBOutlet weak var myLabel: UILabel!
    override func viewDidLoad() {
        super.viewDidLoad()
        myLabel.text = NSLocalizedString("mystring",comment:"")
    }
}

对于Swift 2.3,应该使用相同的方法(在key参数之前不加下划线)。

更新

当与闭包一起使用时,这需要一个解决方法,因为Swift将期望您像这样使用self.NSLocalizedString("mystring",comment:"")。 在这种情况下的解决方法是将字符串分配给闭包外部的let/var

示例:

 // Doesn't work
 self.present(anotherVc, animated: true) { [weak self] in
      self?.myLabel.text = NSLocalizedString("mystring", comment: "") // compiler will throw an error
 } 
 // Does work
 let string = NSLocalizedString("mystring", comment: "")
 self.present(anotherVc, animated: true) { [weak self] in
      self?.myLabel.text = string 
 } 

对于属性初始化器,编译器将使用静态函数,因此设置它们两个非常重要

示例:

class MyClass: NSObject {
   // This let
   let myStr = NSLocalizedString("mystring",comment:"")
}

extension NSObject {
    func NSLocalizedString(_ key: String, comment: String) -> String {
        return "My custom localization"
    }
    // Uses the static method    
    static func NSLocalizedString(_ key: String, comment: String) -> String {
        return "My custom localization"
    }
}

尝试在属性初始化器和闭包中调用 NSLocalizedString。 - Sumit Jangra
你的意思是说需要使用 self 会破坏你所期望的行为?你可以在闭包外部将所需字符串分配给一个 let 常量,然后在闭包内部使用该常量:let string = NSLocalizedString("mystring", comment: ""); self.present(anotherVc, animated: true) { [weak self] in self?.myLabel.text = string } - Samer Murad
对于属性初始化器,编译器使用静态函数。 - Samer Murad
你的意思是需要自我意识会破坏你试图达成的行为吗?- 是的。请更新你的回答,说明你建议做什么。 - Sumit Jangra
你不能在闭包外设置字符串,是因为使用了第三方库吗?还是因为开销太大? - Samer Murad

-1

#undef 是一个 C 预处理指令,而 Swift 不支持 任何 预处理指令,包括用于 NSLocalizedString 的复杂 #define 宏。实际上,它被导入为:

/// Returns a localized string, using the main bundle if one is not specified.
public func NSLocalizedString(_ key: String, tableName: String? = default, bundle: Bundle = default, value: String = default, comment: String) -> String

然而,你可以通过编写自己的实现轻松地实现预期的行为,这样就会自动使用它。 例如

public func NSLocalizedString(_ key: String, tableName: String? = nil, bundle: Bundle = Bundle.main, value: String = "", comment: String) -> String {
    // Do your magic here!
    return "test"
}

但请不要这样做。最好创建一个不同的函数。否则,你的函数是否被使用将不清楚,或者你可能会遇到错误:error: ambiguous use of 'NSLocalizedString(_:tableName:bundle:value:comment:)',即使你只是想让一些东西变成可选的,也需要更改签名。

你的意思是为每个类创建不同名称的 NSLocalizedString 函数吗? - Sumit Jangra
可以使用这种方式,即编写一个接受Any参数的函数,但请注意建议您给该函数取一个不同的名称,如果我的回答对您有帮助,请将其标记为已采纳。 - Coder-256
不,这对我没有帮助。我已经知道它可以与自定义函数一起使用,但我需要重新定义,重新阅读我的问题。 - Sumit Jangra
如果您能提供一些上下文,例如为什么需要这样做以及您将传递哪些确切的参数,那将会很有帮助。我之所以问这个问题,是因为这似乎是一个非常罕见的用例。 - Coder-256
情境是:我们在100多个类中调用了这个方法,现在我们正试图在一个地方覆盖这个方法来处理语言后备情况。 - Sumit Jangra
好的,但是它将确切地传递什么 - Coder-256

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