【问题标题】:how to use #undef directive in swift 2.3如何在 swift 2.3 中使用 #undef 指令
【发布时间】:2018-04-13 16:37:21
【问题描述】:

我想在 swift 2.3 中取消定义或覆盖 NSLocalizedString,我对此进行了很多搜索,最后我在 Objective C 中找到了一种方法,如下所示。

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

我想快速实现这个功能。 我只知道NSLocalizedStringNSBundle.h 中用于Objective C 的宏。所以我们可以重新定义它。但是对于swift 我们无法实现这一点。我只想为swift 重新定义或覆盖NSLocalizedString 函数。请帮我排序出这个。任何帮助将不胜感激。

【问题讨论】:

  • 你考虑过方法混搭吗?这是一个关于如何在 swift kostiakoval.github.io/posts/methods-swizzling-in-swift 中执行此操作的示例
  • 我们可以对类和实例方法使用swizzling。但是你怎么能swizzle全局函数,NSLocalizedString就像一个swift中的全局函数,可以在没有任何类或对象引用的情况下调用。
  • 这个要求很“不寻常”。你想达到什么目的?
  • 你是对的,我的错,完全错过了那部分

标签: swift localization preprocessor-directive nslocalizedstring xcode8.1


【解决方案1】:

#undefC preprocessor directive,Swift does not support any preprocessor directives,包括用于 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 的不同函数
  • 是的,或者只是一个函数需要Any,但再次我建议您将该函数命名为其他名称,如果对您有帮助,请将我的回答标记为已接受。
  • 不,这对我没有帮助。我已经知道它可以与自定义函数一起使用,但我需要重新定义,再次阅读我的问题
  • 如果您可以提供一些上下文,例如为什么这是必要的以及您将传递的确切参数,这将有所帮助。我只是问,因为这似乎是一个非常罕见的用例。
  • 场景是我们在超过 100 个类中调用这个方法,所以现在我们试图在一个地方覆盖这个方法来处理语言后备情况
【解决方案2】:

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"

【讨论】:

  • 您将在项目中重新定义新版本的位置
  • 是全局函数还是协议方法还是别的什么。
  • 我是否需要在我已经调用此方法的每个类中重新定义它
  • 当我们在闭包和属性初始化器中调用 NSLocalizedString 方法时,您的解决方案也不起作用,您需要传递该类的引用才能调用此方法。
  • @SumitDhariwal 您在任何类之外的项目中定义新版本。它是一个全局函数。如果你想使用一个新的实现,你必须在类中重新定义它(只有在需要一个新的实现时,否则它将只取范围内最接近的)。该解决方案也适用于闭包,它采用最接近定义块的范围的函数。
【解决方案3】:

找到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 会期望您使用 NSLocalizedStringself 就像这样,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。
  • 您的意思是对self 的需求破坏了您试图实现的行为?您始终可以将所需的字符串分配给闭包外的let,并在内部使用letlet string = NSLocalizedString("mystring", comment: ""); self.present(anotherVc, animated: true) { [weak self] in self?.myLabel.text = string }
  • 对于属性初始化器,编译器使用静态函数
  • 你的意思是对自我的需要破坏了你试图实现的行为? - 是的。更新你的答案你试图提出的建议。
  • 由于第三方库的使用,您不能在闭包之外设置字符串?还是只是开销太大?
猜你喜欢
  • 1970-01-01
  • 2017-04-26
  • 1970-01-01
  • 2016-12-17
  • 1970-01-01
  • 2011-05-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多