jjzjj

ios - 使用自定义 getter 和 setter 将消息发送到带有 ARC 的已释放实例

coder 2024-01-16 原文

我正在尝试为我的自定义对象 HFObject 实现自定义 getter 和 setter,尽管使用了 ARC,但我的应用程序因 Message sent to deallocated instance 错误而崩溃。

我已经阅读了每一篇相关的文章,那些在 ARC 之前写的不适用,其他的都没有帮助。我打开了僵尸对象调试器选项。


设置自定义 HObject

在 HObject.h 中我声明了这四个属性:

@property (retain) NSString *email;        //Will use custom getter/setter
@property (retain) NSString *firstName;    //Will use custom getter/setter
@property (retain) NSDate *date;           //Will use custom getter/setter
@property (nonatomic, retain) NSMutableDictionary *values;

在HObject的实现中,我去掉了email的自动获取和设置。 firstNamedate 像这样利用 @dynamic

@dynamic email;
@dynamic firstName;
@dynamic date;

我还在我的 HObject init 中分配了 values 字典

- (id)init {
    self = [super init];

    if (self) {
        self.values = [NSMutableDictionary dictionary];
    }

    return self;
}

实现自定义 Getter 和 Sender

对于我的自定义 getter/setter。我已经覆盖了

- (NSMethodSignature *)methodSignatureForSelector:(SEL)选择器

- (void)forwardInvocation:(NSInvocation *)invocation

如下图:

- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector
{
    NSString *sel = NSStringFromSelector(selector);
    if ([sel rangeOfString:@"set"].location == 0) {
        return [NSMethodSignature signatureWithObjCTypes:"v@:@"];
    } else {
        return [NSMethodSignature signatureWithObjCTypes:"@@:"];
    }
}

- (void)forwardInvocation:(NSInvocation *)invocation
{
    NSString *key = NSStringFromSelector([invocation selector]);
    if ([key rangeOfString:@"set"].location == 0) { 
        key = [key substringWithRange:NSMakeRange(3, [key length]-4)]; 

        id obj;   
        [invocation getArgument:&obj atIndex:2];   

        [self.values setObject:obj forKey:key];
    } else {
        id obj = [self.values objectForKey:key];

        [invocation setReturnValue:&obj];
    }
}

我在这里要做的是将属性的所有值存储到我的 values 字典中,并从那里检索它们。


应用崩溃

在我的 View Controller 的实现中,我尝试创建一个 HObject 并为我的属性设置值,然后我记录值字典以查看我的所有值。

- (void)buttonPressed:(id)sender {
    HObject *obj = [[HObject alloc] init];

    NSString *name = @"this is a string object";
    obj.date = [NSDate date];
    obj.email = @"email@website.com";
    obj.firstName = [NSString stringWithFormat:@"%@", name];


    NSLog(@"Values %@", [obj values]);
}

此时应用程序崩溃,这是我的控制台日志

2014-07-27 04:12:37.899 App[61501:60b] Values {
    Date = "2014-07-27 08:12:37 +0000";
    Email = "email@website.com";
    FirstName = "this is a string object";
}
2014-07-27 04:12:37.901 HeadsUp[61501:60b] *** -[CFString release]: message sent to deallocated instance 0x109473fe0

如果您能从这里帮助我,我将不胜感激。我还包括我的调试过程,以防对您有所帮助


我的调试过程(很长,如果你能帮到我就跳过)

我最初创建了许多这样的对象并将它们存储在一个数组中,当我这样做时,与创建单个对象相反。我的应用程序崩溃有点不同。

我的数组:

@property (nonatomic, strong) NSArray *array;

方法:

- (void)createArray
{
    int i = 1; //number of testobjs

    NSMutableArray *objects = [NSMutableArray arrayWithCapacity:i];

    for (int j = 0; j<i; j++) {
        HFObject *obj = [[User alloc] init];

        NSString *name = @"this is a string object";
        [obj setObject:[NSDate date] forKey:@"Date"];
        obj.email = @"email@website.com";
        obj.firstName = [NSString stringWithFormat:@"%@", name];

        [objects addObject:obj];
    }


    self.array = [NSArray arrayWithArray:objects];

}

- (void)buttonPressed:(id)sender {
    HObject *object = [self.array objectAtIndex:0];

    NSLog(@"Values %@", [object values]);
}

崩溃日志:

2014-07-27 04:34:02.893 App[61623:60b] *** -[CFString isNSString__]: message sent to deallocated instance 0x1094988f0
(lldb) 

现在这个崩溃日志几乎和之前的一样了,除了它没有记录 [object values]

中的值

稍微调查一下这个问题,我查看了调试器的左侧窗口(不确定它实际上叫什么),我看到了这个:

(将 HFObject 视为 HObject 并将 dirtyValues 视为 values;出于演示目的,我将它们重命名)

您可以看到在键 @"FirstName" 下没有任何值。

我做了几个类似的测试,在这些测试中我更改了我正在设置的属性的值并更改了数据类型。通常情况下,不仅 FirstName 没有值,Date 也没有。然而,电子邮件的值(value)始终存在。

在研究了 dataTypes 之后,我意识到这是因为 email 是一个 string literal 无法释放。另一方面,firstNamedate 是可以释放的对象。

崩溃日志引用了一个 CFString 属性,我了解到它不使用 ARC。我从未创建过 Core Foundation 对象,所以我着手通过记录 [obj class] 来发现它是在 setter 中创建的:

- (void)forwardInvocation:(NSInvocation *)invocation
{
    NSString *key = NSStringFromSelector([invocation selector]);
    if ([key rangeOfString:@"set"].location == 0) { 
        key = [key substringWithRange:NSMakeRange(3, [key length]-4)]; 

        id obj;   
        [invocation getArgument:&obj atIndex:2];   

        NSLog(@"%@", [obj class]);  //I ADDED THIS LOG

        [self.values setObject:obj forKey:key];
    } else {
        id obj = [self.values objectForKey:key];

        [invocation setReturnValue:&obj];
    }
}

再崩溃一次后,我得到了obj

2014-07-27 04:58:03.893 HeadsUp[61765:60b] __NSDate
2014-07-27 04:58:03.894 HeadsUp[61765:60b] __NSCFConstantString
2014-07-27 04:58:03.894 HeadsUp[61765:60b] __NSCFString
2014-07-27 04:58:03.904 HeadsUp[61765:60b] *** -[__NSDate release]: message sent to deallocated instance 0x109554370
(lldb) 

在这里您可以看到 Date 由于某种原因正在被释放,我的字符串现在是 __NSCF 字符串。

我尝试使用 (__brigde NSString *)obj 将字符串重置为 NSStrings 以及您可以将 CF 对象桥接至 ARC 的所有其他可能方法,但是没有要么工作。

这是我所做的一切。我感谢所有帮助。

最佳答案

问题出在这里:

id obj;   
[invocation getArgument:&obj atIndex:2];

getArgument 只是将对象指针复制到 obj 中而不保留它。 但是,由于 obj 是(默认情况下)一个 __strong 变量,它将在 当前方法的结束。要解决这个问题,请使用

__unsafe_unretained id obj;   
[invocation getArgument:&obj atIndex:2];   

另请注意,您的 getter 实现不起作用。例如,setFirstName: 使用键“FirstName”将键存储在字典中,但是 getter firstName 尝试读取键“firstName”的值。

(正如评论中已经提到的那样,它可能会更容易且更不容易出错 只是分别覆盖三个属性的访问器方法,而不是 动态转发。)

关于ios - 使用自定义 getter 和 setter 将消息发送到带有 ARC 的已释放实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24979501/

有关ios - 使用自定义 getter 和 setter 将消息发送到带有 ARC 的已释放实例的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  3. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  4. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  5. ruby - 在 Ruby 中使用匿名模块 - 2

    假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

  6. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  7. ruby - Facter::Util::Uptime:Module 的未定义方法 get_uptime (NoMethodError) - 2

    我正在尝试设置一个puppet节点,但ruby​​gems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由ruby​​gems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby

  8. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  9. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  10. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

随机推荐