ऑब्जेक्टिव-सी में ऑब्जेक्ट प्रॉपर्टी लिस्ट प्राप्त करें


109

मैं ऑब्जेक्ट-सी में दिए गए ऑब्जेक्ट गुणों की सूची ( NSArrayया के रूप में NSDictionary) कैसे प्राप्त कर सकता हूं ?

इस परिदृश्य की कल्पना करें: मैंने एक मूल वर्ग को परिभाषित किया है NSObject, जो कि सिर्फ एक है NSString, जो गुणों के रूप में एक , BOOLऔर एक NSDataवस्तु रखता है । फिर मेरे पास कई वर्ग हैं जो इस मूल वर्ग का विस्तार करते हैं, प्रत्येक में बहुत सारे गुण हैं।

वहाँ किसी भी तरह से मैं पर एक उदाहरण विधि को लागू कर सकता है माता पिता कि पूरी वस्तु और रिटर्न, कहते हैं, एक के माध्यम से चला जाता है वर्ग NSArrayवर्ग गुण (बच्चे) में से प्रत्येक के रूप में NSStringsकर रहे हैं नहीं तो मैं बाद में यह उपयोग कर सकते हैं, माता पिता के वर्ग पर NSStringकेवीसी के लिए?

जवाबों:


116

मैं बस खुद ही जवाब पाने में कामयाब रहा। ओबज-सी रनटाइम लाइब्रेरी का उपयोग करके, मुझे उन संपत्तियों तक पहुंच प्राप्त हुई जो मैं चाहता था:

- (void)myMethod {
    unsigned int outCount, i;
    objc_property_t *properties = class_copyPropertyList([self class], &outCount);
    for(i = 0; i < outCount; i++) {
        objc_property_t property = properties[i];
        const char *propName = property_getName(property);
        if(propName) {
            const char *propType = getPropertyType(property);
            NSString *propertyName = [NSString stringWithCString:propName
                                                                encoding:[NSString defaultCStringEncoding]];
            NSString *propertyType = [NSString stringWithCString:propType
                                                                encoding:[NSString defaultCStringEncoding]];
            ...
        }
    }
    free(properties);
}

इसने मुझे 'गेटप्रोपरेटाइप' सी फ़ंक्शन बनाने के लिए आवश्यक किया, जो मुख्य रूप से एक Apple कोड नमूने से लिया गया है (अभी सटीक स्रोत याद नहीं कर सकता):

static const char *getPropertyType(objc_property_t property) {
    const char *attributes = property_getAttributes(property);
    char buffer[1 + strlen(attributes)];
    strcpy(buffer, attributes);
    char *state = buffer, *attribute;
    while ((attribute = strsep(&state, ",")) != NULL) {
        if (attribute[0] == 'T') {
            if (strlen(attribute) <= 4) {
                break;
            }
            return (const char *)[[NSData dataWithBytes:(attribute + 3) length:strlen(attribute) - 4] bytes];
        }
    }
    return "@";
}

5
इसके अलावा +1 आदिमों पर त्रुटि करेगा, जैसे इंट। कृपया इसी चीज़ के थोड़े वर्धित संस्करण के लिए मेरा उत्तर नीचे देखें।
jpswain

1
शुद्धता के मामले में, के [NSString stringWithCString:]पक्ष में पदावनत किया जाता है [NSString stringWithCString:encoding:]
zekel

4
Objc रनटाइम हेडर आयात करना चाहिए #import <objc / runtime.h> यह ARC पर काम करता है।
Da KIM

यहां बताया गया है कि स्विफ्ट का उपयोग करके इसे कैसे पूरा किया जाता है।
रामिस

76

@ boliva का उत्तर अच्छा है, लेकिन आदिमों को संभालने के लिए थोड़ा अतिरिक्त चाहिए, जैसे int, long, float, double, आदि।

मैंने इस कार्यक्षमता को जोड़ने के लिए उसका निर्माण किया।

// PropertyUtil.h
#import 

@interface PropertyUtil : NSObject

+ (NSDictionary *)classPropsFor:(Class)klass;

@end


// PropertyUtil.m
#import "PropertyUtil.h"
#import "objc/runtime.h"

@implementation PropertyUtil

static const char * getPropertyType(objc_property_t property) {
    const char *attributes = property_getAttributes(property);
    printf("attributes=%s\n", attributes);
    char buffer[1 + strlen(attributes)];
    strcpy(buffer, attributes);
    char *state = buffer, *attribute;
    while ((attribute = strsep(&state, ",")) != NULL) {
        if (attribute[0] == 'T' && attribute[1] != '@') {
            // it's a C primitive type:
            /* 
                if you want a list of what will be returned for these primitives, search online for
                "objective-c" "Property Attribute Description Examples"
                apple docs list plenty of examples of what you get for int "i", long "l", unsigned "I", struct, etc.            
            */
            return (const char *)[[NSData dataWithBytes:(attribute + 1) length:strlen(attribute) - 1] bytes];
        }        
        else if (attribute[0] == 'T' && attribute[1] == '@' && strlen(attribute) == 2) {
            // it's an ObjC id type:
            return "id";
        }
        else if (attribute[0] == 'T' && attribute[1] == '@') {
            // it's another ObjC object type:
            return (const char *)[[NSData dataWithBytes:(attribute + 3) length:strlen(attribute) - 4] bytes];
        }
    }
    return "";
}


+ (NSDictionary *)classPropsFor:(Class)klass
{    
    if (klass == NULL) {
        return nil;
    }

    NSMutableDictionary *results = [[[NSMutableDictionary alloc] init] autorelease];

    unsigned int outCount, i;
    objc_property_t *properties = class_copyPropertyList(klass, &outCount);
    for (i = 0; i < outCount; i++) {
        objc_property_t property = properties[i];
        const char *propName = property_getName(property);
        if(propName) {
            const char *propType = getPropertyType(property);
            NSString *propertyName = [NSString stringWithUTF8String:propName];
            NSString *propertyType = [NSString stringWithUTF8String:propType];
            [results setObject:propertyType forKey:propertyName];
        }
    }
    free(properties);

    // returning a copy here to make sure the dictionary is immutable
    return [NSDictionary dictionaryWithDictionary:results];
}




@end

1
क्या आपके पास #import <Foundation/Foundation.h>.h फ़ाइल के शीर्ष पर होने का इरादा है ?
एंड्रयू

2
[NSString stringWithUTF8String: propType] "PropType const char *" NSNumber \ x94 \ xfdk को पार्स नहीं कर सकता है, और एक nil स्ट्रिंग देता है ... पता नहीं यह इतना अजीब NSNumber क्यों है। Mb क्योंकि ActiveRecord?
Dumoko

उत्तम! बहुत बहुत धन्यवाद।
अज़िक अब्दुल्ला

यह बिल्कुल सही है!
प्रणॉय सी

28

@ ऑरेंज 80 के जवाब में एक समस्या है: यह वास्तव में हमेशा 0 के साथ स्ट्रिंग को समाप्त नहीं करता है। यह दुर्घटनाग्रस्त होने जैसे अप्रत्याशित परिणामों को जन्म दे सकता है, जबकि इसे UTF8 में बदलने की कोशिश की जा रही है (मैं वास्तव में सिर्फ इस वजह से एक बहुत कष्टप्रद क्रैशबग था। मजेदार डेब्यू कर रहा था ^ ^)। मैंने इसे वास्तव में एक NSString विशेषता से प्राप्त किया और फिर cStringUsingEncoding: को कॉल करके इसे ठीक किया। यह अब एक आकर्षण की तरह काम करता है। (एआरसी के साथ भी काम करता है, कम से कम मेरे लिए)

तो यह अब कोड का मेरा संस्करण है:

// PropertyUtil.h
#import 

@interface PropertyUtil : NSObject

+ (NSDictionary *)classPropsFor:(Class)klass;

@end


// PropertyUtil.m
#import "PropertyUtil.h"
#import <objc/runtime.h>

@implementation PropertyUtil

static const char *getPropertyType(objc_property_t property) {
    const char *attributes = property_getAttributes(property);
    //printf("attributes=%s\n", attributes);
    char buffer[1 + strlen(attributes)];
    strcpy(buffer, attributes);
    char *state = buffer, *attribute;
    while ((attribute = strsep(&state, ",")) != NULL) {
        if (attribute[0] == 'T' && attribute[1] != '@') {
            // it's a C primitive type:
            /*
             if you want a list of what will be returned for these primitives, search online for
             "objective-c" "Property Attribute Description Examples"
             apple docs list plenty of examples of what you get for int "i", long "l", unsigned "I", struct, etc.
             */
            NSString *name = [[NSString alloc] initWithBytes:attribute + 1 length:strlen(attribute) - 1 encoding:NSASCIIStringEncoding];
            return (const char *)[name cStringUsingEncoding:NSASCIIStringEncoding];
        }
        else if (attribute[0] == 'T' && attribute[1] == '@' && strlen(attribute) == 2) {
            // it's an ObjC id type:
            return "id";
        }
        else if (attribute[0] == 'T' && attribute[1] == '@') {
            // it's another ObjC object type:
            NSString *name = [[NSString alloc] initWithBytes:attribute + 3 length:strlen(attribute) - 4 encoding:NSASCIIStringEncoding];
            return (const char *)[name cStringUsingEncoding:NSASCIIStringEncoding];
        }
    }
    return "";
}


+ (NSDictionary *)classPropsFor:(Class)klass
{
    if (klass == NULL) {
        return nil;
    }

    NSMutableDictionary *results = [[NSMutableDictionary alloc] init];

    unsigned int outCount, i;
    objc_property_t *properties = class_copyPropertyList(klass, &outCount);
    for (i = 0; i < outCount; i++) {
        objc_property_t property = properties[i];
        const char *propName = property_getName(property);
        if(propName) {
            const char *propType = getPropertyType(property);
            NSString *propertyName = [NSString stringWithUTF8String:propName];
            NSString *propertyType = [NSString stringWithUTF8String:propType];
            [results setObject:propertyType forKey:propertyName];
        }
    }
    free(properties);

    // returning a copy here to make sure the dictionary is immutable
    return [NSDictionary dictionaryWithDictionary:results];
}

@end

@farthen क्या आप एक उदाहरण प्रदान कर सकते हैं जो मेरे द्वारा प्रदान किए गए कोड के साथ समस्या को प्रदर्शित करता है? मैं इसे देखने के लिए उत्सुक हूं।
21

@ नारंगी 80 खैर, AFAIR डेटा कभी भी शून्य-टर्मिनेटेड नहीं है। यदि ऐसा है तो यह केवल दुर्घटना पर होता है। हालांकि हो सकता है कि मैं गलत हूं। अन्य समाचार में: मेरे पास अभी भी यह कोड चल रहा है और यह रॉक सॉलिड चलाता है: p
felinira

@ Orange80 मैं इस समस्या में भाग गया, जो Google के IMA विज्ञापन लाइब्रेरी से IMAAdRequest पर आपके संस्करण को लागू करने की कोशिश कर रहा है। दूर के समाधान ने इसे हल कर दिया।
क्रिस्टोफर पिक्सले

धन्यवाद। यह मेरे लिए iOS7 में काम किया जब पिछले दो उत्तर नहीं थे। +1 सभी के लिए
क्रिस एचएच

यह एकमात्र उत्तर है जिसने मेरे लिए काम किया। बाकी सब कुछ मुझे "NSString \ x8d \ xc0 \ xd9" संपत्ति के प्रकारों के लिए विचित्रता दे रहा था, शायद इसलिए क्योंकि चार * साइज़ बंद था
ब्रायन Colavito

8

जब मैंने iOS 3.2 के साथ प्रयास किया, तो getPropertyType फ़ंक्शन संपत्ति विवरण के साथ अच्छी तरह से काम नहीं करता है। मुझे iOS दस्तावेज़ीकरण से एक उदाहरण मिला: "उद्देश्य-सी रनटाइम प्रोग्रामिंग गाइड: घोषित गुण"।

यहां आईओएस 3.2 में संपत्ति लिस्टिंग के लिए एक संशोधित कोड है:

#import <objc/runtime.h>
#import <Foundation/Foundation.h>
...
unsigned int outCount, i;
objc_property_t *properties = class_copyPropertyList([UITouch class], &outCount);
for(i = 0; i < outCount; i++) {
    objc_property_t property = properties[i];
    fprintf(stdout, "%s %s\n", property_getName(property), property_getAttributes(property));
}
free(properties);

7

मैंने पाया है कि बॉइवा का समाधान सिम्युलेटर में ठीक काम करता है, लेकिन डिवाइस पर निश्चित लंबाई के विकल्प के कारण समस्याएं होती हैं। मैंने डिवाइस पर काम करने वाली इस समस्या के लिए एक अधिक उद्देश्य-सी-अनुकूल समाधान लिखा है। अपने संस्करण में, मैं विशेषताओं के सी-स्ट्रिंग को एक एनएसएसट्रिंग में परिवर्तित करता हूं और इस पर स्ट्रिंग ऑपरेशन करता हूं ताकि केवल टाइप विवरण का एक विकल्प मिल सके।

/*
 * @returns A string describing the type of the property
*/

+ (NSString *)propertyTypeStringOfProperty:(objc_property_t) property {
    const char *attr = property_getAttributes(property);
    NSString *const attributes = [NSString stringWithCString:attr encoding:NSUTF8StringEncoding];

    NSRange const typeRangeStart = [attributes rangeOfString:@"T@\""];  // start of type string
    if (typeRangeStart.location != NSNotFound) {
        NSString *const typeStringWithQuote = [attributes substringFromIndex:typeRangeStart.location + typeRangeStart.length];
        NSRange const typeRangeEnd = [typeStringWithQuote rangeOfString:@"\""]; // end of type string
        if (typeRangeEnd.location != NSNotFound) {
            NSString *const typeString = [typeStringWithQuote substringToIndex:typeRangeEnd.location];
            return typeString;
        }
    }
    return nil;
}

/**
* @returns (NSString) Dictionary of property name --> type
*/

+ (NSDictionary *)propertyTypeDictionaryOfClass:(Class)klass {
    NSMutableDictionary *propertyMap = [NSMutableDictionary dictionary];
    unsigned int outCount, i;
    objc_property_t *properties = class_copyPropertyList(klass, &outCount);
    for(i = 0; i < outCount; i++) {
        objc_property_t property = properties[i];
        const char *propName = property_getName(property);
        if(propName) {

            NSString *propertyName = [NSString stringWithCString:propName encoding:NSUTF8StringEncoding];
            NSString *propertyType = [self propertyTypeStringOfProperty:property];
            [propertyMap setValue:propertyType forKey:propertyName];
        }
    }
    free(properties);
    return propertyMap;
}

यह NSRange const typeRangeStart = [विशेषताएँ रेंजऑफस्ट्रिंग: @ "T @ \"] पर एक EXC_BAD_ACCESS अपवाद फेंकें; // टाइप स्ट्रिंग की शुरुआत
एडम मेंडोज़ा

6

यह कार्यान्वयन दोनों उद्देश्य-सी वस्तु प्रकार और सी आदिम के साथ काम करता है। यह आईओएस 8 संगत है। यह वर्ग तीन वर्ग विधियाँ प्रदान करता है:

+ (NSDictionary *) propertiesOfObject:(id)object;

किसी वस्तु के सभी दृश्य गुणों का शब्दकोश देता है, जिसमें उसके सभी सुपरक्लास शामिल हैं।

+ (NSDictionary *) propertiesOfClass:(Class)class;

एक वर्ग के सभी दृश्य गुणों का एक शब्दकोश लौटाता है, जिसमें उसके सभी सुपरक्लास शामिल हैं।

+ (NSDictionary *) propertiesOfSubclass:(Class)class;

सभी दृश्य गुणों का एक शब्दकोश देता है जो एक उपवर्ग के लिए विशिष्ट होता है। इसके सुपरक्लास के लिए गुण शामिल नहीं हैं।

इन विधियों के उपयोग का एक उपयोगी उदाहरण किसी ऑब्जेक्ट को उप-विधि उदाहरण में कॉपी करना है, जो किसी प्रतिलिपि पद्धति में गुणों को निर्दिष्ट किए बिना ऑब्जेक्टिव-सी में उप-वर्ग उदाहरण के लिए है। । इस उत्तर के हिस्से इस प्रश्न के अन्य उत्तरों पर आधारित हैं, लेकिन यह वांछित कार्यक्षमता के लिए एक क्लीनर इंटरफ़ेस प्रदान करता है।

हैडर:

//  SYNUtilities.h

#import <Foundation/Foundation.h>

@interface SYNUtilities : NSObject
+ (NSDictionary *) propertiesOfObject:(id)object;
+ (NSDictionary *) propertiesOfClass:(Class)class;
+ (NSDictionary *) propertiesOfSubclass:(Class)class;
@end

कार्यान्वयन:

//  SYNUtilities.m

#import "SYNUtilities.h"
#import <objc/objc-runtime.h>

@implementation SYNUtilities
+ (NSDictionary *) propertiesOfObject:(id)object
{
    Class class = [object class];
    return [self propertiesOfClass:class];
}

+ (NSDictionary *) propertiesOfClass:(Class)class
{
    NSMutableDictionary * properties = [NSMutableDictionary dictionary];
    [self propertiesForHierarchyOfClass:class onDictionary:properties];
    return [NSDictionary dictionaryWithDictionary:properties];
}

+ (NSDictionary *) propertiesOfSubclass:(Class)class
{
    if (class == NULL) {
        return nil;
    }

    NSMutableDictionary *properties = [NSMutableDictionary dictionary];
    return [self propertiesForSubclass:class onDictionary:properties];
}

+ (NSMutableDictionary *)propertiesForHierarchyOfClass:(Class)class onDictionary:(NSMutableDictionary *)properties
{
    if (class == NULL) {
        return nil;
    }

    if (class == [NSObject class]) {
        // On reaching the NSObject base class, return all properties collected.
        return properties;
    }

    // Collect properties from the current class.
    [self propertiesForSubclass:class onDictionary:properties];

    // Collect properties from the superclass.
    return [self propertiesForHierarchyOfClass:[class superclass] onDictionary:properties];
}

+ (NSMutableDictionary *) propertiesForSubclass:(Class)class onDictionary:(NSMutableDictionary *)properties
{
    unsigned int outCount, i;
    objc_property_t *objcProperties = class_copyPropertyList(class, &outCount);
    for (i = 0; i < outCount; i++) {
        objc_property_t property = objcProperties[i];
        const char *propName = property_getName(property);
        if(propName) {
            const char *propType = getPropertyType(property);
            NSString *propertyName = [NSString stringWithUTF8String:propName];
            NSString *propertyType = [NSString stringWithUTF8String:propType];
            [properties setObject:propertyType forKey:propertyName];
        }
    }
    free(objcProperties);

    return properties;
}

static const char *getPropertyType(objc_property_t property) {
    const char *attributes = property_getAttributes(property);
    char buffer[1 + strlen(attributes)];
    strcpy(buffer, attributes);
    char *state = buffer, *attribute;
    while ((attribute = strsep(&state, ",")) != NULL) {
        if (attribute[0] == 'T' && attribute[1] != '@') {
            // A C primitive type:
            /*
             For example, int "i", long "l", unsigned "I", struct.
             Apple docs list plenty of examples of values returned. For a list
             of what will be returned for these primitives, search online for
             "Objective-c" "Property Attribute Description Examples"
             */
            NSString *name = [[NSString alloc] initWithBytes:attribute + 1 length:strlen(attribute) - 1 encoding:NSASCIIStringEncoding];
            return (const char *)[name cStringUsingEncoding:NSASCIIStringEncoding];
        }
        else if (attribute[0] == 'T' && attribute[1] == '@' && strlen(attribute) == 2) {
            // An Objective C id type:
            return "id";
        }
        else if (attribute[0] == 'T' && attribute[1] == '@') {
            // Another Objective C id type:
            NSString *name = [[NSString alloc] initWithBytes:attribute + 3 length:strlen(attribute) - 4 encoding:NSASCIIStringEncoding];
            return (const char *)[name cStringUsingEncoding:NSASCIIStringEncoding];
        }
    }
    return "";
}

@end

मुझे इस लाइन पर एक EXC_BAD_ACCESS अपवाद मिलता है NSString * नाम = [[NSString आवंटित] initWithBytes: विशेषता + 1 लंबाई: strlen (विशेषता) - 1 एन्कोडिंग: NSASCIISringEncoding];
एडम मेंडोज़ा

4

यदि किसी को अभिभावक वर्गों से विरासत में मिली संपत्तियों की आवश्यकता है (जैसा कि मैंने किया) तो इसे पुनरावर्ती बनाने के लिए " नारंगी 80 " कोड पर कुछ संशोधन किया गया है :

+ (NSDictionary *)classPropsForClassHierarchy:(Class)klass onDictionary:(NSMutableDictionary *)results
{
    if (klass == NULL) {
        return nil;
    }

    //stop if we reach the NSObject class as is the base class
    if (klass == [NSObject class]) {
        return [NSDictionary dictionaryWithDictionary:results];
    }
    else{

        unsigned int outCount, i;
        objc_property_t *properties = class_copyPropertyList(klass, &outCount);
        for (i = 0; i < outCount; i++) {
            objc_property_t property = properties[i];
            const char *propName = property_getName(property);
            if(propName) {
                const char *propType = getPropertyType(property);
                NSString *propertyName = [NSString stringWithUTF8String:propName];
                NSString *propertyType = [NSString stringWithUTF8String:propType];
                [results setObject:propertyType forKey:propertyName];
            }
        }
        free(properties);

        //go for the superclass
        return [PropertyUtil classPropsForClassHierarchy:[klass superclass] onDictionary:results];

    }
}

1
क्या हम इसे एक श्रेणी नहीं बना सकते हैं और इसके साथ NSObject का विस्तार कर सकते हैं इसलिए यह कार्यक्षमता NSObject के बच्चे के लिए हर वर्ग में बनाई गई है?
एलेक्स ज़ावाटोन

यह एक अच्छा विचार लगता है, अगर मैं समय पा सकता हूं तो उस विकल्प के साथ उत्तर को अपडेट करूंगा।
पाकीटो वी

एक बार जब आप इसके साथ हो जाते हैं, तो मेरे पास समय होने पर एक विधि डंप जोड़ दूँगा। यह समय है जब हमें प्रत्येक एनएसओबजेक्ट के शीर्ष पर वास्तविक वस्तु संपत्ति और विधि आत्मनिरीक्षण मिला।
एलेक्स ज़ावाटोन

मैं वैल्यू आउटपुट को जोड़ने पर काम कर रहा हूं, लेकिन ऐसा प्रतीत होता है कि कुछ संरचनाओं (रेक्ट्स) के लिए, प्रकार संपत्ति का वास्तविक मूल्य है। यह एक दृश्य के रूप में एक TableViewController और अन्य अहस्ताक्षरित intsController की वापसी के मामले में है या उद्देश्य-सी रनटाइम डॉक्स के साथ संघर्ष के प्रकार के रूप में एफ। इसे पूर्ण रूप से प्राप्त करने के लिए स्पष्ट रूप से अधिक कार्य की आवश्यकता है। डेवलपर
.apple.com/library/mac/documentation/cocoa/conceptual/…

मैं एक नज़र दे रहा था लेकिन एक समस्या है जिसे मैं हल नहीं कर सकता, इसे पुनरावर्ती बनाने के लिए मुझे सुपरक्लास के लिए विधि को कॉल करने की आवश्यकता है (जैसे कि पिछले कोड की अंतिम पंक्ति में) क्योंकि NSObject रूट वर्ग है जो किसी श्रेणी के अंदर काम नहीं करेगा । तो कोई पुनरावृत्ति संभव नहीं ... :( यकीन नहीं अगर NSObject में एक वर्ग अब और जाने का रास्ता है ...
PakitoV

3

"गुण" शब्द थोड़ा फजी है। क्या आपका मतलब उदाहरण चर, गुण, तरीके जो एक्सेसरों की तरह दिखते हैं?

तीनों का जवाब है "हाँ, लेकिन यह बहुत आसान नहीं है।" ऑब्जेक्टिव-सी क्रम एपीआई इवर सूची, विधि सूची या एक वर्ग के लिए संपत्ति सूची प्राप्त करने के कार्य शामिल हैं (जैसे, class_copyPropertyList()), और फिर प्रत्येक प्रकार के लिए एक इसी समारोह सूची में किसी आइटम के नाम प्राप्त करने के लिए (जैसे, property_getName())।

सभी के सभी, इसे सही तरीके से प्राप्त करने के लिए बहुत सारे काम कर सकते हैं, या कम से कम बहुत से लोग जो वास्तव में एक तुच्छ सुविधा के लिए करते हैं, उसके लिए बहुत कुछ करना चाहते हैं।

वैकल्पिक रूप से, आप बस एक रूबी / पायथन स्क्रिप्ट लिख सकते हैं जो सिर्फ हेडर फ़ाइल पढ़ता है और जो कुछ भी आप वर्ग के लिए "गुण" पर विचार करेंगे उसके लिए देखता है।


हाय चक, आपकी प्रतिक्रिया के लिए धन्यवाद। मैं 'विशेषताओं' के साथ जो उल्लेख कर रहा था, वह वास्तव में एक वर्ग गुण था। ओब्ज-सी रनटाइम लाइब्रेरी का उपयोग करके जो मैं चाहता था, उसे पूरा करने में मैं पहले से ही कामयाब रहा। हेडर फ़ाइल को पार्स करने के लिए एक स्क्रिप्ट का उपयोग करना, जो मुझे रनटाइम पर आवश्यक था, उसके लिए काम नहीं करना चाहिए।
boliva

3

मैं ARC ENABLED के साथ काम करने के लिए @ Orange80 का जवाब पाने में सक्षम था ... ... मैं जो चाहता था - कम से कम ... लेकिन बिना किसी परीक्षण और त्रुटि के। उम्मीद है कि यह अतिरिक्त जानकारी किसी को दु: ख पहुंचा सकती है।

अपने उत्तर में वर्णित उन वर्गों को बचाएं = एक वर्ग के रूप में, और आपके AppDelegate.h(या जो भी), में डालें #import PropertyUtil.h। फिर अपने में ...

- (void)applicationDidFinishLaunching:
         (NSNotification *)aNotification {

विधि (या जो भी हो)

PropertyUtil *props  = [PropertyUtil new];  
NSDictionary *propsD = [PropertyUtil classPropsFor:
                          (NSObject*)[gist class]];  
NSLog(@"%@, %@", props, propsD);

राज़ आपकी कक्षा के उदाहरण चर ( इस मामले में मेरी कक्षा है Gist, और मेरे उदाहरण Gistहैgist ) को कास्ट करना है , जिसे आप ... NSObject ... (id)आदि से क्वेरी करना चाहते हैं , इसे काट नहीं पाएंगे .. विभिन्न, अजीबों के लिए , गूढ़ कारण। यह आपको ऐसा कुछ आउटपुट देगा…

<PropertyUtil: 0x7ff0ea92fd90>, {
apiURL = NSURL;
createdAt = NSDate;
files = NSArray;
gistDescription = NSString;
gistId = NSString;
gitPullURL = NSURL;
gitPushURL = NSURL;
htmlURL = NSURL;
isFork = c;
isPublic = c;
numberOfComments = Q;
updatedAt = NSDate;
userLogin = NSString;
}

Apple के सभी अनाकर्षक / OCD के बारे में ObjC के "amazeballs" "आत्मनिरीक्षण के बारे में डींग मारने के लिए ... उन्हें यकीन है कि इस सरल" लुक "को" किसी के स्वयं "," ऐसा बोलने "के लिए करना आसान नहीं है।

यदि आप वास्तव में हॉग वाइल्ड जाना चाहते हैं .. तो देखें .. क्लास-डंप , जो किसी भी निष्पादन योग्य, आदि के हेडर के रूप में झांकने के लिए एक मनमौजी पागल तरीका है ... यह आपकी कक्षाओं में एक बहुत बड़ा रूप प्रदान करता है ... कि मैं व्यक्तिगत रूप से, वास्तव में मददगार - कई, कई परिस्थितियों में। यह वास्तव में इसलिए है कि मैंने ओपी के सवाल का हल ढूंढना शुरू कर दिया। यहाँ कुछ उपयोग पैरामीटर हैं .. आनंद लें!

    -a             show instance variable offsets
    -A             show implementation addresses
    --arch <arch>  choose a specific architecture from a universal binary (ppc, ppc64, i386, x86_64)
    -C <regex>     only display classes matching regular expression
    -f <str>       find string in method name
    -I             sort classes, categories, and protocols by inheritance (overrides -s)
    -r             recursively expand frameworks and fixed VM shared libraries
    -s             sort classes and categories by name
    -S             sort methods by name

3

आपके पास तीन जादू के मंत्र हैं

Ivar* ivars = class_copyIvarList(clazz, &count); // to get all iVars
objc_property_t  *properties = class_copyPropertyList(clazz, &count); //to get all properties of a class 
Method* methods = class_copyMethodList(clazz, &count); // to get all methods of a class.

निम्नलिखित कोड का टुकड़ा आपकी मदद कर सकता है।

-(void) displayClassInfo
{
    Class clazz = [self class];
    u_int count;

    Ivar* ivars = class_copyIvarList(clazz, &count);
    NSMutableArray* ivarArray = [NSMutableArray arrayWithCapacity:count];
    for (int i = 0; i < count ; i++)
    {
        const char* ivarName = ivar_getName(ivars[i]);
        ivarArray addObject:[NSString  stringWithCString:ivarName encoding:NSUTF8StringEncoding]];
    }
    free(ivars);

    objc_property_t* properties = class_copyPropertyList(clazz, &count);
    NSMutableArray* propertyArray = [NSMutableArray arrayWithCapacity:count];
    for (int i = 0; i < count ; i++)
    {
        const char* propertyName = property_getName(properties[i]);
        [propertyArray addObject:[NSString  stringWithCString:propertyName encoding:NSUTF8StringEncoding]];
    }
    free(properties);

    Method* methods = class_copyMethodList(clazz, &count);
    NSMutableArray* methodArray = [NSMutableArray arrayWithCapacity:count];
    for (int i = 0; i < count ; i++)
    {
        SEL selector = method_getName(methods[i]);
        const char* methodName = sel_getName(selector);
        [methodArray addObject:[NSString  stringWithCString:methodName encoding:NSUTF8StringEncoding]];
    }
    free(methods);

    NSDictionary* classInfo = [NSDictionary dictionaryWithObjectsAndKeys:
                           ivarArray, @"ivars",
                           propertyArray, @"properties",
                           methodArray, @"methods",
                           nil];

        NSLog(@"%@", classInfo);
}

2

मैं दिए गए फ़ंक्शन बोलिवा का उपयोग कर रहा था, लेकिन जाहिरा तौर पर इसने iOS 7 के साथ काम करना बंद कर दिया। इसलिए अब स्थैतिक कॉन्स्ट चार्ज * getPropertyType (objc_property_t प्रॉपर्टी) के बजाय एक निम्नलिखित का उपयोग कर सकते हैं:

- (NSString*) classOfProperty:(NSString*)propName{

objc_property_t prop = class_getProperty([self class], [propName UTF8String]);
if (!prop) {
    // doesn't exist for object
    return nil;
}
const char * propAttr = property_getAttributes(prop);
NSString *propString = [NSString stringWithUTF8String:propAttr];
NSArray *attrArray = [propString componentsSeparatedByString:@","];
NSString *class=[attrArray objectAtIndex:0];
return [[class stringByReplacingOccurrencesOfString:@"\"" withString:@""] stringByReplacingOccurrencesOfString:@"T@" withString:@""];
}

तुम मेरे नायक हो। मुझे अभी भी कुछ चीजों को मैन्युअल रूप से सही करना है (किसी कारण से BOOLs 'Tc' के रूप में आ रहे हैं), लेकिन इसने मुझे वास्तव में फिर से काम करने की अनुमति दी।
हरपस्तुम

प्रिमिटिव्स का अपना प्रकार है, "@" ऑब्जेक्ट्स को दर्शाता है और इसके बाद वर्ग का नाम उद्धरणों के बीच दिखाई देता है। एकमात्र अपवाद आईडी है जिसे केवल "टी @" के रूप में एन्कोड किया गया है
मिहाई तिमार

2

स्विफ्ट दर्शकों के लिए, आप कार्यक्षमता का उपयोग करके इस कार्यक्षमता को प्राप्त कर सकते हैं Encodable। मैं समझाऊंगा कि कैसे:

  1. अपने ऑब्जेक्ट को Encodableप्रोटोकॉल में सुधारें

    class ExampleObj: NSObject, Encodable {
        var prop1: String = ""
        var prop2: String = ""
    }
  2. कार्यक्षमता Encodableप्रदान करने के लिए एक्सटेंशन बनाएंtoDictionary

     public func toDictionary() -> [String: AnyObject]? {
        let encoder = JSONEncoder()
        encoder.outputFormatting = .prettyPrinted
        guard let data =  try? encoder.encode(self),
              let json = try? JSONSerialization.jsonObject(with: data, options: .init(rawValue: 0)), let jsonDict = json as? [String: AnyObject] else {
            return nil
        }
        return jsonDict
    }
  3. toDictionaryअपने ऑब्जेक्ट इंस्टेंस और एक्सेस keysप्रॉपर्टी पर कॉल करें ।

    let exampleObj = ExampleObj()
    exampleObj.toDictionary()?.keys
  4. देखा! अपनी संपत्तियों को इस तरह एक्सेस करें:

    for k in exampleObj!.keys {
        print(k)
    }
    // Prints "prop1"
    // Prints "prop2"

1

ये उत्तर मददगार हैं, लेकिन मुझे इससे अधिक की आवश्यकता है। मैं केवल इतना चाहता हूं कि यह जांचा जाए कि संपत्ति का वर्ग प्रकार किसी मौजूदा वस्तु के बराबर है या नहीं। उपरोक्त सभी कोड ऐसा करने में सक्षम नहीं हैं, क्योंकि: किसी वस्तु का वर्ग नाम प्राप्त करने के लिए, object_getClassName () इन जैसे ग्रंथों को लौटाता है:

__NSArrayI (for an NSArray instance)
__NSArrayM (for an NSMutableArray instance)
__NSCFBoolean (an NSNumber object initialized by initWithBool:)
__NSCFNumber (an NSValue object initialized by [NSNumber initWithBool:])

लेकिन अगर नमूना कोड के ऊपर से getPropertyType (...) का आह्वान किया जाए, तो इस तरह से परिभाषित एक वर्ग के गुणों की 4 objc_property_t संरचनाएं:

@property (nonatomic, strong) NSArray* a0;
@property (nonatomic, strong) NSArray* a1;
@property (nonatomic, copy) NSNumber* n0;
@property (nonatomic, copy) NSValue* n1;

यह निम्नानुसार क्रमशः तार देता है:

NSArray
NSArray
NSNumber
NSValue

तो यह निर्धारित करने में सक्षम नहीं है कि क्या NSObject कक्षा की एक संपत्ति का मूल्य होने में सक्षम है या नहीं। फिर कैसे करें?

यहाँ मेरा पूरा नमूना कोड है (फ़ंक्शन getPropertyType (...) ऊपर जैसा है):

#import <objc/runtime.h>

@interface FOO : NSObject

@property (nonatomic, strong) NSArray* a0;
@property (nonatomic, strong) NSArray* a1;
@property (nonatomic, copy) NSNumber* n0;
@property (nonatomic, copy) NSValue* n1;

@end

@implementation FOO

@synthesize a0;
@synthesize a1;
@synthesize n0;
@synthesize n1;

@end

static const char *getPropertyType(objc_property_t property) {
    const char *attributes = property_getAttributes(property);
    //printf("attributes=%s\n", attributes);
    char buffer[1 + strlen(attributes)];
    strcpy(buffer, attributes);
    char *state = buffer, *attribute;
    while ((attribute = strsep(&state, ",")) != NULL) {
        if (attribute[0] == 'T' && attribute[1] != '@') {
            // it's a C primitive type:

            // if you want a list of what will be returned for these primitives, search online for
            // "objective-c" "Property Attribute Description Examples"
            // apple docs list plenty of examples of what you get for int "i", long "l", unsigned "I", struct, etc.

            NSString *name = [[NSString alloc] initWithBytes:attribute + 1 length:strlen(attribute) - 1 encoding:NSASCIIStringEncoding];
            return (const char *)[name cStringUsingEncoding:NSASCIIStringEncoding];
        }
        else if (attribute[0] == 'T' && attribute[1] == '@' && strlen(attribute) == 2) {
            // it's an ObjC id type:
            return "id";
        }
        else if (attribute[0] == 'T' && attribute[1] == '@') {
            // it's another ObjC object type:
            NSString *name = [[NSString alloc] initWithBytes:attribute + 3 length:strlen(attribute) - 4 encoding:NSASCIIStringEncoding];
            return (const char *)[name cStringUsingEncoding:NSASCIIStringEncoding];
        }
    }
    return "";
}

int main(int argc, char * argv[]) {
    NSArray* a0 = [[NSArray alloc] init];
    NSMutableArray* a1 = [[NSMutableArray alloc] init];
    NSNumber* n0 = [[NSNumber alloc] initWithBool:YES];
    NSValue* n1 = [[NSNumber alloc] initWithBool:NO];
    const char* type0 = object_getClassName(a0);
    const char* type1 = object_getClassName(a1);
    const char* type2 = object_getClassName(n0);
    const char* type3 = object_getClassName(n1);

    objc_property_t property0 = class_getProperty(FOO.class, "a0");
    objc_property_t property1 = class_getProperty(FOO.class, "a1");
    objc_property_t property2 = class_getProperty(FOO.class, "n0");
    objc_property_t property3 = class_getProperty(FOO.class, "n1");
    const char * memberthype0 = getPropertyType(property0);//property_getAttributes(property0);
    const char * memberthype1 = getPropertyType(property1);//property_getAttributes(property1);
    const char * memberthype2 = getPropertyType(property2);//property_getAttributes(property0);
    const char * memberthype3 = getPropertyType(property3);//property_getAttributes(property1);
    NSLog(@"%s", type0);
    NSLog(@"%s", type1);
    NSLog(@"%s", type2);
    NSLog(@"%s", type3);
    NSLog(@"%s", memberthype0);
    NSLog(@"%s", memberthype1);
    NSLog(@"%s", memberthype2);
    NSLog(@"%s", memberthype3);

    return 0;
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.