2

我是 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 中使用的代码?

编辑:好的,我使用 CFTypeRef 使用 Jano 的建议。我仍然在同一行代码中遇到相同的崩溃(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;
    }
}

再次感谢您的建议!

4

3 回答 3

1

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

当然,ARC 不允许你调用-retainand -release。但它确实允许你调用CFRetain()and CFRelease(),当在 obj-c 对象上调用时它会做同样的事情。

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

于 2012-12-03T22:51:59.533 回答
0

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

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

于 2012-12-03T22:45:05.963 回答
-1

What Kevin and Caleb said.

Since I wanted to try this myself here is a small example for 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 is just a void* which is the alternative to __unsafe_unretained, and the CFBridging functions cast an Objc pointer to Core Foundation (CFBridgingRetain) and back (CFBridgingRelease).

The easiest thing seems to be creating a lightweight object and let ARC handle it.

于 2012-12-03T23:38:54.030 回答