【问题标题】:Extension Property Crashes In NSString CategoryNSString 类别中的扩展属性崩溃
【发布时间】:2015-05-25 05:51:55
【问题描述】:

我刚刚在Category 类中为NSString 类创建了一个Extension

#import "NSString+Name.h"

@interface NSString(Name)

@property (nonatomic, retain) NSString *var;

@end

但是当我尝试访问类别类中的私有变量时,应用程序崩溃并给出错误。

@implementation NSString (Name)

- (NSString*)newString{

    [self setVar:@"Its a new string"];    // Crashes here

    NSLog(@"name = %@",self.var);

    return self.var;
}

@end

崩溃原因

无法识别的选择器发送到实例 0x1023641c8 2015-05-25 11:12:49.246 Tute[710:14433] *** 由于未捕获而终止应用程序 异常“NSInvalidArgumentException”,原因: '-[__NSCFConstantString setVar:]: 无法识别的选择器发送到 实例 0x1023641c8'

如果我能够在该变量中分配值,那么为什么它说无法识别的选择器

【问题讨论】:

  • 你试过用[self setvar:@"Its a new string"];
  • 正如@Ghanshyam 在他的回答中提到的,您必须访问 _var = @"Its a new string";这将成功设置新字符串
  • @Kamarshad 我无法访问 _var 它只允许我访问 self.var
  • 字符串不会被初始化,所以你不能给它赋值。
  • 它已初始化,这就是我能够调用 newString 方法的原因。

标签: ios objective-c iphone nsstring


【解决方案1】:

您应该使用关联对象。在下面找到对我有用的代码:

.h

@interface NSString (Name)

@property (nonatomic, assign)NSString *var;
- (NSString*)newString;
@end

.m

static char const * const Key = "SomeKey";

@implementation NSString (Name)

- (NSString*)newString
{
    self.var = @"Its a new string";
    NSLog(@"name = %@",self.var);

    return (self.var);
}

- (void)setVar:(NSString *)aVar {
    objc_setAssociatedObject(self, Key, aVar, OBJC_ASSOCIATION_ASSIGN);
}

- (NSString*)var {
    return (NSString*)objc_getAssociatedObject(self, Key);
}

请参阅hereherehere

【讨论】:

  • 这是在Apple create Classes中添加变量的最佳方式link
  • 对于未来的读者来说,key(“SomeKey”)的值并不重要,因为你只是使用key的地址,因此我只使用static void * const kAssociatedStorageKey = (void*)&kAssociatedStorageKey;
【解决方案2】:

您尝试执行的操作存在一些问题。

  1. 您不能按惯例将属性添加到类别中。

来自 Apple 的 [Programming with Objective C][1] 文档:

类别可用于声明实例方法或类方法,但通常不适合声明附加属性。

一个类别可以添加一些称为关联对象的东西,但它的主要目的是添加方法。

  1. 类实例方法中的self引用实例变量

类别实例方法(以 - 开头的方法)对调用该方法的实例变量进行操作。在实例方法中,self 指的是调用者实例变量,而不是类(或您尝试访问的类别属性)。

在您的类别示例中,您将从现有的 NSString 调用 newString,如下所示:

NSString *myString = @"foo";
[myString newString];

换句话说,newString 类别扩展对调用它的字符串进行操作。您可以更改该字符串,或返回不同的结果,但问题是您正在对没有此类 var 属性或方法的 NSString 进行操作。

这就是为什么您会看到“没有这样的选择器消息”,因为 NSString 对您碰巧添加到类别中的不相关属性一无所知。

  1. 以 new 开头的方法对 ARC 具有特定含义。

另一个问题是,您使用“新”开始了该方法。 Objective-C 有一些与内存管理策略有关的特定命名约定。使用 alloc、new、copy 或 mutableCopy 启动方法会隐式告诉 ARC,您的方法(已创建并且)正在返回一个保留对象。您的 newString 方法没有创建对象。

【讨论】:

    【解决方案3】:

    使用 _ 而不是 self 它将进入无限循环

    - (NSString*)newString
    {
    
        _var = @"Its a new string";
        NSLog(@"name = %@",_var);
    
        return (self.var);
    }
    

    【讨论】:

    • 我无法访问 _var 它只允许我访问 self.var 或 [self var]
    • 在 .h 中公开定义在 .m 中声明是否有某种目的?
    猜你喜欢
    • 1970-01-01
    • 2013-02-25
    • 2019-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多