处理ARC中的指针对指针所有权问题 [英] Handling Pointer-to-Pointer Ownership Issues in ARC

查看:138
本文介绍了处理ARC中的指针对指针所有权问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设对象A 具有一个属性:

@property (nonatomic, strong) Foo * bar;

在实现中合成为:

@synthesize bar = _bar;

对象B 操纵Foo **,如本例中从对象A 调用:

Object B manipulates a Foo **, as in this example call from Object A:

Foo * temp = self.bar;
[objB doSomething:&temp];
self.bar = temp;

  • 这或类似措施可以合法完成吗?
  • doSomething:方法的正确声明是什么?
    • Can this, or something similar, be done legitimately?
    • What is the correct declaration for the doSomething: method?
    • 此外,假设在我有机会设置bar属性(并因此拥有temp指向的实例的所有权)之前,可能已释放了对象B 告诉ARC交出拥有的参考资料?换句话说,如果我希望以下示例代码能够正常工作,我将如何处理ARC问题?

      Furthermore, suppose Object B may be deallocated before I have a chance to set the bar property (and thus take on ownership of the instance pointed to by temp) - How would I tell ARC to hand off an owning reference? In other words, if I wanted the following example snippet to work, how would I need to handle the ARC issues?

      Foo * temp = self.bar;    // Give it a reference to some current value
      [objB doSomething:&temp]; // Let it modify the reference
      self.bar = nil;           // Basically release whatever we have
      _bar = temp;              // Since we're getting back an owning reference, bypass setter
      

      • 我在想什么?
      • 编辑

        基于@KevinBallard的回答,我只想确认自己的理解.这是正确的吗?

        Based on @KevinBallard 's answer, I just want to confirm my understanding. Is this correct?

        对象A:

        @implementation ObjectA
        
        @synthesize bar = _bar;
        
        - (void)someMethod
        {
            ObjectB * objB = [[ObjectB alloc] initWithFoo:&_bar];
            // objB handed off somewhere and eventually it's "doSomething" method is called.
        }
        
        @end
        

        对象B:

        @implementation ObjectB
        {
            Foo * __autoreleasing * _temp;
        }
        
        - (id)initWithFoo:(Foo * __autoreleasing *)temp
        {
            id self = [super init];
            if (self)
            {
                _temp = temp;
            }
            return self;
        }
        
        - (void)doSomething
        {
            ...
            *_temp = [[Foo alloc] init]; 
            ...
        }
        
        @end
        

        这会产生一个编译时错误:passing address of non-local object to __autoreleasing parameter for write-back

        This creates a compile-time error: passing address of non-local object to __autoreleasing parameter for write-back

        推荐答案

        ARC需要知道对象引用的所有权,以便可以确定何时释放它,等等.对于任何变量(本地,实例或全局),ARC都有规则用于确定所有权;通过推断或通过显式属性.这等于程序员需要在ARC之前跟踪所有权.

        ARC needs to know the ownership of an object reference so it can determine when to release it etc. For any variable (local, instance or global) ARC has rules for determining the ownership; either by inference or by an explicit attribute. This equates to the pre-ARC need for the programmer to track ownership.

        但是,如果引用变量,会发生什么?您无法(在ARC之前)自己编写代码,该代码接受对变量的引用,并且无论该变量的所有权如何,该代码始终可以正常工作-因为您不知道是否需要释放变量等.您不能构造适用于变量(从变化的意义上来说)未知所有权的代码.

        But what happens if you have a reference to a variable? You could not (pre-ARC) yourself write code which accepted a reference to a variable and which would always work correctly regardless of the ownership of that variable - as you could not know whether you needed to release etc. I.e. you can not construct code which works for variable (in the sense of changing!) unknown ownership.

        ARC面临相同的问题,其解决方案是推断或接受指定引用变量所有权的显式属性,然后要求调用方安排对具有适当所有权的变量的引用被通过.后一点可能需要使用隐藏的临时变量.在规范,并称为回写传递".

        ARC faces the same problem and its solution is to infer, or accept an explicit attribute specifying, the ownership of referenced variable and then require the caller to arrange for a reference to a variable of appropriate ownership to be passed. This latter bit can require the use of hidden temporary variables. This is referred to as "least bad solution" in the specification and is termed "pass-by-writeback".

        问题的第一部分:

        Foo * temp = self.bar;
        [objB doSomething:&temp];
        self.bar = temp;
        

        • 这或类似措施可以合法完成吗?
          • Can this, or something similar, be done legitimately?
          • 是的,该代码可以被ARC使用.推断tempstrong,一些幕后的东西碰巧通过引用doSomething:传递给它.

            Yes, the code is fine by ARC. temp is inferred to be strong and some behind the scenes stuff happens to pass it by reference to doSomething:.

            • doSomething:方法的正确声明是什么?
            • What is the correct declaration for the doSomething: method?

            - (void) doSomething:(Foo **)byRefFoo
            

            ARC推断byRefFoo的类型为Foo * __autoreleasing *-对自动释放引用的引用.这就是传递回写"的要求.

            ARC infers byRefFoo to be of type Foo * __autoreleasing * - a reference to an autoreleasing reference. This is what is required by "pass-by-writeback".

            此代码仅有效,因为temp是本地代码.用实例变量执行此操作是不正确的(如您在EDIT中所发现的).假设参数在标准输出"模式下使用并且返回时已分配任何更新值,则有效.这两个都是因为回写传递方式是最差的解决方案"的一部分...

            This code is only valid because temp is a local. It would be incorrect to do this with an instance variable (as you found out in your EDIT). It is also only valid assuming the parameter is being used in standard "out" mode and any updated value has been assign when doSomething: returns. Both of these are because the way pass-by-writeback works as part of that "least bad solution"...

            摘要:使用局部变量时,可以通过引用将其传递以在标准输出"模式下使用,并通过ARC推断出任何必需的属性等.

            Summary: when using local variables they can be passed by reference for use in the standard "out" pattern with ARC inferring any required attributes etc.

            我们将使用类型Breadcrumbs代替问题的Foo;这实际上是一个包裹的NSString,它跟踪每个initretainreleaseautoreleasedealloc(几乎将在下面看到),因此我们可以看到发生了什么. Breadcrumbs的写法并不重要.

            Instead of the Foo of the question we'll use a type Breadcrumbs; this is essentially a wrapped NSString which tracks every init, retain, release, autorelease and dealloc (well almost as you'll see below) so we can see what is going on. How Breadcrumbs is written is not material.

            现在考虑以下课程:

            @implementation ByRef
            {
               Breadcrumbs *instance;                                // __strong inferred
            }
            

            一种更改通过引用传递的值的方法:

            A method to change a value passed by reference:

            - (void) indirect:(Breadcrumbs **)byRef                  // __autoreleasing inferred
            {
               *byRef = [Breadcrumbs newWith:@"banana"];
            }
            

            indirect:的简单包装器,因此我们可以看到它传递了什么以及何时返回:

            A simple wrapper for indirect: so we can see what it is passed and when it returns:

            - (void) indirectWrapper:(Breadcrumbs **)byRef           // __autoreleasing inferred
            {
               NSLog(@"indirect: passed reference %p, contains %p - %@, owners %lu", byRef, *byRef, *byRef, [*byRef ownerCount]);
               [self indirect:byRef];
               NSLog(@"indirect: returned");
            }
            

            还有一个演示indirect:的方法,该方法调用了局部变量(想象中为local):

            And a method to demonstrate indirect: called on a local variable (called imaginatively local):

            - (void) demo1
            {
               NSLog(@"Strong local passed by autoreleasing reference");
               Breadcrumbs *local;                                   // __strong inferred
               local = [Breadcrumbs newWith:@"apple"];
               NSLog(@"local: addr %p, contains %p - %@, owners %lu", &local, local, local, [local ownerCount]);
               [self indirectWrapper:&local];
               NSLog(@"local: addr %p, contains %p - %@, owners %lu", &local, local, local, [local ownerCount]);
            }
            
            @end
            

            现在需要一些代码来练习demo1本地化自动释放池,以便我们可以查看分配,释放的内容以及时间:

            Now some code to exercise demo1 localizing the autorelease pool so we can see what is allocated, released and when:

            ByRef *test = [ByRef new];
            
            NSLog(@"Start demo1");
            @autoreleasepool
            {
               [test demo1];
               NSLog(@"Flush demo1");
            }
            NSLog(@"End demo1");
            

            执行上述操作会在控制台上产生以下内容:

            Executing the above produces the following on the console:

            ark[2041:707] Start demo1
            ark[2041:707] Strong local passed by autoreleasing reference
            ark[2041:707] >>> 0x100176f30: init
            ark[2041:707] local: addr 0x7fff5fbfedc0, contains 0x100176f30 - apple, owners 1
            ark[2041:707] indirect: passed reference 0x7fff5fbfedb8, contains 0x100176f30 - apple, owners 1
            ark[2041:707] >>> 0x100427d10: init
            ark[2041:707] >>> 0x100427d10: autorelease
            ark[2041:707] indirect: returned
            ark[2041:707] >>> 0x100427d10: retain
            ark[2041:707] >>> 0x100176f30: release
            ark[2041:707] >>> 0x100176f30: dealloc
            ark[2041:707] local: addr 0x7fff5fbfedc0, contains 0x100427d10 - banana, owners 2
            ark[2041:707] >>> 0x100427d10: release
            ark[2041:707] Flush demo1
            ark[2041:707] >>> 0x100427d10: release
            ark[2041:707] >>> 0x100427d10: dealloc
            ark[2041:707] End demo1
            

            [">>"行来自Breadcrumbs.] 只需跟随对象(0x100 ...)和变量(0x7fff ...)的地址即可清除...

            [The ">>>" lines come from Breadcrumbs.] Just follow the addresses of the objects (0x100...) and variables (0x7fff...) and it is all clear...

            也许不是!这里又是每个块后面的注释:

            Well maybe not! Here it is again with comments after each chunk:

            ark[2041:707] Start demo1
            ark[2041:707] Strong local passed by autoreleasing reference
            ark[2041:707] >>> 0x100176f30: init
            ark[2041:707] local: addr 0x7fff5fbfedc0, contains 0x100176f30 - apple, owners 1
            

            在这里我们看到[Breadcrumbs newWith:@"apple"]在地址0x100176f30处创建了一个对象.它存储在地址为0x7fff5fbfedc0local中,并且该对象具有1个所有者(local).

            Here we see that [Breadcrumbs newWith:@"apple"] creates an object at address 0x100176f30. This is stored in local, whose address is 0x7fff5fbfedc0, and the object has 1 owner (local).

            ark[2041:707] indirect: passed reference 0x7fff5fbfedb8, contains 0x100176f30 - apple, owners 1
            

            这是隐藏变量:由于indirect:需要引用自动释放变量,因此ARC创建了一个新变量,其地址为0x7fff5fbfedb8,并将对象引用(0x100176f30)复制到该变量中.

            Here comes the hidden variable: as indirect: requires a reference to an autoreleasing variable ARC has created a new variable, whose address is 0x7fff5fbfedb8, and copied the object reference (0x100176f30) into that.

            ark[2041:707] >>> 0x100427d10: init
            ark[2041:707] >>> 0x100427d10: autorelease
            ark[2041:707] indirect: returned
            

            indirect:内部,将创建一个新对象,并且ARC在分配该对象之前会自动释放该对象-因为传递的引用引用了一个自动释放变量.

            Inside indirect: a new object is created and ARC autoreleases it before assigning it - because the passed references refers to an autoreleasing variable.

            注意: ARC不需要对引用变量(0x7fff5fbfedb8)的上一个内容(0x100176f30)进行任何操作,因为它是自动释放,因此不承担责任. IE. 自动释放所有权"的意思是,分配的任何引用都必须已经有效地自动发布.您会看到创建隐藏变量ARC时实际上并没有保留并自动释放其内容-不需要这样做,因为它知道在其管理的对象中有一个强引用(在local中). [在下面的最后一个示例中,ARC确实必须管理此分配,但是它仍然设法避免使用自动释放池.]

            Note: ARC does not need to do anything with the previous contents (0x100176f30) of the referenced variable (0x7fff5fbfedb8) as it is autoreleasing and hence not its responsibility. I.e. what "autoreleasing ownership" means is that any reference assigned must have already been effectively autoreleased. You'll see when creating the hidden variable ARC did not actually retain and autorelease its contents - it did not need to do this as it knows there is a strong reference (in local) to the object which it is managing. [In the last example below ARC does have to manage this assignment but it still manages to avoid using the autorelease pool.]

            ark[2041:707] >>> 0x100427d10: retain
            ark[2041:707] >>> 0x100176f30: release
            ark[2041:707] >>> 0x100176f30: dealloc
            

            这些操作是由于将隐藏变量的值复制(逐个写回中的写回")到local中的结果. release/dealloc用于local中的旧强引用,而retain用于由隐藏变量(由自动释放)引用的对象

            These actions result from copying (the "writeback" in call-by-writeback) the value from the hidden variable into local. The release/dealloc are for the old strong reference in local, and the retain is for the object referenced by the hidden variable (which was autoreleased by indirect:)

            注意:这是为什么此写回仅适用于使用传递引用的出局"模式的原因-您不能将传递给indirect:的引用原样存储到隐藏的局部变量即将消失...

            Note: this writeback is why this only works for the "out" pattern of using pass-by-reference - you can't store the reference passed to indirect: as it is to a hidden local variable which is about to disappear...

            ark[2041:707] local: addr 0x7fff5fbfedc0, contains 0x100427d10 - banana, owners 2
            

            因此,调用local引用新对象之后,它具有 2 个所有者-local占一个,而另一个是indirect:中的autorelease

            So after the call local refers to the new object, and it has 2 owners - local accounts for one, and the other is the autorelease in indirect:

            ark[2041:707] >>> 0x100427d10: release
            

            demo1现在已完成,因此ARC在local

            demo1 is now finished so ARC releases the object in local

            ark[2041:707] Flush demo1
            ark[2041:707] >>> 0x100427d10: release
            ark[2041:707] >>> 0x100427d10: dealloc
            ark[2041:707] End demo1
            

            ,并且demo1返回本地化的@autoreleasepool后,会处理indirect:的自动释放,现在所有权为零,我们得到了dealloc.

            and after demo1 returns the localized @autoreleasepool handles the autorelease pending from indirect:, now the ownership is zero and we get the dealloc.

            通过引用传递实例变量

            以上内容处理了通过引用传递局部变量的问题,但不幸的是,传写回传不能用于实例变量.有两种基本解决方案:

            The above deals with passing local variables by reference, but unfortunately pass-by-writeback does not work for instance variables. There are two basic solutions:

            • 将实例变量复制到本地

            • copy your instance variable to a local

            添加一些属性

            为了演示第二个示例,我们在类ByRef中添加了strongIndirect:,该类指定它需要引用强变量:

            To demonstrate the second we add to class ByRef a strongIndirect: which specifies it requires a reference to a strong variable:

            - (void) strongIndirect:(Breadcrumbs * __strong *)byRef
            {
               *byRef = [Breadcrumbs newWith:@"plum"];
            }
            
            - (void) strongIndirectWrapper:(Breadcrumbs * __strong *)byRef
            {
               NSLog(@"strongIndirect: passed reference %p, contains %p - %@, owners %lu", byRef, *byRef, *byRef, [*byRef ownerCount]);
               [self strongIndirect:byRef];
               NSLog(@"strongIndirect: returned");
            }
            

            和相应的demo2,它使用ByRef的实例变量(再次使用instance的虚构名称):

            and a corresponding demo2 which uses ByRef's instance variable (again with the imaginative name of instance):

            - (void) demo2
            {
               NSLog(@"Strong instance passed by strong reference");
               instance = [Breadcrumbs newWith:@"orange"];
               NSLog(@"instance: addr %p, contains %p - %@, owners %lu", &instance, instance, instance, [instance ownerCount]);
               [self strongIndirectWrapper:&instance];
               NSLog(@"instance: addr %p, contains %p - %@, owners %lu", &instance, instance, instance, [instance ownerCount]);
            }
            

            使用与上述demo1类似的代码执行此操作,我们得到:

            Execute this with a similiar piece of code as for demo1 above and we get:

            1  ark[2041:707] Start demo2
            2  ark[2041:707] Strong instance passed by strong reference
            3  ark[2041:707] >>> 0x100176f30: init
            4  ark[2041:707] instance: addr 0x100147518, contains 0x100176f30 - orange, owners 1
            5  ark[2041:707] strongIndirect: passed reference 0x100147518, contains 0x100176f30 - orange, owners 1
            6  ark[2041:707] >>> 0x100427d10: init
            7  ark[2041:707] >>> 0x100176f30: release
            8  ark[2041:707] >>> 0x100176f30: dealloc
            9  ark[2041:707] strongIndirect: returned
            10 ark[2041:707] instance: addr 0x100147518, contains 0x100427d10 - plum, owners 1
            11 ark[2041:707] Flush demo2
            12 ark[2041:707] End demo2
            

            哪个比以前短一些.这有两个原因:

            Which is a bit shorter than before. This is for two reasons:

            • 当我们将强变量(instance)传递给方法(strongIndirect:)时,该方法期望引用强变量,因此ARC无需使用隐藏变量-行中的变量上面的4和5相同(0x100147518).

            • As we are passing a strong variable (instance) to a method (strongIndirect:) which expects a reference to a strong variable there is no need for ARC to use a hidden variable - the variables in line 4 and 5 above are the same (0x100147518).

            由于ARC知道strongIndirect:中的引用变量很强,因此无需在strongIndirect:中存储自动释放的引用,然后在调用后写回该值-ARC只是执行标准的强分配,第6行-8,以后没有自动释放的内容(在第11和12行之间).

            As ARC knows the referenced variable in strongIndirect: is strong there is no need to store an autoreleased reference within strongIndirect: and then write this back after the call - ARC just does a standard strong assignment, lines 6-8, and there is nothing to autorelease later (between lines 11 and 12).

            strongIndirect:是否适用于强大的本地人?

            Does strongIndirect: work for strong locals?

            当然,这是demo3:

            - (void) demo3
            {
               NSLog(@"Strong local passed by strong reference");
               Breadcrumbs *local;                                   // __strong inferred
               local = [Breadcrumbs newWith:@"apple"];
               NSLog(@"local: addr %p, contains %p - %@, owners %lu", &local, local, local, [local ownerCount]);
               [self strongIndirectWrapper:&local];
               NSLog(@"local: addr %p, contains %p - %@, owners %lu", &local, local, local, [local ownerCount]);
            }
            

            使用我们的标准包装器执行此操作会产生:

            Executing this with our standard wrapper produces:

            1  ark[2041:707] Start demo3
            2  ark[2041:707] Strong local passed by strong reference
            3  ark[2041:707] >>> 0x100176f30: init
            4  ark[2041:707] local: addr 0x7fff5fbfedc0, contains 0x100176f30 - apple, owners 1
            5  ark[2041:707] strongIndirect: passed reference 0x7fff5fbfedc0, contains 0x100176f30 - apple, owners 1
            6  ark[2041:707] >>> 0x100427d20: init
            7  ark[2041:707] >>> 0x100176f30: release
            8  ark[2041:707] >>> 0x100176f30: dealloc
            9  ark[2041:707] strongIndirect: returned
            10 ark[2041:707] local: addr 0x7fff5fbfedc0, contains 0x100427d20 - plum, owners 1
            11 ark[2041:707] >>> 0x100427d20: release
            12 ark[2041:707] >>> 0x100427d20: dealloc
            13 ark[2041:707] Flush demo3
            14 ark[2041:707] End demo3
            

            这与前面的示例几乎相同,只有两个小的区别:

            This is almost the same as the previous example, just two minor differences:

            • 通过堆栈上的本地地址(0x7fff5fbfedc0),第4行和第5行

            当它存储在本地时,新对象将由ARC第11和12行清除

            As it is stored in a local the new object is cleaned up by ARC, lines 11 and 12

            为什么不总是将__strong添加到引用参数?

            Why not always add __strong to reference arguments?

            一个原因是因为并非所有事物都强大! ARC的传递回写功能也适用于弱势本地用户.我们的最终演示:

            One reason is because not everything is strong! ARC's pass-by-writeback works for weak locals as well. Our final demo:

            - (void) demo4
            {
               NSLog(@"Weak local passed by autoreleasing reference");
               instance = [Breadcrumbs newWith:@"peach"];
               Breadcrumbs __weak *weakLocal = instance;
               NSLog(@"weakLocal: addr %p, contains %p - %@, owners %lu", &weakLocal, weakLocal, weakLocal, [weakLocal ownerCount]);
               [self indirectWrapper:&weakLocal];
               NSLog(@"weakLocal: addr %p, contains %p -, %@, owners %lu", &weakLocal, weakLocal, weakLocal, [weakLocal ownerCount]);
            }
            

            [这里我们只使用了instance,因此我们需要对其进行弱引用."

            [Here we've just used instance so we have something to make a weak reference to.]

            使用我们的标准包装器执行此操作会产生:

            Executing this with our standard wrapper produces:

             1 ark[2041:707] Start demo4
             2 ark[2041:707] Weak local passed by autoreleasing reference
             3 ark[2041:707] >>> 0x608000000d10: init
             4 ark[2041:707] weakLocal: addr 0x7ffeefbfde58, contains 0x608000000d10 - peach, owners 4
             5 ark[2041:707] >>> 0x608000000d10: retainWeakReference
             6 ark[2041:707] indirect: passed reference 0x7ffeefbfde40, contains 0x608000000d10 - peach, owners 2
             7 ark[2041:707] >>> 0x604000001060: init
             8 ark[2041:707] >>> 0x604000001060: autorelease
             9 ark[2041:707] indirect: returned
            10 ark[2041:707] >>> 0x608000000d10: release
            11 ark[2041:707] weakLocal: addr 0x7ffeefbfde58, contains 0x604000001060 - banana, owners 4
            12 ark[2041:707] Flush demo4
            13 ark[2041:707] >>> 0x604000001060: release
            14 ark[2041:707] >>> 0x604000001060: dealloc
            15 ark[2041:707] End demo4
            16 ark[2041:707] >>> 0x608000000d10: release
            17 ark[2041:707] >>> 0x608000000d10: dealloc
            

            注意:

            • 第3、16和9行17与instance有关-创建新值并发布&最后释放的内容-重要的内容从第4行开始

            • Lines 3, 16 & 17 are related to instance - create a new value and release & deallocated at the end - the important stuff starts at line 4

            第4行显示了已分配给weakLocal的内容,请注意,将`instance'的强引用复制到此弱变量中不需要任何保留. (注意:显示弱变量的内容确实涉及一些保留和释放操作,为清楚起见已将其删除.)

            Line 4 shows what has been assigned to weakLocal, note that copying the strong reference from `instance into this weak variable does not require any retain. (Note: displaying the contents of a weak variable does involved some retain and release operations, these have been elided for clarity.)

            ARC对弱局部变量(第4行,0x7ffeefbfde58)也使用隐藏变量(第6行,0x7ffeefbfde40).在强本地情况(demo1)中,ARC知道存储在此隐藏变量中的引用将保持有效,并避免使用自动释放池.在这种情况下,这不能保证,但是ARC仍然设法避免使用自动释放池:ARC保留了引用(第5行,retainWeakReferenceretain的特殊版本,用于弱变量),并且在调用完成后,可以使用发布(第10行).与使用自动释放池相比,这会缩短强引用的寿命.

            ARC uses a hidden variable (line 6, 0x7ffeefbfde40) for weak locals (line 4, 0x7ffeefbfde58) as well. In the strong local case (demo1) ARC knows the reference stored in this hidden variable will remain valid and avoids using the autorelease pool. In this case this isn't guaranteed but ARC still manages to avoid the autorelease pool: ARC retains the reference (line 5, retainWeakReference is a special version of retain for weak variables) and after the call has completed balances this with a release (line 10). This shortens the lifetime of the strong reference compared to using the autorelease pool.

            indirectWrapper(第8行)中的自动释放分配(0x604000001060)在排空池(第13和14行)时达到平衡.最后,当我们的ByRef实例消失时,ARC会清理存储在instance(0x608000000d10)中的对象.

            The autoreleased assignment (0x604000001060) inside indirectWrapper (line 8) is balanced when the pool is drained (lines 13 & 14). Finally ARC cleans up the object stored in instance (0x608000000d10) when our ByRef instance goes away.

            摘要

            • 没有任何添加的属性,ARC将对通过引用作为参数传递的局部(推断的强)变量(推断的自动释放)做正确的事情. (本地"包括当前方法的参数.)

            • Without any added attributes ARC will do the right thing for local (inferred strong) variables passed as parameters by reference (inferred autoreleasing). (And "local" includes parameters to the current method.)

            这是由ARC使用传递回写的方式实现的,并且只有遵循"out"参数模式时,才有效.如果您希望存储传递的参考以供以后使用,则需要自己做更多的事情.

            This is implemented by ARC using pass-by-writeback and only works if you follow the "out" parameter pattern. If you wish to store the passed reference for use later you'll need to do more yourself.

            如果希望通过引用传递实例变量,则需要将其复制到本地变量中,或使用__strong赋予接收参数类型属性.

            If you wish to pass instance variables by reference you either need to copy them into locals or attribute the receiving parameter type with __strong.

            通过写回传递也适用于__weak当地人.

            pass-by-writeback also works for __weak locals.

            希望有帮助.

            附录2016年4月:__block变量

            Addendum Apr 2016: __block variables

            在希思·边界的评论中,

            In the comments Heath Borders has asked:

            如果我的局部变量是__block类型怎么办?我很确定这种情况与实例变量相同,因为我需要将它们复制到本地变量,或者使用__strong属性指定接收参数的类型,但是我对其他人的看法很好奇.

            What if my local variable is a __block type? I'm pretty sure this case is the same as an instance variable in that I need to either copy them to locals, or attribute the receiving parameter type with __strong, but I'm curious about someone else's opinion.

            有趣的问题.

            规范状态:

            如果参数表达式的格式不合法,则传递回写格式不正确:

            The pass-by-writeback is ill-formed if the argument expression does not have a legal form:

            &var,其中var是具有可保留对象指针类型的自动存储持续时间的标量变量

            &var, where var is a scalar variable of automatic storage duration with retainable object pointer type

            默认情况下(Objective-)C中的局部变量具有自动存储期限-在输入/退出其封闭函数/方法/块时,它们会自动创建和销毁.在上面的答案中,当我们提到局部变量"时,我们隐式地指的是具有自动存储持续时间的局部变量.

            Local variables in (Objective-)C by default have automatic storage duration - they are automatically created and destroyed as their enclosing function/method/block is entered/exited. In the above answer when we refer to "local variable" we are implicitly referring to local variables with automatic storage duration.

            可以使用存储限定符存储类说明符声明局部变量,以更改变量的存储持续时间.最常见的是static;具有静态存储持续时间的局部变量在程序的整个执行过程中都存在,但只能(直接)在其局部范围内访问.

            Local variables can be declared with a storage qualifier or storage class specifier to change the storage duration of the variable. The most commonly seen one is static; local variables with static storage duration exist throughout the execution of the program but are only (directly) accessible within their local scope.

            如果尝试通过传递回写传递static局部变量,则编译器将产生错误,指示该变量没有自动存储持续时间.您必须以与实例变量(具有已分配存储期限的实例变量)相同的方式处理此类变量.

            If you attempt to pass a static local variable with pass-by-writeback the compiler will produce an error indicating the variable does not have automatic storage duration. You must handle such variables in the same way as instance variables (which have allocated storage duration).

            __block存储限定符是作为块的一部分和规范状态引入(Objective-)C:

            The __block storage qualifier was introduced into (Objective-)C as part of blocks and the specification states:

            __block存储限定符与现有本地存储限定符autoregisterstatic互斥. __block限定的变量的行为就像它们在分配的存储中一样,并且在上次使用该变量后会自动恢复该存储.

            The __block storage qualifier is mutually exclusive to the existing local storage qualifiers auto, register, and static. Variables qualified by __block act as if they were in allocated storage and this storage is automatically recovered after last use of said variable.

            因此,像实例变量一样,__block局部变量的作用就好像它已分配了存储持续时间一样,因此根据回写传递的规范,此类变量不能使用,因为它没有自动存储持续时间. ..

            So a __block local variable acts as if it has allocated storage duration, just like instance variables, and so by the specification of pass-by-writeback such a variable cannot be used as it does not have automatic storage duration...

            但是使用撰写本文时的最新工具(Xcode 7.2,Clang 7.0.2)__block合格的局部变量由传递回写支持,并且其处理方式与那些相同.具有自动存储期限-使用隐藏的__autoreleasing临时目录.

            However with the tools current at the time of writing (Xcode 7.2, Clang 7.0.2) __block qualified local variables are supported by pass-by-writeback and are handle the same as those with automatic storage duration - a hidden __autoreleasing temporary is used.

            该文件似乎没有记录.

            从某种意义上说,无论编译与否,使用它都是安全的",并且一旦编译,即使工具改变了,代码也仍然可以工作,并且以后也不能再次编译了...至少在不处理变量的情况下与必须处理实例变量相同).

            Having said that it is "safe" to use in the sense that it will either compile or not, and once compiled the code will work even if the tools change and it cannot be compiled again in the future... (at least without handling the variable the same was as instance variables must be handled).

            可以接受它的原因可以从对传递回写的限制(强调):

            The reason why it can be accepted can be gleaned from the rationale for the restrictions on pass-by-writeback (emphasis added):

            理论上

            参数形式的限制有两个目的.首先,它使得无法将数组的地址传递给参数,从而避免了将数组"参数误认为是输出参数的严重风险. 第二,由于下面的实现,使得用户看到混淆的混叠问题的可能性大大降低,以下实现中,在原始参数变量中没有立即看到他们存储在写回临时文件中的信息.

            The restriction in the form of the argument serves two purposes. First, it makes it impossible to pass the address of an array to the argument, which serves to protect against an otherwise serious risk of mis-inferring an "array" argument as an out-parameter. Second, it makes it much less likely that the user will see confusing aliasing problems due to the implementation, below, where their store to the writeback temporary is not immediately seen in the original argument variable.

            传递回写不支持实例变量是没有技术原因的,但是由于混叠会引起混淆. __block变量位于自动变量和分配变量之间,因此,当前的工具编写者可能选择将它们与前者而不是后者分组以进行传递回写.

            There is no technical reason why instance variables could not be supported by pass-by-writeback, but it could be confusing due to aliasing. __block variables lie somewhere between automatic and allocated ones, so maybe the current tool writers choose to group them with the former rather than the latter for pass-by-writeback.

            注意:熟悉块实现的读者会知道,根据使用情况,可以将__block合格的本地实现为具有自动或分配存储持续时间的优化,因此想知道是否这会影响它们用于传递回写.事实并非如此.

            Note: Readers familiar with the implementation of blocks will know that a __block qualified local may be implemented as an optimisation with either automatic or allocated storage duration, depending on usage, and therefore wonder whether this impacts their use for pass-by-writeback. This does not appear to be the case.

            这篇关于处理ARC中的指针对指针所有权问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆