简体   繁体   English

引用块中的iOS应用程序委托是否会创建委托对象的副本?

[英]Does referencing an iOS app delegate in a block create a copy of the delegate object?

Consider the following example: 请考虑以下示例:

- (void)exampleFunction
{
  AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
  SomeClass *classObject = [[SomeClass alloc] init];
  [classObject someFunctionThatDoesBackgroundWorkAndCallsACompletionBlock:^(NSDictionary *results) {
    SomeNeatObject *object = appDelegate.someNeatObject;
    [object doSomeNeatStuff:results];
  }];
}

Making an assumption that the completion block is executed on the main/UI thread to avoid additional insanity, here's what I'm unsure of: 假设在主/ UI线程上执行完成块以避免额外的疯狂,这是我不确定的:

  1. Does the appDelegate variable get copied onto the stack, as per normal block rules when referencing variables inside the block? 当引用块内的变量时,appDelegate变量是否被复制到堆栈中,按照正常的块规则?
  2. If yes to #1, is this a good / safe practice? 如果是#1,这是一个好/安全的做法吗? I could see this possibly causing problems if you did this in a block that was subsequently dispatched to a GCD queue, as .someNeatObject could have changed state / gone to nil? 我可以看到这可能会导致问题,如果你在随后调度到GCD队列的块中执行此操作,因为.someNeatObject可能已更改状态/变为nil?

I realize that the appDelegate should not be overused, but it is useful for it to hold information about the current state of the application, such as Core Data-related objects if you use Apple's templates for initializing a Core Data stack (at least on iOS projects). 我意识到appDelegate不应该被过度使用,但如果你使用Apple的模板来初始化Core Data堆栈(至少在iOS上),它可以保存有关应用程序当前状态的信息,例如Core Data相关对象。项目)。 That particular case (Core Data) has me concerned as much of that stack is not thread-safe nor is it a good idea to be copying it. 那个特殊情况(核心数据)让我担心这个堆栈不是线程安全的,也不是复制它的好主意。

Thanks in advance. 提前致谢。

Your example will not compile because delegate is not defined. 您的示例将无法编译,因为未定义委托。 I assume you mean "SomeNeatObject *object = appDelegate.someNeatObject;" 我假设你的意思是“SomeNeatObject * object = appDelegate.someNeatObject;”

In this example, appDelegate is a variable, whose value will be captured by the block. 在此示例中,appDelegate是一个变量,其值将由块捕获。 It's no different than any other variable. 它与任何其他变量没有什么不同。

It's not unsafe, because [[UIApplication sharedApplication] delegate] always returns the same thing, unless you change the delegate, which you probably don't. 它不是不安全的,因为[[UIApplication sharedApplication]委托]总是返回相同的东西,除非你改变委托,你可能不会。

The fundamental concepts here are: appDelegate is a variable which points (or refers) to an object (or instance) of type AppDelegate . 这里的基本概念是: appDelegate是一个指向 (或引用) AppDelegate类型的对象 (或实例)的变量 In an iOS app there is one such instance, which is returned by [[UIApplication sharedApplication] delegate]. 在iOS应用程序中,有一个这样的实例,由[[UIApplication sharedApplication]委托]返回。 If you create a reference to appDelegate inside a block, you are making a copy of the variable, not the object. 如果在块内创建对appDelegate的引用,则表示您正在复制变量,而不是对象。 So in your code's block: 所以在你的代码块中:

SomeNeatObject *object = appDelegate.someNeatObject;

This is semantically the same as putting the following code in the block (casts omitted): 这在语义上与在块中放置以下代码相同(强制转换):

SomeNeatObject *object = [[UIApplication sharedApplication] delegate].someNeatObject;

The SomeNeatObjects being referred to are the same thing. 引用的SomeNeatObjects是相同的东西。

Slightly more advanced concept: any object has an address in memory (an integer, usually seen in hexadecimal). 略微更高级的概念:任何对象在内存中都有一个地址(一个整数,通常以十六进制显示)。 If two variables have the same hexadecimal value, they point to the same object. 如果两个变量具有相同的十六进制值,则它们指向同一个对象。 If they have different values, they point to different objects. 如果它们具有不同的值,则它们指向不同的对象。 In your example, appDelegate (outside block) and appDelegate (inside block) have the same value, therefore point to the same object. 在您的示例中,appDelegate(外部块)和appDelegate(内部块)具有相同的值,因此指向同一个对象。

If you were to do this: 如果你这样做:

AppDelegate * otherDelegate = [appDelegate copy];

Then you would be making a copy of the object pointed to by appDelegate. 然后你将制作appDelegate指向的对象的副本。 But don't do this, please. 但请不要这样做。

It's retain count does get incremented. 它的保留计数会增加。 The remedy is to tag it with the __weak attribute: 解决方法是使用__weak属性标记它:

- (void)exampleFunction {
  __weak AppDelegate *weakDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];

  SomeClass *classObject = [[SomeClass alloc] init];
  [classObject someFunctionThatDoesBackgroundWorkAndCallsACompletionBlock:^(NSDictionary *results) {
    SomeNeatObject *object = weakDelegate.someNeatObject;
    [object doSomeNeatStuff:results];
  }];
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM