【问题标题】:Slow iOS string operation...why?iOS 字符串操作慢...为什么?
【发布时间】:2014-03-13 23:32:32
【问题描述】:

我有四个文本字段,我需要从中创建一个“名称”,如下所示:

firstname lastname 和 otherfirstname otherlastname(即 Barbara Smith 和 John Jameson)

但是,如果缺少任何部分,则需要将其与分隔空间和/或分隔“and”一起省略,因此最终可能会出现“Barbara and John”或“John Jameson”或“Smith”和 Jameson' 或这四个字段的任何组合。

如果它是执行回调的这四个字段之一,我会调用一个方法来从textFieldShouldEndEditing 创建这个新的名称字符串。然后我使用自己的协议方法通过委托回调设置应用程序标题(由于我的视图控制器嵌套)。

这一切都很好,除了出于某种原因,在这四个字段之间点击真的很慢。

在我看来,在任何其他文本字段之间点击要快得多。我怀疑这是我的名字字符串生成方法。

这是我的textFieldShouldEndEding 回调:

- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
// set the event title if the client name fields have been edited
if ((textField == self.CPNameFirst) || (textField == self.CPNameLast) || (textField == self.CSNameFirst) || (textField == self.CSNameLast)) {
    if (self.CPNameFirst.text.length == 0 && self.CPNameLast.text.length == 0 && self.CSNameFirst.text.length == 0 && self.CSNameLast.text.length == 0) {
        // the user has just erased all data that could make up the event name automatically
        self.theEvent.name = @"New Client";
    } else {
        // set the event name using the client names
        self.theEvent.name = [self generateAutomaticEventName];
    }
    [self.delegate changeAppTitle:self.theEvent.name];
}
return YES;
}

以及生成名称字符串的方法:

- (NSString *)generateAutomaticEventName {
NSString *theName = [[NSString alloc] init];
NSString *CPPart = [[NSString alloc] init];
NSString *CSPart = [[NSString alloc] init];

// generate the primary client part
if ((self.CPNameFirst.text.length == 0) && !(self.CPNameLast.text.length == 0)) {
    // primary first name is blank so we don't need the leading space
    CPPart = self.CPNameLast.text;
} else if ((self.CPNameLast.text.length == 0) && !(self.CPNameFirst.text.length == 0)) {
    // primary first name is blank so we don't need the trailing space
    CPPart = self.CPNameFirst.text;
} else if ((self.CPNameFirst.text.length == 0) && (self.CPNameLast.text.length == 0)) {
    // both are blank
    CPPart = @"";
} else {
    // neither are blank
    CPPart = [NSString stringWithFormat:@"%@ %@", self.CPNameFirst.text, self.CPNameLast.text];
}

// generate the secondary client part
if ((self.CSNameFirst.text.length == 0) && !(self.CSNameLast.text.length == 0)) {
    // secondary first name is blank so we don't need the leading space
    CSPart = self.CSNameLast.text;
} else if ((self.CSNameLast.text.length == 0) && !(self.CSNameFirst.text.length == 0)) {
    // secondary first name is blank so we don't need the trailing space
    CSPart = self.CSNameFirst.text;
} else if ((self.CSNameFirst.text.length == 0) && (self.CSNameLast.text.length == 0)) {
    // both are blank
    CSPart = @"";
} else {
    // neither are blank
    CSPart = [NSString stringWithFormat:@"%@ %@", self.CSNameFirst.text, self.CSNameLast.text];
}

// combine the two parts into the final name
if ((CSPart.length == 0) && !(CPPart.length == 0)) {
    // no secondary client names entered
    theName = CPPart;
} else if ((CPPart.length == 0) && !(CSPart.length == 0)) {
    // no primary client names entered
    theName = CSPart;
} else if ((CPPart.length == 0) && (CSPart.length == 0)) {
    // both are blank
    theName = @"New Client";
} else {
    theName = [NSString stringWithFormat:@"%@ and %@", CPPart, CSPart];
}

return theName;
}

有没有更好的方法来做到这一点?

会不会是其他原因导致减速? (设置应用标题不是委托回调……我已经测试过了。)

【问题讨论】:

  • 可能是更适合codereview.stackexchange.com的问题
  • 您是否尝试过使用仪器时间分析器?那应该能够告诉您哪些操作导致了延迟。此外,不需要 allocinit 你的 NSStrings,因为你只是在之后分配它们。
  • 这真的不是看起来很有趣的代码......也许只是在 lastNameIsSet 和 firstNameIsSet 或类似的顶部设置一个 BOOL 。 !(CSPart.length == 0)是太多反转无法阅读,我的大脑变长了,没有零长度,没有不是零长度......这与if(CSPart.length)相同
  • 格雷迪 - 好点。我会清理它。然而,虽然丑陋(不可否认)它是准确的,而且 iPad 阅读它的速度比我们快得多。但是为什么在字段之间点击时会有明显的延迟?这真的应该立即执行,不是吗?
  • JJC - 当我对它进行时间分析时,它不会深入调用 generateAutomaticName(它将其标记为执行 textFieldShouldEndEditing 所花费的 100% 时间)。也许我只是对分析器不够好,无法弄清楚如何深入了解我的功能以查看 IT 是如何超时的。我想我会继续搞砸它。

标签: ios objective-c nsstring uitextfield


【解决方案1】:

正如其中一位评论者所说,Instruments 是您的朋友。您可以通过在 Xcode 的“产品”菜单下选择“配置文件”来使用 Instruments 运行您的应用程序。使用时间分析器模板。

看看你的代码就发现了一些明显的问题:

  • 不要分配/初始化 CPPart 和 CSPart。您将稍后分配它们。 (约定说像这样的局部变量应该以小写开头。)
  • 您计算每个文本字段的长度 3 次。只需执行一次并存储在局部变量中。

我的猜测和其他人一样只是猜测。使用 Instruments 进行分析将准确地告诉您时间花在了哪里。

【讨论】:

  • 试图用 Time Profiler 来解决这个问题,但我不知道如何深入到 generateAutomaticEventName 方法。我会继续搞砸的。
  • 另外,我猜我应该将变量命名为 theCPPart 和 theCSPart。您对命名约定是正确的。我现在已经删除了 alloc/init。我不知道为什么我把它们放在那里。谢谢。
【解决方案2】:

您的代码看起来不错,但无论如何这是一个小优化。

NSArray *array = [NSArray arrayWithObjects:self.CPNameFirst.text, ... all your inputs..., nil];
NSMutableString *str = [[NSMutableString alloc] init];
for (NSString *s in array)
{
    if (s.length>0)
    {
        if (str.length>0)
            [str appendString:@" "];
        [str appendString:s];
    }
}
if (!str.length)
    str = @"new client";
return str;

(可能有一些语法错误,因为我没有对此进行测试。)

【讨论】:

  • 代码看起来不错?还是没有明显检测到错误?
  • @GradyPlayer 好吧,我在原始代码中看不到任何真正的瓶颈,特别是对于今天的处理器。 :)
  • 嗯,没有循环,所以我不知道为什么它会很慢,我怀疑它不是。它会在恒定时间内运行,但仍然不愉快。
  • 这样的循环并不完全有效。我需要在前两部分(或前 1 或无)和后两部分(或发送单个部分)之间插入单词“and”,或者如果根本没有秒部分,则将其省略。这就是为什么我最终将其分解为愚蠢的“如果”语句。不过,如果第二部分有任何内容,也许我可以做两块这样的事情,然后将“和”插入。
  • 哦,就像我在其他 cmets 中所说的那样:我知道这段代码很难看,但它仍然应该在 iPad Air 上立即运行。然而,当我在字段之间点击时,它有点滞后。我不明白。除非可能,只是可能,所有这些“如果”语句都很麻烦。啊。
【解决方案3】:

我无法解决这个问题。我清理了很多代码,当从textFieldShouldEndEditing 调用时,它的执行速度仍然非常缓慢。

我改为在textFieldShouldReturnkeyboardWillBeHidden 中调用,现在速度更快了(尽管它仅在键盘关闭或点击 Return 时执行)。

感谢大家的帮助!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-04
    • 2015-11-02
    • 2011-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多