菜鸟教程小白 发表于 2022-12-13 08:45:57

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


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

<p>我已经阅读了所有相关的帖子,在 ARC 之前编写的那些不适用,其他所有内容都没有帮助。我打开了僵尸对象调试器选项。</p>

<hr/>

<h2>设置自定义 HObject</h2>

<p>在 HObject.h 中我声明了这四个属性:</p>

<pre><code>@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;
</code></pre>

<p>在HObject的实现中,我去掉了<code>email</code>的自动获取和设置。 <code>firstName</code> 和 <code>date</code> 像这样使用 <code>@dynamic</code></p>

<pre><code>@dynamic email;
@dynamic firstName;
@dynamic date;
</code></pre>

<p>我还在我的 HObject init 中分配 <code>values</code> 字典</p>

<pre><code>- (id)init {
    self = ;

    if (self) {
      self.values = ;
    }

    return self;
}
</code></pre>

<hr/>

<h2>实现自定义 Getter & Sender</h2>

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

<p><code>- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector</code> </p>

<p>和</p>

<pre><code>- (void)forwardInvocation:(NSInvocation *)invocation
</code></pre>

<p>如下图:</p>

<pre><code>- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector
{
    NSString *sel = NSStringFromSelector(selector);
    if (.location == 0) {
      return ;
    } else {
      return ;
    }
}

- (void)forwardInvocation:(NSInvocation *)invocation
{
    NSString *key = NSStringFromSelector();
    if (.location == 0) {
      key = -4)];

      id obj;   
      ;   

      ;
    } else {
      id obj = ;

      ;
    }
}
</code></pre>

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

<hr/>

<h2>应用程序崩溃</h2>

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

<pre><code>- (void)buttonPressed:(id)sender {
    HObject *obj = [ init];

    NSString *name = @&#34;this is a string object&#34;;
    obj.date = ;
    obj.email = @&#34;[email protected]&#34;;
    obj.firstName = ;


    NSLog(@&#34;Values %@&#34;, );
}
</code></pre>

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

<pre><code>2014-07-27 04:12:37.899 App Values {
    Date = &#34;2014-07-27 08:12:37 +0000&#34;;
    Email = &#34;[email protected]&#34;;
    FirstName = &#34;this is a string object&#34;;
}
2014-07-27 04:12:37.901 HeadsUp *** -: message sent to deallocated instance 0x109473fe0
</code></pre>

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

<hr/>

<h2>我的调试过程(很长,如果您已经可以帮助我,请跳过)</h2>

<p>我最初创建了许多这样的对象并将它们存储在一个数组中,当我这样做时,而不是创建单个对象。我的应用崩溃了一点。</p>

<p>我的数组:</p>

<pre><code>@property (nonatomic, strong) NSArray *array;
</code></pre>

<p>方法:</p>

<pre><code>- (void)createArray
{
    int i = 1; //number of testobjs

    NSMutableArray *objects = ;

    for (int j = 0; j&lt;i; j++) {
      HFObject *obj = [ init];

      NSString *name = @&#34;this is a string object&#34;;
       forKey:@&#34;Date&#34;];
      obj.email = @&#34;[email protected]&#34;;
      obj.firstName = ;

      ;
    }


    self.array = ;

}

- (void)buttonPressed:(id)sender {
    HObject *object = ;

    NSLog(@&#34;Values %@&#34;, );
}
</code></pre>

<p>崩溃日志:</p>

<pre><code>2014-07-27 04:34:02.893 App *** -: message sent to deallocated instance 0x1094988f0
(lldb)
</code></pre>

<p>现在这个崩溃日志几乎和之前一样了,除了这没有记录 <code></code></p> 里面的值

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

<p> <img src="/image/vjRpb.png" alt="()"/> </p>

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

<p>您可以看到在 <code>@"FirstName"</code> 键下没有任何值。</p>

<p>我做了几个类似的测试,我更改了我正在设置的属性的值并更改了数据类型。很多时候,不仅<code>FirstName</code> 没有值,<code>Date</code> 也没有。但是,电子邮件的值(value)始终存在。</p>

<p>在研究了 dataTypes 之后,我意识到这是因为 <code>email</code> 是一个无法释放的 <code>string literal</code>。另一方面,<code>firstName</code> 和 <code>date</code> 是可以释放的对象。</p>

<p>崩溃日志引用了一个 <code>CFString</code> 属性,我了解到它不使用 ARC。我从未创建过 Core Foundation 对象,所以我开始通过记录 <code></code>:</p> 来发现它是在 setter 中创建的

<pre><code>- (void)forwardInvocation:(NSInvocation *)invocation
{
    NSString *key = NSStringFromSelector();
    if (.location == 0) {
      key = -4)];

      id obj;   
      ;   

      NSLog(@&#34;%@&#34;, );//I ADDED THIS LOG

      ;
    } else {
      id obj = ;

      ;
    }
}
</code></pre>

<p>再次崩溃后,我得到了 <code>obj</code> 类</p>

<pre><code>2014-07-27 04:58:03.893 HeadsUp __NSDate
2014-07-27 04:58:03.894 HeadsUp __NSCFConstantString
2014-07-27 04:58:03.894 HeadsUp __NSCFString
2014-07-27 04:58:03.904 HeadsUp *** -: message sent to deallocated instance 0x109554370
(lldb)
</code></pre>

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

<p>我尝试使用 <code>(__brigde NSString *)obj</code> 将字符串重置为 <code>NSStrings</code> 以及您可以将 CF 对象桥接到 ARC 的所有其他可能方式,但这并没有也可以工作。</p>

<p>这是我所做的一切。我感谢任何和所有的帮助。</p></p>
                                    <br><hr><h1><strong>Best Answer-推荐答案</ strong></h1><br>
                                            <p><p>问题出在这里:</p>

<pre><code>id obj;   
;
</code></pre>

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

<pre><code>__unsafe_unretained id obj;   
;   
</code></pre>

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

<p>(正如评论中已经提到的那样,它可能会更容易且不易出错
只是分别覆盖三个属性的访问器方法,而不是
动态转发。)</p></p>
                                   
                                                <p style="font-size: 20px;">关于ios - 使用自定义 getter 和 setter 将消息发送到带有 ARC 的已释放实例,我们在Stack Overflow上找到一个类似的问题:
                                                        <a href="https://stackoverflow.com/questions/24979501/" rel="noreferrer noopener nofollow" style="color: red;">
                                                                https://stackoverflow.com/questions/24979501/
                                                        </a>
                                                </p>
                                       
页: [1]
查看完整版本: ios - 使用自定义 getter 和 setter 将消息发送到带有 ARC 的已释放实例