“缺少__block类型说明符”重构代码后的编译错误,但在重构之前确定 [英] "Missing __block type specifier" compilation error after refactoring code but ok before refactor
问题描述
我有一些代码可以下载图像并将其分配到一个块中。代码当前有效但是我想将它重构为一个单独的方法,但是在重构之后我得到了一个编译错误。
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 $ c范围内的局部变量$ c>。
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];
这有两个原因:
- 您无法在块中分配
targetImage
。这是属于fetchFbImage
的局部变量,该局部变量不归因于__ block
,因此该块具有它的常量副本 - 你不能分配给常量。这就是编译器发出错误消息的原因。 - 但是你的问题比这更大,你假设分配给
fetchFbImage
的局部变量targetImage
将会如何调用属性object.image
- 并且它无法做到这一点。targetImage
只是一个局部变量,它使用object.image
的值初始化方法调用。
- You cannot assign to
targetImage
within the block. This is a local variable belonging tofetchFbImage
, 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. - However your issue is bigger than this, you are assuming that an assignment to
fetchFbImage
's local variabletargetImage
will some how invoke the propertyobject.image
- and there is no way it can do that.targetImage
is just a local variable which was initialised with the value ofobject.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屋!