Swift: Fetching type encoding

The always wonderful John Holdsworth has put together a replacement ivar_getTypeEncoding() written for Swift classes as part of his XprobePlugin pack. He tells me this is under an MIT license. Update: John asks me to change that to public domain.

/*****************************************************
 ********* ivar_getTypeEncoding() for swift **********
 *****************************************************/

struct _swift_class;

struct _swift_type {
    unsigned long flags;
    const char *typeIdent;
};

struct _swift_field {
    unsigned long flags;
    union {
        struct _swift_type *typeInfo;
        Class objcClass;
    };
    void *unknown;
    struct _swift_field *conditional;
    union {
        struct _swift_class *swiftClass;
        struct _swift_field *subType;
    };
    struct _swift_field *extraType;
};

struct _swift_data {
    unsigned long flags;
    const char *className;
    int fieldcount, flasg2;
    const char *ivarNames;
    struct _swift_field **(*get_field_data)();
};

struct _swift_class {
    union {
        Class meta;
        unsigned long flags;
    };
    Class supr;
    void *buckets, *vtable, *pdata;
    int size, tos, mds, eight;
    struct _swift_data *swiftData;
};

static const char *typeInfoForName( const char *name ) {
    return strdup([[NSString stringWithFormat:@"@\"%s\"", name] UTF8String]);
}

static const char *typeInfoForClass( Class aClass ) {
    return typeInfoForName( class_getName(aClass) );
}

static const char *ivar_getTypeEncodingSwift( Ivar ivar, Class aClass ) {
    struct _swift_class *swiftClass = (__bridge struct _swift_class *)aClass;
    if ( !((unsigned long)swiftClass->pdata & 0x1) )
        return ivar_getTypeEncoding( ivar );

    struct _swift_data *swiftData = swiftClass->swiftData;
    const char *nameptr = swiftData->ivarNames;
    const char *name = ivar_getName(ivar);
    int ivarIndex;

    for ( ivarIndex=0 ; ivarIndexfieldcount ; ivarIndex++ )
        if ( strcmp(name,nameptr) == 0 )
            break;
        else
            nameptr += strlen(nameptr)+1;

    if ( ivarIndex == swiftData->fieldcount )
        return NULL;

    struct _swift_field **swiftFields = swiftData->get_field_data();
    struct _swift_field *field = swiftFields[ivarIndex];
    struct _swift_class *ivarClass = field->swiftClass;

    // this could probably be tidied up if I knew what was going on...
    if ( field->flags == 0x2 && (field->conditional->flags > 0x2 || (ivarClass && ivarClass->flags>0x2) ) )
        return typeInfoForName(field->typeInfo->typeIdent);
    else if ( field->flags == 0xe )
        return typeInfoForClass(field->objcClass);
    else if ( field->conditional && field->conditional->flagsconditional->flags == 0xe )
            return typeInfoForClass(field->conditional->objcClass);
        else
            return field->conditional->typeInfo->typeIdent+1;
    }
    else if ( !ivarClass )
        return field->typeInfo->typeIdent+1;
    else if ( ivarClass->flags == 0x1 )
        return field->subType->typeInfo->typeIdent+1;
    else if ( ivarClass->flags == 0xe )
        return typeInfoForClass(field->subType->objcClass);
    else
        return typeInfoForClass((__bridge Class)ivarClass);
}

2 Comments

  • Hey Erica, just wanted to let you know the code doesn’t compile as it is. `ivarIndexfieldcount` is not defined and there’s an extra `}` somewhere in those chained `if – else` Cheers!

    • The post is from June 2014. I think there’s a 2-week statute of limitations with Swift in terms of language changes.