NSString子类或包装类或类别

时间:2017-05-18 22:46:09

标签: ios objective-c cocoa foundation objective-c-category

由于某些政府指导原则(医疗与健康措辞),我目前正在帮助需要更改应用语言的客户。他们的应用程序很庞大,所有字符串都包含在代码中,即(stringWithFormat / hardcoded),它们都不在外部表中。这意味着这将是一项庞大的手工任务。

在未来的一个未确定的时刻,客户认为他们将获得回复当前措辞的批准,并希望将字符串切换回来。大多数变化实际上都是将一个有问题的单词转换为一个问题较少的单词。

我想如果我可以在运行时基于bool开关更改字符串,它可能会消除所涉及的手动工作,并且它会让我在需要时切换语言。

首次尝试:

+ (instancetype)stringWithFormat:(NSString *)format, ...
{
   va_list args;
   va_start(args,format);
   //todo check flag if we're changing the language
   //todo replace problematic word from 'format'
   NSString *result = [NSString stringWithFormat:format,args];

   return result;
}

我首先快速编写了一个类别来覆盖stringWithFormat以替换有问题的单词。我忘了我会失去stringWithFormat的原始实现。这导致无休止的递归。

Next Attempt(子类):

我开始尝试子类化NSString但是遇到了一个stackoverflow帖子,说如果我的解决方案是将类集群子类化,那么我就不能理解我的问题了,因为几乎没有对类集群进行子类化。

最终选项(包装):

我最后的尝试是编写一个包装类,但这种方法违背了最初的目的,即避免手动寻找应用程序中的每个字符串。

我不确定如何解决这个问题。如果我需要向其中一个核心类添加/覆盖功能,我该怎么办。

3 个答案:

答案 0 :(得分:1)

有一个更简单的解决方案似乎更合适。使用NSLocalizedString,使用键而不是实际字符串:

displayString *NSString = NSLocalizedString(@"displayString", nil);
cancelButtonTitle *NSString = NSLocalizedString(@"cancelButtonTitle", nil);

然后在您的应用中创建Localizable.strings文件,并定义应显示的实际值:

"displayString" = "The string to display in English"
"cancelButtonTitle" = "Cancel"

您将Localizable.strings文件放入应用程序包中,应用程序使用它在运行时进行字符串替换。

您还可以为不同语言定义不同版本的Localizable.strings,例如,如果用户将其语言设置为西班牙语,则对NSLocalizedString()的调用会为您提供西班牙语版本。

(正如你所提到的,NSString是一个类集群。这意味着它是各种不同私有子类的公共接口。你不能确定你的私有子类是什么在创建NSString时获取,并且尝试将其子类化是一个坏主意。)

答案 1 :(得分:1)

对于硬编码字符串,除了通过将其分配给某种类型的字符串转换器类而手动修改它们之外别无他法。所以那些:

yourmom.text = @"Hi Mom";
yourdad.text = [NSString stringWithFormat:@"%@ and Dad!",yourmom.text];

您需要将这些类型的分配更改为

yourmom.text = [StringConverter string:@"Hi Mom"];
yourdad.text = [StringConverter string:@"%@ and Dad!" placeHolder:yourmom.text];

对于storyboard或xibs中的字符串,您可以通过viewdidload中的迭代循环来更改它们。祝你好运。

答案 2 :(得分:1)

你的第一次尝试的想法没有错,只是它的实施中有点错误。变化:

NSString *result = [NSString stringWithFormat:format,args];

为:

NSString *result = [NSString alloc] initWithFormat:format arguments:args];

这是stringWithFormat:的扩展,拦截将起作用。

关于类集群的思考在这种特殊情况下是一个红色的鲱鱼,集群的前端(NSString)必须提供类方法的实现(+stringWithFormat:),所以你可以使用一个简单的类拦截它们。

,拦截+stringWithFormat: 时要小心。一个简单的测试将告诉你它被框架使用了很多而且你不想打破它们 - 因为我的第一个简单的测试是通过简单地将“d”改为“c”来实现的,它将“窗口”改为“wincow”,这反过来打破了Xcode默认应用程序的绑定设置,该应用程序绑定了属性“窗口”......

如果您正在更改与健康相关的单词,那么您可能会更好。整个字符串会更好。

更好的方法可能是简单地编写一个RE来匹配代码中的所有文字字符串,并将function(string)替换为您编写的用于执行转换的某个函数(而不是方法)。

HTH