2012-11-13 10 views
6

मैं आईओएस प्रोजेक्ट में प्रोटोकॉल बफर का उपयोग करना चाहता हूं। मैं पूरी परियोजना को एक उद्देश्य-सी ++ फियास्को में बनाने से बचने की कोशिश कर रहा हूं, इसलिए मैं सी ++ प्रोटोबफ कक्षाओं को उद्देश्य-सी में लपेटना चाहता हूं। मेरे पास कई दर्जन प्रोटोबफ संदेश हैं, और जब मैंने एक बार में सफलतापूर्वक एक कक्षा की है, तो आदर्श रूप से मैं दोहराए गए कोड को कम करने के लिए विरासत का उपयोग करना चाहता हूं। मैं उद्देश्य-सी के लिए नया हूं और मैंने 10 वर्षों में सी ++ के बारे में जो कुछ भी नहीं जानता था, उतना ही उपयोग नहीं किया है, इसलिए यह ज्यादातर निराशा में एक अभ्यास रहा है। नीचे एक उदाहरण है कि मैंने एक संदेश कैसे लपेट लिया है।क्या उद्देश्य-सी में प्रोटोकॉल बफर को लपेटने का कोई तरीका है और अभी भी विरासत का लाभ उठाएं?

कोड

.proto:

message MessageA { 
    optional string value = 1; 
} 

MessageAWrapper.h:

#import <Foundation/Foundation.h> 

@interface MessageAWrapper : NSObject 

@property (nonatomic) NSString *value; 

+ (id)fromString:(NSString *)string; 
- (NSString *)serialize; 

@end 

MessageAWrapper.mm:

#import "MessageA.h" 
#import "message.pb.h" 

@interface MessageAWrapper() 

@property (nonatomic) MessageA *message; 

@end 

@implementation MessageAWrapper 

- (id)init 
{ 
    self = [super init]; 
    if (self) { 
     self.message = new MessageA(); 
    } 
    return self; 
} 

- (void)dealloc { 
    delete self.message; 
    self.message = NULL; 
} 

- (NSString *)value { 
    return [NSString stringWithUTF8String:self.message->value().c_str()]; 
} 

- (void)setValue:(NSString *)value { 
    self.message->set_value([value UTF8String]); 
} 

- (NSString *)serialize { 
    std::string output; 
    self.message->SerializeToString(&output); 
    return [NSString stringWithUTF8String:output.c_str()]; 
} 

+ (id)fromString:(NSString *)string { 
    MessageA *message = new MessageA(); 
    message->ParseFromString([string UTF8String]); 

    MessageAWrapper *wrapper = [[MessageAWrapper alloc] init]; 
    wrapper.message = message; 
    return wrapper; 
} 

@end 

लक्ष्य

वहाँ कोड है कि यहाँ तक दर्जनों बार दोहराया जाएगा का एक बहुत कुछ है, जिसमें केवल भिन्नता लिपटे वर्ग प्रकार (init, dealloc, serialize, fromString), इसलिए आदर्श मैं पर डाल करना चाहते हैं है इसके बजाय एक माता-पिता ProtobufMesssage कक्षा। दुर्भाग्यवश मुझे इस काम को करने में कोई सफलता नहीं मिली क्योंकि मुझे अभिभावक वर्ग के लिए कक्षा का पता लगाने का कोई तरीका नहीं मिल रहा है, जिसका उदाहरण init और fromString में है।

चीजें मैं का प्रयास किया है

  • struct
  • टेम्पलेट वर्ग
  • शून्य *

बाधाओं मैं

    का सामना करना पड़ा
  • एक वर्ग/प्रकार
  • ज फ़ाइल में किसी भी सी ++ हेडर या कोड नहीं हो सकता है (के रूप में इस ऑब्जेक्टिव-सी होने के लिए पूरी परियोजना की आवश्यकता है ++)
  • के लिए एक संदर्भ स्टोर करने के लिए एक तरह से नहीं मिल सकता है Protobuf संदेश माता-पिता (Message या MessageLite), क्योंकि वे सार

जैसा कि मैंने कहा मैं सी ++ या ऑब्जेक्टिव-सी की बहुत कम समझ है के लिए संदर्भ रखने कठिनाई; मेरा अधिकांश अनुभव पायथन और जावा जैसे उच्च स्तर की भाषाओं के साथ है (हालांकि मैं ज्यादातर मूल सी चीजों को पॉइंटर्स समझता हूं)।

क्या यह शायद संभव भी नहीं है? क्या मैं इसे गलत कर रहा हूं या कुछ स्पष्ट याद कर रहा हूं? कोई भी सहायताकाफी प्रशंसनीय होगी। धन्यवाद।

उत्तर

0

मुझे सी ++ के बारे में बहुत कुछ पता नहीं है, लेकिन क्या आप उद्देश्य-सी संपत्ति को Message * होने की घोषणा नहीं कर सकते?

आप पहले से ही .mm फ़ाइल में संपत्ति की घोषणा के द्वारा हैडर से सी ++ कोड अलग कर दिया है, समस्या आप होगा संकलक (value() और set_value()) द्वारा नाम उदाहरण के तरीकों और के लिए मान्य तरीकों केवल होने के साथ है उपवर्ग। यह Reflection कक्षा का उपयोग अपने नाम से फ़ील्ड प्राप्त करने और सेट करने में मदद कर सकता है।

Message* foo = new Foo; 
const Descriptor* descriptor = foo->GetDescriptor(); 

const FieldDescriptor* text_field = descriptor->FindFieldByName("text"); 
assert(text_field != NULL); 
assert(text_field->type() == FieldDescriptor::TYPE_STRING); 
assert(text_field->label() == FieldDescriptor::LABEL_OPTIONAL); 

const Reflection* reflection = foo->GetReflection(); 
assert(reflection->GetString(foo, text_field) == "Hello World!"); 

आप ऑब्जेक्टिव-सी -objectForKey: और -setObject:forKey: उदाहरण तरीकों कि typecheck और मिलता है या सेट मूल्य बना सकते हैं (भी संदेहास्पद MessageAWrapper के मामले में प्रमुख @"value" होगा): यहाँ गूगल के message.h से एक अंश इस दिखा है । आपके उप-वर्गों को सी ++ कोड से अवगत होने की भी आवश्यकता नहीं होगी।

आप निर्माता को -init और +fromString: विधि में +_createNewInstance में विधि को अलग भी कर सकते हैं;

+(Message*)_createNewInstance{ return new MessageA(); } 

सी ++ वस्तु बनाने के अलावा सभी कोड पुन: उपयोग करने MessageWrapper के अपने उपवर्गों की इजाजत दी।

0

जबकि उद्देश्य सी में बहुत शक्तिशाली आत्मनिरीक्षण क्षमताएं हैं, सी ++ अधिक सीमित है। आपके पास RTTI (रन टाइम प्रकार की जानकारी) है, लेकिन यह उद्देश्य सी समकक्ष के रूप में भी शक्तिशाली नहीं है।

हालांकि, यह आपके लिए पर्याप्त हो सकता है। अपने उद्देश्य सी ++ वर्ग के भीतर, आप typeid ऑपरेटर के साथ आप संदेश ऑब्जेक्ट के प्रकार के हो सकते हैं:

if((typeid(self.message) == typed(foo)){ 
    //doSomething 
else if((typeid(self.message) == typed(bar)){ 
    // doSomething else 
} 

हो सकता है कि सबसे अच्छा विकल्प एक और अविवेक स्तर जोड़ना है। एक उद्देश्य सी क्लास पदानुक्रम बनाएं जो आपके सभी प्रोटोकॉल बफर सी ++ कक्षाओं को लपेटता है और फिर एक और उद्देश्य सी बनाता है जो उन वर्गों का उपयोग करता है (शायद प्रतिनिधियों के रूप में)। मेरा मानना ​​है कि यह एक बेहतर विकल्प हो सकता है। उन अपरिहार्य मामलों के लिए केवल C++ का उपयोग करें।

गुड लक!

+0

'dynamic_cast' का उपयोग करके बेहतर होगा – newacct

संबंधित मुद्दे