Search code examples
iosarrayscore-text

Variable sized array of struct?


I want to make an array of structs of which the size is known only at runtime

NSMutableArray *styleSettingsArray = [NSMutableArray array];

NSString *fontAlignmentAttribute = [element attributeNamed:@"TextAlignment"];
if(fontAlignmentAttribute)
{
    CTTextAlignment alignment = [self getTextAlignment:fontAlignmentAttribute];
    CTParagraphStyleSetting styleSetting = {kCTParagraphStyleSpecifierAlignment, sizeof(CTTextAlignment), &alignment};
    [styleSettingsArray addObject:[NSValue valueWithBytes:&styleSettings objCType:@encode(CTParagraphStyleSetting)]];
}

// other posible attributes

CTParagraphStyleRef paragraphStyleRef = CTParagraphStyleCreate((__bridge const CTParagraphStyleSetting *)(styleSettingsArray), [styleSettingsArray count]);
[dictionary setObject:(__bridge id)(paragraphStyleRef) forKey:(NSString*)kCTParagraphStyleAttributeName];
CFRelease(paragraphStyleRef);

This code does not work.

EDIT:

CTParagraphStyleCreate takes a pointer to an array of CTParagraphStyleSetting, such as

CTParagraphStyleSetting styleSettings[] = {
    { kCTParagraphStyleSpecifierAlignment, sizeof(CTTextAlignment), alignment},
    {...},
    {...}
};

How can I allocate this array, and add stuff to it without knowing how much stuff will be in it ? (how do I use malloc ?)


Solution

  • To avoid having to collect the number of attributes and then create them in a second pass I suggest to use NSMutableData instead of a plain C array or malloc. This style would allow you to use your existing code with only minimal changes:

    NSMutableData *styleSettingsArray = [NSMutableData array];
    
    NSString *fontAlignmentAttribute = [element attributeNamed:@"TextAlignment"];
    CTTextAlignment alignment;
    if (fontAlignmentAttribute)
    {
        alignment = [self getTextAlignment:fontAlignmentAttribute];
        CTParagraphStyleSetting styleSetting = { kCTParagraphStyleSpecifierAlignment, sizeof(CTTextAlignment), &alignment};
        [styleSettingsArray appendBytes:&styleSetting length:sizeof(styleSetting)];
    }
    
    // other posible attributes
    CTParagraphStyleRef paragraphStyleRef = CTParagraphStyleCreate([styleSettingsArray bytes], [styleSettingsArray length] / sizeof(CTParagraphStyleSetting));
    

    Edit: Please note the extension of the lifetime of the alignment variable, compared to your code. This is necessary because it is referenced after the block ends in which it was declared before.