【问题标题】:Objective-c object inside a typedef struct (forbidden in ARC)typedef 结构中的 Objective-c 对象(在 ARC 中被禁止)
【发布时间】:2012-12-03 22:41:01
【问题描述】:

我是 Objective-C 编程和 Xcode 的新手。我继承了一个项目的旧版本(3.2.5),最近将其转换为最新版本(4.5.2)。我将此项目转换为 ARC,但在 typedef 结构中找到的 Objective-c 对象存在问题:

typedef struct _BitmapFontChar {
    int charID;
    int x;
    int y;
    int width;
    int height;
    int xOffset;
    int yOffset;
    int xAdvance;
    Image * image; // Objective-C object in struct forbidden in ARC
    float scale;
} BitmapFontChar;

当我尝试使用 __unsafe __unretained_ 时,它在 ARC 中编译得很好,但该项目不再工作了。当然,*image 对象没有保留,我的项目崩溃了。

结构体使用如下:

@interface BitmapFont : NSObject {

    GameController * sharedGameController;
    Image * image;
    BitmapFontChar * charsArray; // typedef struct
    int commonHeight;
    Color4f fontColor;
}​
...

charsArray = calloc(kMaxCharsInFont, sizeof(BitmapFontChar));

如何将此代码转换为可以保留 *image 对象但也可以在 ARC 中使用的代码?

编辑: 好的,我使用了 Jano 的建议,使用 CFTypeRef。我仍然在同一行代码中遇到相同的崩溃(EXC_BAD_ACCESS)。我想我没有正确使用 CFBridgingRetain 。下面是我的 .h 文件:

#import "Global.h"

@class Image;
@class GameController;

#define kMaxCharsInFont 223


typedef struct _BitmapFontChar {
    int charID;
    int x;
    int y;
    int width;
    int height;
    int xOffset;
    int yOffset;
    int xAdvance;
    CFTypeRef image;
    float scale;
} BitmapFontChar;

enum {
    BitmapFontJustification_TopCentered,
    BitmapFontJustification_MiddleCentered,
    BitmapFontJustification_BottomCentered,
    BitmapFontJustification_TopRight,
    BitmapFontJustification_MiddleRight,
    BitmapFontJustification_BottomRight,
    BitmapFontJustification_TopLeft,
    BitmapFontJustification_MiddleLeft,
    BitmapFontJustification_BottomLeft
};

@interface BitmapFont : NSObject {

    GameController *sharedGameController;
    Image *image;
    BitmapFontChar *charsArray;
    int commonHeight;
    Color4f fontColor;
}

@property(nonatomic, strong) Image *image;
@property(nonatomic, assign) Color4f fontColor;

- (id)initWithFontImageNamed:(NSString*)aFileName ofType:(NSString*)aFileType 
  controlFile:(NSString*)aControlFile scale:(Scale2f)aScale filter:(GLenum)aFilter;

- (id)initWithImage:(Image *)aImage controlFile:(NSString *)aControlFile 
  scale:(Scale2f)aScale filter:(GLenum)aFilter;

-(void)renderStringAt:(CGPoint)aPoint text:(NSString*)aText;

-(void)renderStringJustifiedInFrame:(CGRect)aRect justification:(int)aJustification 
  text:(NSString*)aText;

-(int)getWidthForString:(NSString*)string;
-(int)getHeightForString:(NSString*)string;

@end

下面是我的 .m 文件的一部分,其中包含发生崩溃的方法和代码行:

-(void)renderStringAt:(CGPoint)aPoint text:(NSString*)aText {
    float xScale = image.scale.x;
    float yScale = image.scale.y;

    for(int i=0; i<[aText length]; i++) {

        unichar charID = [aText characterAtIndex:i] - 32;

        int y = aPoint.y + (commonHeight * yScale) - (charsArray[charID].height 
            + charsArray[charID].yOffset) * yScale;
        int x = aPoint.x + charsArray[charID].xOffset;
        CGPoint renderPoint = CGPointMake(x, y);

        CFTypeRef vpImage = CFBridgingRetain(image); //???
        ((__bridge Image *)(charsArray[charID].image)).color = fontColor;//CRASH EXC_BAD_ACCESS

        [((__bridge Image *)(charsArray[charID].image)) renderAtPoint:renderPoint];

        aPoint.x += charsArray[charID].xAdvance * xScale;
    }
}

再次感谢您的建议!

【问题讨论】:

    标签: xcode object struct automatic-ref-counting


    【解决方案1】:

    使用__unsafe_unretained,并重新引入该特定结构字段的显式保留/释放。大概这在以前有效,所以今天没有理由不能工作。

    当然,ARC 不允许您调用 -retain-release。但它确实允许您调用 CFRetain()CFRelease(),它们在 obj-c 对象上调用时会执行相同的操作。

    或者,如果您想将代码转换为 Obj-C++,您可以在 C++ 结构中嵌入 __strong 对象,编译器将为您生成正确的析构函数。

    【讨论】:

    • 对不起,我不相信我可以选择将项目转换为 Obj-C++。我可能是错的,但我认为苹果只接受 Obj-C 项目。对不起,之前没有说明这一点,但这个项目是一个苹果应用程序。
    • @user1873837:你被误导了。 Apple 不在乎你是使用 Obj-C++ 还是 C++,甚至用 Haskell 编写所有东西。
    【解决方案2】:

    如何将此代码转换为保留 *image 的内容 对象,但也可以在 ARC 中工作?

    一种方法是将struct _BitmapFontChar 转换为适当的Objective-C 类。然后引用其他 Obj-C 对象就可以了。

    【讨论】:

    • 我将如何使用这行代码来完成这项工作: charsArray = calloc(kMaxCharsInFont, sizeof(BitmapFontChar)); ?
    • 或者这行代码:charsArray[charID].image.color = fontColor;?抱歉,我还在学习 Objective-c。
    【解决方案3】:

    Kevin 和 Caleb 所说的。

    因为我想自己尝试一下,所以这里是 CodeRunner 的一个小例子:

    #import <Foundation/Foundation.h>
    int main(int argc, char *argv[]) {
        @autoreleasepool {
    
            typedef struct _person {
                char name[25];
                CFTypeRef avatar;
            } person;
    
            NSObject *avatar = [NSObject new];
            CFTypeRef vpAvatar = CFBridgingRetain(avatar);
            person carol = { "Carol", vpAvatar }; 
    
            CFBridgingRelease(carol.avatar);
        }
    }
    

    CFRefType 只是一个 void*,它是 __unsafe_unretained 的替代方案,CFBridging 函数将一个 Objc 指针投射到 Core Foundation (CFBridgingRetain) 并返回 (CFBridgingRelease)。

    最简单的事情似乎是创建一个轻量级对象并让 ARC 处理它。

    【讨论】:

    • “轻量级对象”的代码是什么样的?我宁愿让 ARC 处理我的所有对象。
    • 一个只包含您需要的变量。
    • 我在执行您使用 CFTypeRef 的建议时遇到问题。这些代码行出现错误: charsArray[charID].image.color = fontColor; [charsArray[charID].image renderAtPoint:renderPoint];错误是:成员引用基类型“CFTypeRef”(又名“const void *”)不是结构或联合。 ??
    • 听起来你正在调用void* 上的方法。您需要使用(__bridge type*) 将对象带回。试试[((__bridge Image*)(charsArray[charID].image)) renderAtPoint:renderPoint];
    • 谢谢亚诺!效果很好!错误消失了,但我的项目仍然在同一个地方以相同的 EXC_BAD_ACCESS 崩溃。我想我没有正确使用 CFBridgingRetain。我将把我的 .h 和我的 .m 文件的一部分添加到这个线程中。我最初应该这样做的。也许有人能看出我做错了什么。
    猜你喜欢
    • 2011-12-26
    • 2013-01-24
    • 1970-01-01
    • 2012-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-27
    • 2014-06-19
    相关资源
    最近更新 更多