【问题标题】:pass objective c object and primitive type into a void *将目标 c 对象和原始类型传递到 void *
【发布时间】:2012-06-25 17:29:27
【问题描述】:

我想传递 2 个变量:

UIImage * img
int i

进入另一个只需要 (void *) 的方法

我尝试制作一个包含 img 和 i 的 C 结构

struct MyStruct {
    UIImage *img;
    int i;
}

但是 xcode 给我一个错误提示“ARC forbids Objective-C objects in structs or unions”

接下来我尝试编写一个包含 img 和 i 的 Objective-c 类 MyStruct2,分配初始化它的一个实例并将其类型转换为 (__bridge void*),然后将其传递给方法。我的用例似乎很少涉及。似乎应该有更好的方法。

实现这一目标的最简单方法是什么?

谢谢。

基于 cmets 进行编辑:我必须使用 void *,因为它是 UIView API 所要求的。我创建了 UIVIew API 提到的选择器

+ (void)setAnimationDidStopSelector:(SEL)selector

请参阅http://developer.apple.com/library/ios/#documentation/uikit/reference/UIView_Class/UIView/UIView.html 上的 setAnimationDidStopSelector 文档。它说...选择器应采用以下形式:

    - (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context 

我想将 img 和 i 都传递给 (void *)context 参数。

【问题讨论】:

  • 为什么不改变你传递给他们的方法?
  • 只是出于好奇,为什么不改变方法本身呢?
  • @Anne 可能他正在使用 pthreads 并且回调只能采用 1 个参数。

标签: objective-c ios


【解决方案1】:

你可以这样做:

struct MyStruct {
    __unsafe_unretained UIImage *img;
    int i;
}

但是,如果您这样做,您必须记住img 字段不会自动保留和释放其UIImage

如果您发布有关“仅需要 (void *) 的方法”的更多详细信息,我们也许可以为您提供更好的建议。

编辑

您已更新您的问题,说您需要将 void * 传递给 animationDidStop:finished:context: 选择器。由于您使用的是 ARC,我知道您的目标是 iOS 4.0 或更高版本,因此您应该改用 animateWithDuration:animations:completion:。那么你不需要传递void *

UIImage *img = someImage();
int i = someInt();

[UIView animateWithDuration:2.0 animations:^{
    // set the animatable properties here
} completion:^(BOOL finished) {
    doSomethingWithImageAndInteger(img, i);
}];

【讨论】:

  • Rob,我喜欢你回答的第 1 部分。 真的简单。
  • 小心点,你在玩 __unsafe_unretained 会造成伤害。注意“不安全”这个词,这是有原因的。 __unretained 就足够了。 :)
【解决方案2】:

ARC 不能跟随普通旧 C 结构中的 ObjC 对象。它跟踪堆栈上的指针,或者 ObjC 和 C++ 对象中的指针,这些指针是使用显式或隐式方法复制的,但无论如何都在编译器控制之下。

所以...使用一个类。如果你喜欢 C++,或者:

@interface MyNotSoPlainStruct

@property ( nonatomic, strong ) UImage* image;
@property ( nonatomic ) int i;

@end

@implementation MyNotSoPlainStruct
@end

MyNotSoPlainStruct* foo = [MyNotSoPlainStruct new];
foo.image = …
foo.i = …

你去吧。

解决方案需要更多的行,这是事实,但您可以更好地控制事情的完成方式,包括图像生命周期。您可以使用强指针,如果它更适合您的需要,则可以使用弱指针。

当然,您也可以使用字典或数组。文字使这变得特别容易:

NSDictionary* arguments = @{ @"image" : <image>, @"i" : @( <int> ) };
arguments[@"i"].intValue returns the int you need.

很简单。

编辑

忘记转移部分了,哎呀:)。那么:

您必须使用以下注释:

void* argumentsPointer = (__bridge_retained void*) arguments;

参数被保留,并且该引用不再由 ARC 管理。

当你收到你的指针返回时,你必须转换它:

NSDictionary* arguments = (__bridge_transfer NSDictionary*) argumentsPointer;

如果最后一个已知引用消失,仅使用 __bridge 可能会导致指针悬空。如果您希望 void* 保留字典,则必须先使用 __bridge_retained,然后再使用 __bridge_transfer。

【讨论】:

  • 感谢面料。如果我使用 NSDictionary,我需要在将它传递给方法之前将其类型转换为 (__bridge void*)。对吗?
  • 在答案中添加了转移东西:)
  • 在指针上巧妙地使用__bridge_retained__bridge_transfer。没想到!
猜你喜欢
  • 2014-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-08
  • 2013-08-23
相关资源
最近更新 更多