“缺少__block类型说明符”重构代码后的编译错误,但在重构之前确定 [英] "Missing __block type specifier" compilation error after refactoring code but ok before refactor

查看:97
本文介绍了“缺少__block类型说明符”重构代码后的编译错误,但在重构之前确定的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些代码可以下载图像并将其分配到一个块中。代码当前有效但是我想将它重构为一个单独的方法,但是在重构之后我得到了一个编译错误。

I have some code that downloads an image and assigns it within a block. The code currently works however I want to refactor it into a separate method, however after the refactoring I get a compilation error.

这是编译和运行的原始代码已成功分配下载的图像:

This is the original code which compiles and runs with the downloaded image being assigned successfully:

- (void) someMethod
{
   …
   MyObject* object = [[MyObject alloc] init];
   [self.objects addObject: object];

   NSString* graphRequest = [NSString stringWithFormat:@"%@%@%@",  @"https://graph.facebook.com/",
                              fbid,
                              @"/picture?type=square"];
    FBRequest *fbRequest = [FBRequest requestForGraphPath: graphRequest];
    [fbRequest startWithCompletionHandler:
     ^(FBRequestConnection *connection, id result, NSError *theError)
     {
         NSDictionary<FBGraphObject> *dict = (NSDictionary<FBGraphObject> *) result;
         if (dict)
         {
             NSString* urlAsString = [dict objectForKey:@"id"];
             if ([urlAsString length] > 0)
             {
                 NSURL *url = [NSURL URLWithString: urlAsString];
                 NSData *data = [NSData dataWithContentsOfURL:url];
                 object.image = [UIImage imageWithData:data];
             }
         }
     }];
}

如果我将其重构为以下内容,则会出现编译错误

If I refactor it to the following then I get a compilation error

- (void) someMethod
{
   …
   MyObject* object = [[MyObject alloc] init];
   [self.objects addObject: object];
   [self fetchFbImage: object.image forFbid:fbid];
}


- (void) fetchFbImage:(UIImage*) targetImage forFbid:(NSString*) fbid
{
    NSString* graphRequest = [NSString stringWithFormat:@"%@%@%@",  @"https://graph.facebook.com/",
                              fbid,
                              @"/picture?type=square"];
    FBRequest *fbRequest = [FBRequest requestForGraphPath: graphRequest];
    [fbRequest startWithCompletionHandler:
     ^(FBRequestConnection *connection, id result, NSError *theError)
     {
         NSDictionary<FBGraphObject> *dict = (NSDictionary<FBGraphObject> *) result;
         if (dict)
         {
             NSString* urlAsString = [dict objectForKey:@"id"];
             if ([urlAsString length] > 0)
             {
                 NSURL *url = [NSURL URLWithString: urlAsString];
                 NSData *data = [NSData dataWithContentsOfURL:url];
                 targetImage = [UIImage imageWithData:data];
             }
         }
     }];
}

编译错误是分配到targetImage的行,变量不可分配(缺少__block类型说明符)。

The compilation error is the line assigning into targetImage, "Variable is not assignable (missing __block type specifier)".

我应该在哪里添加__block类型说明符?为什么在重构之后会出现问题而不是之前的问题?

Where should I add the __block type specifier? And why is there an issue after the refactoring but not before?

谢谢

推荐答案

您似乎对参数如何在Objective-C中工作感到困惑。

You seem to be confused over how parameters work in Objective-C.

在您的原始代码中,您有:

In your original code you have:

MyObject* object = [[MyObject alloc] init];

声明对象作为本地变量方法。然后在你写的块内:

which declares object as a local variable of the method. Then within the block you write:

object.image = [UIImage imageWithData:data];

所以你的块引用局部变量 object 并且(因为声明中没有 __ block 属性)该块获取变量内容的常量副本。这很好,因为你没有改变 object 中的内容,它是对 MyObject 实例的引用,但是在该实例上调用一个方法来改变该实例的内部状态。[*]

So your block references the local variable object and (as you have no __block attribute on the declaration) the block gets a constant copy of the contents of variable. This is fine because you are not changing what is in object, which is a reference to your MyObject instance, but are calling a method on that instance which changes the internal state of that instance.[*]

现在让我们来看看你的重构。您删除了 someMethod 的代码块,并将其放入新方法 fetchFbImage 。在 someMethod 中,您调用 fetchFbImage

Now let's look at your refactoring. You remove a chunk of your someMethod's code and place it in a new method fetchFbImage. In someMethod you call fetchFbImage:

[self fetchFbImage:object.image forFbid:fbid];

这会传递对象的当前值。图像指向的方法,以便在 fetchFbImage 中分配属性。参数的类型 targetImage UIImage * - 对 UIImage的引用 - 它不是code> UIImage * 类型的属性 - 你不能拥有这种类型的参数,属性不能只传递它们的值或引用具有属性的对象。

This passes the current value of object.image to the method it does not pass the property in such a way that it can be assigned to in fetchFbImage. The type of the argument targetImage is UIImage * - a reference to an UIImage - it is not "a property of type UIImage *" - you cannot have arguments of such a type, properties cannot be passed around only their values or reference to objects which have properties.

当调用方法时,每个参数实际上是一个局部变量,它初始化为传递的参数值,因此上述方法调用有效地执行: / p>

When a method is called each parameter is effectively a local variable which is initialised to the argument value passed, so the above method call effectively performs:

UIImage *targetImage = object.image;

其中 targetImage 是一个局部变量范围 fetchFbImage object someMethod

where targetImage is a local variable in the scope of fetchFbImage and object is the local variable in the scope of someMethod.

现在在 fetchFbImage 的块内你写道:

targetImage = [UIImage imageWithData:data];

这有两个原因:


  1. 您无法在块中分配 targetImage 。这是属于 fetchFbImage 的局部变量,该局部变量不归因于 __ block ,因此该块具有它的常量副本 - 你不能分配给常量。这就是编译器发出错误消息的原因。

  2. 但是你的问题比这更大,你假设分配给 fetchFbImage 的局部变量 targetImage 将会如何调用属性 object.image - 并且它无法做到这一点。 targetImage 只是一个局部变量,它使用 object.image 初始化方法调用。

  1. You cannot assign to targetImage within the block. This is a local variable belonging to fetchFbImage, that local variable is not attributed with __block, and so the block has a constant copy of it - and you cannot assign to constants. This is why the compiler issues the error message.
  2. However your issue is bigger than this, you are assuming that an assignment to fetchFbImage's local variable targetImage will some how invoke the property object.image - and there is no way it can do that. targetImage is just a local variable which was initialised with the value of object.image by the method call.

解决此问题的唯一方法是传递 fetchFbImage MyObject 实例的引用,然后在 fetchFbImage 内的块内分配给 image 该对象的属性就像你的预先重构代码那样。

The only way to fix this is to pass fetchFbImage a reference to your MyObject instance and then within the block inside of fetchFbImage to assign to the image property of that object just as your pre-refectored code did.

所以你的代码看起来像:

So your code will look something like:

- (void) fetchFbImage:(MyObject *)targetObject forFbid:(NSString *)fbid
{
   ...
   targetObject.image = [UIImage imageWithData:data];
   ...
}

...

[self fetchFbImage:object forFbid:fbid];

HTH

附录

看到您对另一个答案的评论,您希望 fetchFbImage 不知道 MyObject 并且能够获取图像而不管它们将从哪里引用。

Seeing your comment on another answer it appears you would like fetchFbImage to have no knowledge of MyObject and be able to fetch images regardless of where they will be referenced from.

一种简单的方法是执行此操作遵循与 FBRequest 相同的设计 - 使用完成处理程序。为方便起见,定义完成块的类型:

A simple way to do this is to follow the same design you have for FBRequest - use a completion handler. For convenience define a type for the completion block:

typedef void (^ImageConsumer)(NSImage *image);

现在定义您的方法以采取以下方法之一:

Now define your method to take one of these:

- (void) fetchFbImageForFbid:(NSString *)fbid completionHandler:(ImageConsumer)handler

中的块中fetchFbImageForFbid 将图像传递给处理程序:

In your block within fetchFbImageForFbid pass the image to the handler:

handler([UIImage imageWithData:data]);

的调用中,someMethod 传递一个将值赋给您的属性的块:

And in the call in someMethod pass a block which assigns the value to your property:

[self fetchFbImageForFbid:fbid
        completionHandler:^(NSImage *image) { object.image = image; }
];






[*]如果这是令人困惑的想到引用作为房子的地址。地址是不变的,房子里有多少人不是。你可以告诉别人去这个地址,有一个很棒的派对 - 房子的内容(状态)发生变化,地址不变。


[*] If this is confusing think of the reference as the address of a house. The address is constant, how many people are in the house is not. You can tell someone "go to this address, there is a great party on" - the contents ("state") of the house changes, its address does not.

这篇关于“缺少__block类型说明符”重构代码后的编译错误,但在重构之前确定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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