उद्देश्य-सी आत्मनिरीक्षण / परावर्तन


79

उद्देश्य-सी में विशेष रूप से एप्पल के कोको / कोको-टच वातावरण में तात्कालिक वस्तु की सामग्री को डंप करने के लिए क्या कोई विधि, फ़ंक्शन, एपीआई, आमतौर पर स्वीकृत तरीका आदि है?

मैं ऐसा कुछ करने में सक्षम होना चाहता हूं

MyType *the_thing = [[MyType alloc] init];
NSString *the_dump = [the_thing dump]; //pseudo code
NSLog("Dumped Contents: %@", the_dump);

और ऑब्जेक्ट की आवृत्ति चर नाम और मान प्रदर्शित किए जाते हैं, साथ ही रन टाइम पर कॉल करने के लिए उपलब्ध कोई भी तरीका। आदर्श रूप में पढ़ने के लिए एक आसान प्रारूप में।

PHP से परिचित डेवलपर्स के लिए, मैं मूल रूप से प्रतिबिंब कार्यों ( var_dump(), get_class_methods()) और OO परावर्तन एपीआई के बराबर की तलाश कर रहा हूं ।


मुझे आश्चर्य है कि एक ही सवाल कुछ दिन हैं। इस सवाल के लिए धन्यवाद।
यानिक लोरीट

7
हाँ, महान सवाल। अन्य समान भाषाओं की तुलना में ओबजेक का सबसे बड़ा लाभ इसकी अद्भुत गतिशील रनटाइम प्रणाली है जो आपको इस तरह की भयानक चीजें करने की अनुमति देती है। दुर्भाग्य से, लोग शायद ही कभी इसकी पूरी क्षमता का उपयोग करते हैं, इसलिए आपके प्रश्न के बारे में एसओ समुदाय को पढ़ाने के लिए यश।
rpj

मैंने प्रतिबिंब OSReflectionKit से निपटने के लिए एक हल्का पुस्तकालय बनाया है । इस लाइब्रेरी का उपयोग करके आप सरल [the_thing fullDescription] कॉल कर सकते हैं।
अलेक्जेंड्रे ओएस

महान प्रश्न !! - क्या आपके पास कोई विचार है कि वास्तविक संपत्ति को एक बार सेट करने के बाद इसे रिफ्लेक्शन का उपयोग कैसे करें? मेरा यहाँ एक प्रश्न है: stackoverflow.com/q/25538890/1735836
पेट्रीसिया

जवाबों:


112

अद्यतन: इस तरह के सामान को देखने वाला कोई भी व्यक्ति ऑब्जेक्टिव-सी रनटाइम के लिए माइक ऐश के ओबीजीसी रैपर की जांच कर सकता है

यह कमोबेश आप इसके बारे में कैसे जाना है:

#import <objc/runtime.h>

. . . 

-(void)dumpInfo
{
    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* classDump = [NSDictionary dictionaryWithObjectsAndKeys:
                               ivarArray, @"ivars",
                               propertyArray, @"properties",
                               methodArray, @"methods",
                               nil];

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

वहां से, उदाहरण की संपत्तियों के वास्तविक मूल्यों को प्राप्त करना आसान है, लेकिन आपको यह देखने के लिए जांचना होगा कि क्या वे आदिम प्रकार या ऑब्जेक्ट हैं, इसलिए मैं इसे डालने के लिए बहुत आलसी था। आप विरासत श्रृंखला को स्कैन करने का विकल्प भी चुन सकते हैं। एक वस्तु पर परिभाषित सभी गुण प्राप्त करें । फिर श्रेणियों पर परिभाषित तरीके हैं, और अधिक ... लेकिन लगभग सब कुछ आसानी से उपलब्ध है।

यहाँ एक उदाहरण दिया गया है कि उपरोक्त कोड क्या है UILabel के लिए:

{
    ivars =     (
        "_size",
        "_text",
        "_color",
        "_highlightedColor",
        "_shadowColor",
        "_font",
        "_shadowOffset",
        "_minFontSize",
        "_actualFontSize",
        "_numberOfLines",
        "_lastLineBaseline",
        "_lineSpacing",
        "_textLabelFlags"
    );
    methods =     (
        rawSize,
        "setRawSize:",
        "drawContentsInRect:",
        "textRectForBounds:",
        "textSizeForWidth:",
        . . .
    );
    properties =     (
        text,
        font,
        textColor,
        shadowColor,
        shadowOffset,
        textAlignment,
        lineBreakMode,
        highlightedTextColor,
        highlighted,
        enabled,
        numberOfLines,
        adjustsFontSizeToFitWidth,
        minimumFontSize,
        baselineAdjustment,
        "_lastLineBaseline",
        lineSpacing,
        userInteractionEnabled
    );
}

6
+1 यह बहुत अधिक है कि मैं इसे कैसे करूंगा (इसे एक NSObjectश्रेणी बनाऊंगा)। हालाँकि, आपको free()अपने ivars, propertiesऔर methodsसरणियों, या फिर आप उन्हें लीक कर रहे हैं।
डेव डोंगलांग

वाह, यह भूल गया। अब उनमें रखो। धन्यवाद।
फेलिक्सज़

4
कठबोली हम आइवर के मूल्यों को देखते हैं?
समहान सलाउद्दीन

2
... और उनके प्रकार। मैंने देखा कि आपने कहा था कि यह किया जा सकता है, लेकिन आप निश्चित रूप से इस बात की बेहतर समझ रखते हैं कि मैं ऐसा करता हूं। क्या आप आइवर और प्रॉपर्टीज के मूल्यों और प्रकारों को प्राप्त करने के लिए कोड के साथ किसी बिंदु पर इसे अपडेट कर पाएंगे?
जनरलमीक

एआरसी के साथ, क्या अभी भी ivars, गुण और विधियों सरणियों को मुक्त करना आवश्यक है?
चक क्रट्सिंगर

12

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


जानकारी के लिए +1, बस जिस तरह की चीज की मुझे तलाश थी। उस ने कहा, मैं एक पूर्व-निर्मित समाधान के लिए उम्मीद कर रहा था, क्योंकि मैं भाषा के लिए नया पर्याप्त हूं कि मैं जो कुछ भी जल्दी से एक साथ हैक कर लूंगा वह भाषा के कुछ प्रमुख सूक्ष्मता को याद कर सकता है।
एलन स्टॉर्म

7
यदि आप किसी उत्तर को अस्वीकार करने जा रहे हैं, तो कृपया टिप्पणी छोड़ने का शिष्टाचार रखें।
डेवॉन्ग

8

यहाँ मैं वर्तमान में सार्वजनिक प्रकाशन के लिए एक पुस्तकालय में, कक्षा चर को स्वचालित रूप से प्रिंट करने के लिए उपयोग कर रहा हूं - यह उदाहरण के वर्ग से सभी गुणों को डंप करके वंशानुक्रम के पेड़ को वापस करने का काम करता है। KVC के लिए धन्यवाद आपको यह ध्यान रखने की आवश्यकता नहीं है कि कोई संपत्ति एक आदिम प्रकार है या नहीं (अधिकांश प्रकारों के लिए)।

// Finds all properties of an object, and prints each one out as part of a string describing the class.
+ (NSString *) autoDescribe:(id)instance classType:(Class)classType
{
    NSUInteger count;
    objc_property_t *propList = class_copyPropertyList(classType, &count);
    NSMutableString *propPrint = [NSMutableString string];

    for ( int i = 0; i < count; i++ )
    {
        objc_property_t property = propList[i];

        const char *propName = property_getName(property);
        NSString *propNameString =[NSString stringWithCString:propName encoding:NSASCIIStringEncoding];

        if(propName) 
        {
            id value = [instance valueForKey:propNameString];
            [propPrint appendString:[NSString stringWithFormat:@"%@=%@ ; ", propNameString, value]];
        }
    }
    free(propList);


    // Now see if we need to map any superclasses as well.
    Class superClass = class_getSuperclass( classType );
    if ( superClass != nil && ! [superClass isEqual:[NSObject class]] )
    {
        NSString *superString = [self autoDescribe:instance classType:superClass];
        [propPrint appendString:superString];
    }

    return propPrint;
}

+ (NSString *) autoDescribe:(id)instance
{
    NSString *headerString = [NSString stringWithFormat:@"%@:%p:: ",[instance class], instance];
    return [headerString stringByAppendingString:[self autoDescribe:instance classType:[instance class]]];
}

+1 बहुत उपयोगी है, हालांकि यह केवल भाग में प्रश्न का उत्तर देता है। क्या आप लाइब्रेरी जारी करते समय यहां एक टिप्पणी जोड़ देंगे?
फेलिक्सज़

@KendallHelmstetterGelner - महान जानकारी !! क्या आपके पास कोई विचार है कि वास्तविक संपत्ति को एक बार सेट करने के बाद कि आपने इसे रिफ्लेक्शन का उपयोग कैसे किया है? मेरा यहाँ एक प्रश्न है: stackoverflow.com/q/25538890/1735836
पेट्रीसिया

@ ठीक है, इस तकनीक का उपयोग करके आपको जो भी तार वापस मिलेंगे, उनका उपयोग [myObject setValue: myValue forKey: propertyName] में किया जा सकता है। जिस तकनीक को मैंने ऊपर उल्लिखित किया है (संपत्ति सूची का उपयोग करके) प्रतिबिंब है ... आप सीधे संपत्ति विधियों को कॉल करने के लिए objc_property_t सरणी का उपयोग कर सकते हैं, लेकिन सेट करें: forKey: उपयोग करना आसान है और बस के रूप में भी काम करता है।
केंडल हेल्मसटेटर गेलनर

4

मैंने संपत्ति के मूल्यों को छापने के लिए केंडल के कोड के लिए दो ट्वीक्स बनाए, जो मेरे लिए बहुत काम आए। मैंने इसे क्लास विधि के बजाय एक इंस्टेंस विधि के रूप में परिभाषित किया, जैसा कि सुपरक्लास रिकर्सन इसे कहते हैं। मैंने गैर-केवीओ-अनुरूप गुणों के लिए अपवाद हैंडलिंग को भी जोड़ा, और आउटपुट में लाइन ब्रेक को जोड़कर इसे पढ़ने में आसान बना दिया (और भिन्न):

-(NSString *) autoDescribe:(id)instance classType:(Class)classType
{
    NSUInteger count;
    objc_property_t *propList = class_copyPropertyList(classType, &count);
    NSMutableString *propPrint = [NSMutableString string];

    for ( int i = 0; i < count; i++ )
    {
        objc_property_t property = propList[i];

        const char *propName = property_getName(property);
        NSString *propNameString =[NSString stringWithCString:propName encoding:NSASCIIStringEncoding];

        if(propName) 
        {
         @try {
            id value = [instance valueForKey:propNameString];
            [propPrint appendString:[NSString stringWithFormat:@"%@=%@\n", propNameString, value]];
         }
         @catch (NSException *exception) {
            [propPrint appendString:[NSString stringWithFormat:@"Can't get value for property %@ through KVO\n", propNameString]];
         }
        }
    }
    free(propList);


    // Now see if we need to map any superclasses as well.
    Class superClass = class_getSuperclass( classType );
    if ( superClass != nil && ! [superClass isEqual:[NSObject class]] )
    {
        NSString *superString = [self autoDescribe:instance classType:superClass];
        [propPrint appendString:superString];
    }

    return propPrint;
}

महान जानकारी !!! - क्या आपके पास कोई विचार है कि वास्तविक संपत्ति को एक बार सेट करने के बाद इसे रिफ्लेक्शन का उपयोग कैसे करें? मेरा यहाँ एक प्रश्न है: stackoverflow.com/q/25538890/1735836
पेट्रीसिया

3

ईमानदारी से, इस काम का सही उपकरण Xcode डिबगर है। यह सब जानकारी एक दृश्य तरीके से आसानी से सुलभ है। समय का उपयोग करने का तरीका जानें, यह एक बहुत शक्तिशाली उपकरण है।

अधिक जानकारी:

डीबगर का उपयोग करना

आउटडेटेड Xcode डिबगिंग गाइड - Apple द्वारा संग्रहीत

Xcode के साथ डिबगिंग के बारे में - Apple द्वारा संग्रहीत

LLDB और डिबगिंग के बारे में - Apple द्वारा संग्रहीत

GDB के साथ डिबगिंग - Apple द्वारा संग्रहीत

SpriteKit डिबगिंग गाइड - Apple द्वारा संग्रहीत

कोर फाउंडेशन के लिए प्रोग्रामिंग डिबगिंग विषय - Apple द्वारा संग्रहीत


4
अच्छी जानकारी के लिए +1, लेकिन कभी-कभी किसी वस्तु की स्थिति को दो बिंदुओं पर डंप करना और आउटपुट को उस समय की तुलना में किसी कार्यक्रम की स्थिति में शुरू करना अधिक तेज़ होता है।
एलन स्टॉर्म

1

मैंने इसमें से कोकोपोड बनाया है, https://github.com/neoneye/autodescribe

मैंने क्रिस्टोफर पिक्सले के कोड को संशोधित किया है और इसे NSObject पर एक श्रेणी बना दिया है और इसमें एक यूनीटेस्ट भी जोड़ा है। इसका उपयोग कैसे करना है:

@interface TestPerson : NSObject

@property (nonatomic, strong) NSString *firstName;
@property (nonatomic, strong) NSString *lastName;
@property (nonatomic, strong) NSNumber *age;

@end

@implementation TestPerson

// empty

@end

@implementation NSObject_AutoDescribeTests

-(void)test0 {
    TestPerson *person = [TestPerson new];
    person.firstName = @"John";
    person.lastName = @"Doe";
    person.age = [NSNumber numberWithFloat:33.33];
    NSString *actual = [person autoDescribe];
    NSString *expected = @"firstName=John\nlastName=Doe\nage=33.33";
    STAssertEqualObjects(actual, expected, nil);
}

@end

0

मैं पहले आत्मनिरीक्षण और परिशोधन के साथ भ्रमित हूं, इसलिए नीचे कुछ जानकारी प्राप्त करें।

आत्मनिरीक्षण वस्तु के लिए यह जांचने की क्षमता है कि वह किस प्रकार का है, या प्रोटोकॉल यह अनुरूप है, या चयनकर्ता इसका जवाब दे सकता है। Objc एपीआई जैसे isKindOfClass/ isMemberOfClass/ conformsToProtocol/ respondsToSelectorआदि।

आत्मनिरीक्षण क्षमता आत्मनिरीक्षण से अधिक है capability यह न केवल वस्तु जानकारी प्राप्त कर सकता है बल्कि वस्तु मेटा-डेटा, गुण और कार्यों को भी संचालित कर सकता है। जैसे object_setClassवस्तु प्रकार को संशोधित कर सकते हैं।

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