【问题标题】:Building a NSURL from a NSString and NSUserDefaults broken since Xcode 5 & Mavericks从 Xcode 5 和 Mavericks 以来损坏的 NSString 和 NSUserDefaults 构建 NSURL
【发布时间】:2013-11-26 04:36:09
【问题描述】:

我们公司使用的 Mac 应用程序过去可以在 OS X Mountain Lion 中完美运行。升级到 OS X Mavericks 后,它停止工作。由于我们还没有全部升级,我们可以清楚地看到,在 ML 机器上它仍然可以工作,而在 Mavericks 机器上却不行。

深入研究代码并从 Xcode 5 运行它,很快就发现以下负责构建对 Trello 的 API 调用的代码块的行为与预期不符:

NSString *token = [[NSUserDefaults standardUserDefaults] objectForKey:TRELLOTOKEN];    

NSLog(@"TOKEN: %@", token);    

NSString *urlString = [NSString stringWithFormat:@"/1/cards/%@/idList?value=%@&key=%@&token=%@", taskID, DOINGLISTID, TRELLOKEY, token];    

NSLog(@"URLSTRING: %@", urlString); 

NSURL *url = [NSURL URLWithString:urlString relativeToURL:[NSURL URLWithString:TRELLOLOGENDPOINT]];  

NSLog(@"URL: %@", url);

输出:

TOKEN: thetokenstring
URLSTRING: /1/cards/.../idList?value=...&key=...&token=thetokenstring
URL: (null)

我将 taskID、DOINGLISTID、TRELLOKEY 变量更改为 ... 以保持简短和匿名。 我可以保证键不包含需要转义的字符(它们也需要在 ML 中转义)。

问题是我的 url 变量在使用 NSURL URLWithString 函数分配后仍然为空。

有一种方法可以解决这种情况,只需将字符串分配给 NSString *token 变量。因此,如果我们将第一行替换为:

NSString *token = @"thetokenstring";

然后就可以了。如果愿意,您可以简单地从 NSLog 输出中复制粘贴令牌。

输出:

TOKEN: thetokenstring
URLSTRING: /1/cards/.../idList?value=...&key=...&token=thetokenstring
URL: /1/cards/.../idList?value=...&key=...&token=thetokenstring -- https://trello.com

显然我需要来自 NSUserDefaults 的令牌。

有人能解释一下吗?我想知道为什么这不起作用(不再起作用)以及如何解决它。

我已经尝试了以下方法:

  • 将 NSUserDefaults 结果显式转换为 NSString。
  • 使用以下命令初始化 NSString *token:

    [NSString stringWithString:...]

不幸的是没有运气......

【问题讨论】:

  • 这是一个有点奇怪的建议,但请尝试NSLog(@"%@", [NSArray arrayWithObject:token]);。数组描述使用旧式 ASCII plist 格式,如果token 包含您不期望的内容,它将突出显示。我想我也会登录[token class]

标签: objective-c nsuserdefaults xcode5 nsurl osx-mavericks


【解决方案1】:

好的,我找到了解决方案。基于 Ken Thomases 的出色评论。

原来令牌包含换行符。听起来很愚蠢吧?这可能是因为在用户授权应用程序后,我必须从一个非常简单的页面的 DOM 中过滤代码。

我想 NSURL 的实现发生了一些变化,因此它不允许在 url 字符串的末尾使用换行符(它不应该)。不过,我不会排除任何其他可行解释的存在。

【讨论】:

  • 如果NSURL 的实现以这种方式发生变化,我会感到非常惊讶。发行说明中提到它之前没有正确检查单个字符串,但除此之外没有任何内容
  • 好吧,看来我别无选择,只能感到非常惊讶。我的测试表明,在 10.9 之前,+URLWithString: 和朋友们会欣然允许 last 字符为任何字符,如果需要,可以对其进行百分比编码。 any 其他位置的无效字符将导致返回nil。我怀疑发行说明不够广泛
【解决方案2】:

代码似乎没问题!
无论如何,你可以用这个替换第一行,看看它是否有效:

NSString *token = [[[NSUserDefaults standardUserDefaults] objectForKey:TRELLOTOKEN] description];

这只是一个想法,可能是这样,也可能不是!我的想法是您使用的方法是返回(id),可以将其传递给NSString,它应该可以在NSLog 消息(以及以前的操作系统)的输出中工作。 description 方法只返回(NSString *),它与令牌对象相同。 (id) 是动态类型,可能会导致一些问题。最好按照您想要返回的方式编写代码 NSString
顺便说一句,[[NSUserDefaults standardUserDefaults] objectForKey:TRELLOTOKEN] 可能会返回nil(取决于您的代码逻辑!)。所以最好像这样使用它:

NSString *token;
NSObject *tokenObj = [[NSUserDefaults standardUserDefaults] objectForKey:TRELLOTOKEN];
if (token != nil) {
    token = [tokenObj description];
} else {
    token = @"";
}
NSString *urlString = [NSString stringWithFormat:@"/1/cards/%@/idList?value=%@&key=%@&token=%@", taskID, DOINGLISTID, TRELLOKEY, token];    
NSURL *url = [NSURL URLWithString:urlString relativeToURL:[NSURL URLWithString:TRELLOLOGENDPOINT]];
NSLog(@"URL: %@", url);

希望能解决您的难题! ;)

【讨论】:

  • 为什么要替换第一行?请给出一个理由,不要只是说这样做,也不要解释为什么 -1 基于如果改进我将删除。
  • 您使用的方法是返回 (id),可以将其传递给 NSString,它应该像在输出 NSLog 消息(以及以前的操作系统)中一样工作。 description 方法只返回 (NSString *) 这是同一种令牌对象。 (id) 是动态类型,我的原因是一些问题。这只是一个简单的想法!我得出的结论可能不是这里的情况!
  • 请更新您的答案。如果返回的东西没有description 方法怎么办?如果 nil 返回为 nil 没有 description 会发生什么代码将在此行崩溃。
  • Objectiv-C 世界中的任何对象都有描述方法。顺便说一句,您可以覆盖 description 方法以返回适合您的 NSString 。当您(在您的代码中)将输出分配给 NSString 对象(令牌)时,您实际上是在放置描述方法返回的内容。但是在这里你说我希望输出类型特别是 NSString 而不是(id)!您至少可以尝试一下并给出问题解决或仍然保持不变的反馈吗?
  • 顺便说一句!你可以在 nil 对象上调用任何你喜欢的方法!它不会做任何事情! NSObject * theNullObject = nil; [theNullObject description];
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-08-05
  • 2014-03-20
  • 1970-01-01
  • 2014-02-04
  • 2012-11-10
  • 2018-11-08
  • 2012-02-02
相关资源
最近更新 更多