【问题标题】:Comparing objects in Obj-C, why they don't match?比较 Obj-C 中的对象,为什么它们不匹配?
【发布时间】:2015-09-18 20:33:30
【问题描述】:

赏金通知

你好!我开始对这个问题给予赏金,因为人们不会阅读整个问题,也不会试图了解问题的根源。或者,不知道这里发生了什么。需要更详细的方法。谢谢!

结束

当我使用自定义任务调用 NSURLSession 时 - 我将这些任务存储在字典中。当我收到委托回电时,我需要找到它与哪个任务有关。这是我的做法:

- (NSInteger)getOperationIdentifierForTask:(NSURLSessionTask*)task
{
    for (NSString *key in self.operations)
    {
        HttpTaskOperation *value = [self.operations objectForKey:key];
        if (value.task == task) return [key integerValue]; //**********
    }

    return 0;
}

它以前对我有用(肯定是 iOS7),但现在这种比较从未成功。我还从当地人那里截取了屏幕截图,请参阅突出显示的对象 ID。是的,我不是 C 开发人员,所以它可能与问题有关 :) 我认为这是由于指针问题..

当带有 //***** 的代码行执行时 - 我没有得到匹配。这个函数总是返回 0。

编辑:

似乎与代理有关的问题。 iOS 在我创建和存储 NSURLSession 时实际上返回 NSProxy。 NSUURLSessionTask 也一样。 这一切都是新事物吗?鉴于您在当地人看到的情况,我如何比较这些对象?我需要得到task._taskDelegate,但它没有暴露出来..

【问题讨论】:

  • 你不是在比较_task(0x787346a0)和task(0x78753180)吗? _task.taskDelegate 与 _task 不同
  • 你不是在比较taskDelegate;您正在比较 task 本身。试试if (value.task.taskDelegate == task) {...}
  • 没有足够的上下文来回答这个问题。您有一个指针 task 被传递给该方法,以及一个预期包含相同指针的数组。然而,如果不知道指针来自哪里,或者数组是如何填充的,就无法知道这种期望是否合理。
  • 查看我的编辑,我在运行时显示比较线的本地人和 sn-ps - 它们(左侧和右侧)都显示相同的 id
  • 局部变量的截图和其他两张截图有矛盾。具体来说,最后一个屏幕截图将value.task 显示为0x78690480。但是在局部变量中,您突出显示了value.task.taskDelegate

标签: ios objective-c


【解决方案1】:

目前尚不清楚您是如何向operations 添加项目的。

此行具有误导性:

for (NSString *key in self.operations)

因为在您的调试跟踪中,您的密钥似乎实际上是 operations 中的 NSNumber。

您为什么不尝试使用taskIdentifier。它应该唯一标识会话中的任务。

- (NSInteger)getOperationIdentifierForTask:(NSURLSessionTask*)task
{
    NSNumber * value = self.operations[@(task.taskIdentifier)];

    if( value == nil )
         return 0;

    return value.integerValue;
}

【讨论】:

  • String 是因为它是一个 NSMutableDictionary。我将所有 NSURL 任务包装到 NSOperations 中。但问题是 - 当我收到 NSURLSession 的回电时 - 他们只传回任务。本质上我在这种方法中所做的 - 试图匹配哪个 NSOperation 携带 NSURLSessionTask.. 但似乎我创建的所有 NSURLSessionTasks 都被包装到 NSProxy 中,这反过来又导致了我遇到的问题。我不知道为什么它以前有效。本质上,我需要以某种方式从 NSProxy 中提取“真实”对象
  • 致投票者:NSURLSessionTask.taskIdentifier 是操作系统设置的只读属性。我自己用不了。
  • 您的回答确实为我指明了正确的方向,我一开始没有得到它,我真的不需要设置 taksIdentifier。因此,它可以修复和解决问题。如果没有人回答我为什么开始有这个问题的完整解释,我会奖励你,因为它之前工作得很好..
【解决方案2】:

您不能对非原始对象使用原始相等检查==。你应该使用isEqual:。在您的子类中覆盖它并比较需要相同的项目的任何属性以确保相等。

在你的子类中做这样的事情:

-(BOOL)isEqual:(id)object{
    if([object isKindOfClass:[YourSubClass class]]){
        YourSubClass *otherObject = (YourSubClass*)object;

        NSInteger currentDistinctiveNumber = [self.someDistinctiveProperty integerValue];
        NSInteger otherDistinctiveNumber = [otherObject.someDistinctiveProperty integerValue];
        if(currentDistinctiveNumber == otherDistinctiveNumber){
            return YES;
        }
    }

    return NO;
}

【讨论】:

  • 不幸的是我做不到。这是 NSURLSessionTask,没有我可以锁定的属性..
  • 如果不是自定义的,那么就使用 isEqual:。你不需要重写,Apple 已经为你完成了这项工作。
  • isEqual 也不比较,结果相同
【解决方案3】:

如果您确定它可以在 iOS 7 中运行,并且我在这里猜测,那么在过渡到 iOS 9 之前您没有任何问题,我会说这个问题可能是由Apple的新App Transport Security引起的。

原因:

在 iOS 9 和 OS X 10.11 中,Apple 引入了应用传输安全 (ATS),这是一组对应用网络连接的低级限制。这些限制中最明显的一项是要求应用程序不再通过纯 HTTP 建立连接。相反,除非另有明确说明,否则操作系统会强制使用 HTTPS。

从您提供的屏幕截图来看,您指向的 URL 似乎是基于 http:// 的 URL,而不是 https://。我这样说是因为您的问题似乎始于HTTPTaskOperation

修复:

将以下字典添加到您应用的 .plist 文件中:

这完全取消了 Apple 的新安全 (ATS)

如果这是一个问题,或者如果它仍然无法正常工作,您需要调整 Exceptions 以适应您的项目需求。查看之前的链接,或阅读 Apple 的 App Transport Security documentation

.

如果不是 iOS 9 ATS 问题

~已添加~

This堆栈溢出问答给出如下解释:

如果您使用的是基于委托的实现,那么事情很快就会变得非常棘手。这是因为 NSURLSession 的一个可以理解的(但令人难以置信的)特性,任务级的委托是在会话级实现的。 (想一想:需要不同处理的两个不同请求在共享会话对象上调用相同的委托方法。Egad!)

可以在操作中包装一个基于委托的 NSURLSessionTask(...),但它涉及一个笨拙的过程,即让会话对象维护一个字典,将任务标识符与任务操作对象交叉引用,让它传递这些任务委托方法传递给任务对象,然后让任务对象符合各种 NSURLSessionTask 委托协议。这是一个相当大的工作量,因为 NSURLSession 没有在会话中提供 maxConcurrentOperationCount 样式的功能(更不用说其他 NSOperationQueue 的优点,比如依赖项、完成块等)

【讨论】:

  • 我用 .plist 添加的图片编辑了我的帖子
  • 克里斯,这不是 ATS 问题(我确实有这个问题,因为我使用 SSL,但它是固定的,与 Q 无关。你在第二部分中解释的正是我所做的,我包装到 NSOperationQueue ,上面的那个函数正是它的本质——用 NSURLSessionTask 交叉引用 NSOperation
【解决方案4】:

Objective-C 中的“==”运算符检查两个变量是否指向完全相同的对象。如果您有 2 个包含相同数据的不同对象,则测试将失败。

正如其他人所说,您应该为您的自定义子类实现 isEqual 方法,或者如果您没有简单的方法来子类化/向您的类添加类别,您可以创建一个全局函数,该函数需要 2 个您的对象作为参数并返回一个 BOOL,告诉您它们是否等效。

【讨论】:

  • 这是完全相同的对象,这就是我想要弄清楚的。请参阅我在比较的地方添加了屏幕截图。它是同一个对象,但不返回..
【解决方案5】:

'==' 在objective-c 中测试对象的引用相等性。这意味着它检查两个对象是否是相同的对象,而不是它们的值是否相同。尝试使用对象 isEqualTo: 函数。如果它是您自己的对象,请编写一个 isEqualTo: 函数来测试该对象中某个值的相等性。

【讨论】:

    【解决方案6】:

    也许您可以在存储操作之前将每个任务的唯一标识符存储在NSURLSessionTasktaskDescription 属性中,然后使用该值进行比较。该值应保持不变,从而避免在传递的对象之间进行指针比较。

    【讨论】:

      猜你喜欢
      • 2015-06-07
      • 2010-12-25
      • 2022-03-30
      • 2011-11-11
      • 1970-01-01
      • 1970-01-01
      • 2013-08-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多