【问题标题】:Can a method return an NSRange?方法可以返回 NSRange 吗?
【发布时间】:2010-04-07 20:57:40
【问题描述】:

我有一个返回 NSRange 的方法。当我从类外部调用此方法时,出现编译错误。

NSRange tmpRange;
tmpRange = [phrase rangeInString:searchString forString:theLetter goingForward:YES];
return tmpRange.location == -1;

在 .h 文件中:

#import <Foundation/Foundation.h>


@interface Phrase : NSObject {

}
- (NSRange) rangeInString:(NSString *) tgt forString:(NSString *) find goingForward:(BOOL) fwd;  

@end

此方法在 Phrase 对象中由其他方法调用,没有问题。编译器说“分配中的类型不兼容”。

谁能给我解释一下?我认为它与返回在对象外部生成的 NSRange/struct 类型值有关,但我不知道为什么它在一个地方而不是另一个地方工作。

【问题讨论】:

  • 请注意,对于无效的NSRange,通常应该使用NSNotFound 作为location 字段值。
  • 嗯——由于各种低质量的原因,我实际上将位置值用作一种错误代码:-1 就是这样一个代码。所有代码都小于零。这实际上与错误没有任何关系,因为编译器不知道在运行时将返回什么。但这就是为什么我不使用 NSNotFound...
  • 位置变量被定义为一个 NSUInteger,所以它永远不会小于零。你应该使用 NSNotFound。
  • 但这与为什么在编译时应该为简单地转储方法结果的赋值抛出错误完全无关:一种在定义它的类中工作正常的方法。它可以'不知道返回的值是什么。

标签: iphone objective-c cocoa cocoa-touch macos


【解决方案1】:

当然方法可以返回 NSRange。但是返回结构需要特别注意编译器,因为调用方法的方式通常不同(objc_msgSend_stretobjc_msgSend)。

请确保将phrase 声明为

Phrase* phrase = ...;

以便编译器知道 -rangeInString:… 返回的是 NSRange,而不是

id phrase = ...;

(另外,由于您没有显示编译器错误的哪一行,请确保使用 return … == -1; 的函数返回的是 BOOL 而不是 NSRange。)

【讨论】:

  • 您还需要确保将包含Phrase接口的头文件导入到调用该方法的文件中。
  • 短语已导入——请参阅下面的评论。已经声明了 Phrase 的实例,并且在同一类的其他地方,在其他方法中对 Phrase 实例进行了多次引用。引发错误的那一行是将 tmpRange 分配给方法调用的结果。
  • @Dan:你如何声明变量 phrase
【解决方案2】:

方法可以返回 NSRange 吗?

是的。

此方法在 Phrase 对象中由其他方法调用,没有问题。 …当我从类外部调用这个方法时,我得到一个编译错误。 … 编译器说“赋值中的类型不兼容”。

记得将#importPhrase.h 加入到您正在与 Phrase 对象对话的实现文件中。否则,编译器不知道您的rangeOfString:forString:goingForward: 方法,并且假定它返回id。它需要头文件中的@interface知道该方法返回NSRange

假设您的短语对象在一个实例变量中,您可能在声明 ivar 的头文件中使用 @class Phrase; 声明了 Phrase 类。那是一个前向声明;它告诉编译器存在一个名为“Phrase”的类(因此像Phrase *myPhrase 这样的声明将是合法的),但它不会告诉编译器有关它的任何其他信息。为此,您需要导入标头。

对于知道类 B 的实例的类 A 的实例,一般规则是 A 的标头 (A.h) 使用 @class 前向声明类 B,而 A 的实现 (A.m) 导入 B 的标头 (B.h) .

另一种情况是 A 是 B 的子类。您需要 @interface 来创建子类,因此在这种情况下,仅在这种情况下,A.h 必须导入 B.h。由于是为 B 导入头部,所以不需要前向声明 B。

【讨论】:

  • 其实Phrase类是导入的,不是用@class声明的。非 Phrase 类导入 Phrase,而 Phrase 不导入其他类(只是 Foundation)。 Phrase 声明返回值是一个 NSRange。调用 Phrase 类方法的类在自身内部存储了一个 Phrase 的实例,称为短语。
【解决方案3】:

我不认为这是答案,但 NSRange.location 被声明为 NSUInteger。通过将其与 -1 进行比较,您将无符号值与有符号值进行比较。

我能想到的唯一其他答案是,您从中进行调用的 .m 文件没有导入标头 Phrase.h。现在,我知道你相信它有,但编译器却另有说法。尝试在文件上运行预处理器以查看它实际导入的内容。 (右键单击包含 .m 文件的编辑器 - 预处理位于弹出的上下文菜单底部附近)。

【讨论】:

    【解决方案4】:

    是的,您可以在方法中返回 C 结构。那不是问题。此外,位置是一个 NSUInteger,永远不会是 -1。使用 NSNotFound 进行测试。

    您的 Phrase 对象的实例是如何键入的?您是否使用id 而不是Phrase *?您是否正确导入了 Phrase 标头?

    您应该向我们提供有关导致编译错误的代码的更多信息。

    【讨论】:

      【解决方案5】:

      回答一些即将提出的问题:

      #import <Foundation/Foundation.h>
      #import "OverlayView.h"
      #import "Phrase.h"
      #import "TimerPaneView.h"
      

      是 MainPane.h 中的标头,是进行调用的类标头。

      在 MainPane.h 的头文件中,声明了短语:

          Phrase              *phrase;
      

      在实现文件中,是的,它导入了 MainPane 标头:

      phrase = [[Phrase alloc] init];
      

      是如何在 initWithFrame 方法中实例化短语类。我把这句话对象引用了几十次,调用了方法,引用了这个类中的属性,没有问题。不,在 dealloc 之前永远不会释放短语对象。

      -- 补充说:我以为我找到了问题所在:一段折叠的代码从未被调用过,它的旧返回值为 BOOL。此方法最初返回 BOOL,但已被转换。但是我消除了它,问题仍然存在。

      我也应该说我已经重构了解决这个问题的方法,但这仍然是一个谜......

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-09-27
        • 2011-12-10
        • 1970-01-01
        • 2012-06-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-02-15
        相关资源
        最近更新 更多