Dailycode.info

Short solution for short problems

Sudzc code generator is missing SoapDictionary

When I was working with the Sudzc code generator, and the resultset contained an array of objects (e.g. factories) the strange thing was that the SoapDictionary object was referenced in the generated code, but not included in the Soap code library. So I found a version of this SoapDictionary of a previous version of Sudzc and rewrote it a little to work with ARC. And es, now it returns my objects as an MSMutableArray of these objects!!! Fantastic!

Here's the code for the SoapDictionary which I called SoapDict but you can call it SoapDictionary cause else you need to change the references:

header:

 

//

//  SoapDict.h

//  GALVASFIAPP01

//

//  Created by Mark Deraeve on 10/08/12.

//  Copyright (c) 2012 __GALV__. All rights reserved.

//

 

#import "SoapObject.h"

#import "Soap.h"

 

@interface SoapDict : SoapObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> {

    NSMutableDictionary* items;

}

 

@property (nonatomic, retain) NSMutableDictionary* items;

 

+ (id) newWithNode: (CXMLNode*) node;

- (id) initWithNode: (CXMLNode*) node;

+ (id) serialize: (NSDictionary*) dictionary;

 

- (NSUInteger)count;

- (id)objectForKey:(id)aKey;

- (NSEnumerator *)keyEnumerator;

 

- (NSArray *)allKeys;

- (NSArray *)allKeysForObject:(id)anObject;    

- (NSArray *)allValues;

- (NSString *)description;

- (NSString *)descriptionInStringsFileFormat;

- (NSString *)descriptionWithLocale:(id)locale;

- (NSString *)descriptionWithLocale:(id)locale indent:(NSUInteger)level;

- (BOOL)isEqualToDictionary:(NSDictionary *)otherDictionary;

- (NSEnumerator *)objectEnumerator;

- (NSArray *)objectsForKeys:(NSArray *)keys notFoundMarker:(id)marker;

- (BOOL)writeToFile:(NSString *)path atomically:(BOOL)useAuxiliaryFile;

- (BOOL)writeToURL:(NSURL *)url atomically:(BOOL)atomically; // the atomically flag is ignored if url of a type that cannot be written atomically.

 

- (NSArray *)keysSortedByValueUsingSelector:(SEL)comparator;

- (void)getObjects:(id *)objects andKeys:(id *)keys;

 

+ (id)dictionary;

+ (id)dictionaryWithObject:(id)object forKey:(id)key;

+ (id)dictionaryWithObjects:(id *)objects forKeys:(id *)keys count:(NSUInteger)cnt;

+ (id)dictionaryWithObjectsAndKeys:(id)firstObject, ... NS_REQUIRES_NIL_TERMINATION;

+ (id)dictionaryWithDictionary:(NSDictionary *)dict;

+ (id)dictionaryWithObjects:(NSArray *)objects forKeys:(NSArray *)keys;

 

- (id)initWithObjects:(id *)objects forKeys:(id *)keys count:(NSUInteger)cnt;

- (id)initWithObjectsAndKeys:(id)firstObject, ... NS_REQUIRES_NIL_TERMINATION;

- (id)initWithDictionary:(NSDictionary *)otherDictionary;

- (id)initWithDictionary:(NSDictionary *)otherDictionary copyItems:(BOOL)flag;

- (id)initWithObjects:(NSArray *)objects forKeys:(NSArray *)keys;

 

+ (id)dictionaryWithContentsOfFile:(NSString *)path;

+ (id)dictionaryWithContentsOfURL:(NSURL *)url;

- (id)initWithContentsOfFile:(NSString *)path;

- (id)initWithContentsOfURL:(NSURL *)url;

 

- (void)removeObjectForKey:(id)aKey;

- (void)setObject:(id)anObject forKey:(id)aKey;

 

- (void)addEntriesFromDictionary:(NSDictionary *)otherDictionary;

- (void)removeAllObjects;

- (void)removeObjectsForKeys:(NSArray *)keyArray;

- (void)setDictionary:(NSDictionary *)otherDictionary;

 

+ (id)dictionaryWithCapacity:(NSUInteger)numItems;

- (id)initWithCapacity:(NSUInteger)numItems;

 

- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len;

 

- (void)encodeWithCoder:(NSCoder *)aCoder;

- (id)initWithCoder:(NSCoder *)aDecoder;

 

- (id)copyWithZone:(NSZone *)zone;

- (id)mutableCopyWithZone:(NSZone *)zone;

 

@end

Implementation:

 

//

//  SoapDict.m

//  GALVASFIAPP01

//

//  Created by Mark Deraeve on 10/08/12.

//  Copyright (c) 2012 __GALV__. All rights reserved.

//

 

#import "SoapDict.h"

 

@implementation SoapDict

 

@synthesize items;

 

+ (id) newWithNode: (CXMLNode*) node

{

    return [[SoapDict alloc] initWithNode:node];

}

 

- (id) initWithNode: (CXMLNode*) node

{

    if(self = [self init]) {

    }

    return self;

}

 

+ (id) serialize: (NSDictionary*) dictionary

{

    NSMutableString* s = [NSMutableString string];

    return s;

}

 

- (id) object {

    return self.items;

}

 

- (NSUInteger)count {

    return [self.items count];

}

 

- (id)objectForKey:(id)aKey {

    return [self.items objectForKey:aKey];

}

 

- (NSEnumerator *)keyEnumerator {

    return [self.items keyEnumerator];

}

 

- (NSArray *)allKeys {

    return [self.items allKeys];

}

 

- (NSArray *)allKeysForObject:(id)anObject {

    return [self.items allKeysForObject:anObject];

}

 

- (NSArray *)allValues {

    return [self.items allValues];

}

 

- (NSString *)description {

    return [self.items description];

}

 

- (NSString *)descriptionInStringsFileFormat {

    return [self.items descriptionInStringsFileFormat];

}

 

- (NSString *)descriptionWithLocale:(id)locale {

    return [self.items descriptionWithLocale:locale];

}

 

- (NSString *)descriptionWithLocale:(id)locale indent:(NSUInteger)level {

    return [self.items descriptionWithLocale:locale indent:level];

}

 

- (BOOL)isEqualToDictionary:(NSDictionary *)otherDictionary {

    return [self.items isEqualToDictionary:otherDictionary];

}

 

- (NSEnumerator *)objectEnumerator {

    return [self.items objectEnumerator];

}

 

- (NSArray *)objectsForKeys:(NSArray *)keys notFoundMarker:(id)marker {

    return [self objectsForKeys:keys notFoundMarker:marker];

}

 

- (BOOL)writeToFile:(NSString *)path atomically:(BOOL)useAuxiliaryFile {

    return [self.items writeToFile:path atomically:useAuxiliaryFile];

}

 

- (BOOL)writeToURL:(NSURL *)url atomically:(BOOL)atomically {

    return [self.items writeToURL:url atomically:atomically];

}

 

- (NSArray *)keysSortedByValueUsingSelector:(SEL)comparator {

    return [self.items keysSortedByValueUsingSelector:comparator];

}

 

- (void)getObjects:(id __unsafe_unretained [])objects andKeys:(id __unsafe_unretained [])keys {

    return [self.items getObjects:objects andKeys:keys];

}

 

+ (id)dictionary {

    return [[SoapDict alloc] init];

}

 

+ (id)dictionaryWithObject:(id)object forKey:(id)key {

    return [[SoapDict alloc] initWithObjectsAndKeys:object, key, nil];

}

 

+ (id)dictionaryWithObjects:(id *)objects forKeys:(id *)keys count:(NSUInteger)cnt {

    return [[SoapDict alloc] initWithObjects:objects forKeys:keys count:cnt];

}

 

+ (id)dictionaryWithObjectsAndKeys:(id)firstObject, ...{

    SoapDict* d = [SoapDict dictionary];

    BOOL isKey = NO;

    id eachObject;

    id key;

    id value;

    va_list argumentList;

    if (firstObject) {

        isKey = YES;

        value = firstObject;

        va_start(argumentList, firstObject);

        while ((eachObject = va_arg(argumentList, id))) {

            if(isKey) {

                key = eachObject;

                [d.items setObject:value forKey:key];

                isKey = NO;

                value = nil;

                key = nil;

            } else {

                value = eachObject;

            }

        }

        va_end(argumentList);

    }

    return d;

}

 

+ (id)dictionaryWithDictionary:(NSDictionary *)dict {

    return [[SoapDict alloc] initWithDictionary:dict];

}

 

+ (id)dictionaryWithObjects:(NSArray *)objects forKeys:(NSArray *)keys {

    return [[SoapDict alloc] initWithObjects:objects forKeys:keys];

}

 

- (id)initWithObjects:(id *)objects forKeys:(id *)keys count:(NSUInteger)cnt {

    return [[SoapDict alloc] initWithObjects:objects forKeys:keys count:cnt];

}

 

- (id)initWithObjectsAndKeys:(id)firstObject, ... {

    if(self = [self init]) {

        BOOL isKey = NO;

        id eachObject;

        id key;

        id value;

        va_list argumentList;

        if (firstObject) {

            value = firstObject;

            isKey = YES;

            va_start(argumentList, firstObject);

            while ((eachObject = va_arg(argumentList, id))) {

                if(isKey) {

                    key = eachObject;

                    [self.items setObject:value forKey:key];

                    isKey = NO;

                    value = nil;

                    key = nil;

                } else {

                    value = eachObject;

                }

            }

            va_end(argumentList);

        }

    }

    return self;

}

 

- (id)initWithDictionary:(NSDictionary *)otherDictionary {

    if (self = [self init]) {

        self.items = [[NSMutableDictionary alloc] initWithDictionary:otherDictionary];

    }

    return self;

}

 

- (id)initWithDictionary:(NSDictionary *)otherDictionary copyItems:(BOOL)flag {

    if (self = [self init]) {

        self.items = [[NSMutableDictionary alloc] initWithDictionary:otherDictionary];

    }

    return self;

}

 

- (id)initWithObjects:(NSArray *)objects forKeys:(NSArray *)keys {

    if (self = [self init]) {

        self.items = [[NSMutableDictionary alloc] initWithObjects:objects forKeys:keys];

    }

    return self;

}

 

+ (id)dictionaryWithContentsOfFile:(NSString *)path {

    return [[SoapDict alloc] initWithContentsOfFile:path];

}

 

+ (id)dictionaryWithContentsOfURL:(NSURL *)url {

    return [[SoapDict alloc] initWithContentsOfURL:url];

}

 

- (id)initWithContentsOfFile:(NSString *)path {

    if (self = [self init]) {

        self.items = [[NSMutableDictionary alloc] initWithContentsOfFile:path];

    }

    return self;

}

 

- (id)initWithContentsOfURL:(NSURL *)url {

    if (self = [self init]) {

        self.items = [[NSMutableDictionary alloc] initWithContentsOfURL:url];

    }

    return self;

}

 

- (void)removeObjectForKey:(id)aKey {

    [self.items removeObjectForKey:aKey];

}

 

- (void)setObject:(id)anObject forKey:(id)aKey {

    [self.items setObject:anObject forKey:aKey];

}

 

- (void)addEntriesFromDictionary:(NSDictionary *)otherDictionary {

    [self.items addEntriesFromDictionary:otherDictionary];

}

 

- (void)removeAllObjects {

    [self.items removeAllObjects];

}

 

- (void)removeObjectsForKeys:(NSArray *)keyArray {

    [self.items removeObjectsForKeys:keyArray];

}

 

- (void)setDictionary:(NSDictionary *)otherDictionary {

    [self.items setDictionary:otherDictionary];

}

 

+ (id)dictionaryWithCapacity:(NSUInteger)numItems {

    return [[SoapDict alloc] initWithCapacity:numItems];

}

 

- (id)initWithCapacity:(NSUInteger)numItems {

    if(self = [self init]) {

        self.items = [[NSMutableDictionary alloc] initWithCapacity:numItems];

    }

    return self;

}

 

- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id __unsafe_unretained [])stackbuf count:(NSUInteger)len {

    return [self.items countByEnumeratingWithState:state objects:stackbuf count:len];

}

 

- (void)encodeWithCoder:(NSCoder *)aCoder {

    [self.items encodeWithCoder:aCoder];

}

 

- (id)initWithCoder:(NSCoder *)aDecoder {

    return [self.items initWithCoder:aDecoder];

}

 

- (id)copyWithZone:(NSZone *)zone {

    return [self.items copyWithZone:zone];

}

 

- (id)mutableCopyWithZone:(NSZone *)zone {

    return [self.items mutableCopyWithZone:zone];

}

 

@end

 

 

I just got rid of all the non ARC code and replaced (id *) with (id __unsafe_unretained []) at some places.

 


SUDZC webservices always return 0 (WCF web service and IOS client)

This occurs when you are using ARC (Automatic Reference Counting) generated code.

I found the place to look on these websites: http://stackoverflow.com/questions/8645637/sudzc-with-ios-5-and-arc 

and http://code.google.com/p/sudzc/issues/detail?id=40 but it didn't solve my problem completely. 

In my case it was an .Net web service (WCF) and I had to use s:Body in stead of Body in the SUDZC generated file: SoapRequest.m

CXMLNode* element = [[SoapgetNode: [doc rootElement] withName: @"s:Body"] childAtIndex:0]; 

Found it out by NSLogging the CXML document (I used NSLog tp inspect the cxmldocument ):

        CXMLNode* test = [doc rootElement];

        

        NSLog(@"%@",test); 

Here I got this:

<CXMLElement 0x68c1a50 [0x68c1b10] s:Envelope  <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> <s:Body><GetUserIDResponse xmlns="http://tempuri.org/"><GetUserIDResult>8</GetUserIDResult></GetUserIDResponse></s:Body> </s:Envelope> >

 

So if in your case the s:Body still doesn't do the trick, look into the XML code and find out which prefix to use! Soon I will be posting a complete solution using WCF web serivces and SUDZC generator for iOS 5. It will be a local service running on the local network, not available through the internet. 

Now an extra finding when you are working with custom objects. In my case I'm using Entity Framework with self tracking entities. There entities are passed over the WCF webservice. SUDZC will generate these objects for you and adds them to a NSMutableArray. But when you look at the objects in the array you will notice all properties are empty or nil. Therefore I had to make another change in the generated objects. In the exemple below I changed the generated code withName: @ChangeTracker ... into withName: @"a:ChangeTracker ... I had to change this for all the properties of the entity. So they were filled with the data coming from the xml!

NSMutableString* s = [superserializeElements];

[s appendFormat: @"<a:CashPayment>%@</a:CashPayment>", (self.CashPayment)?@"true":@"false"];

if (self.ChangeTracker != nil) [s appendString: [self.ChangeTrackerserialize: @"a:ChangeTracker"]];

if (self.City != nil) [s appendFormat: @"<a:City>%@</a:City>", [[self.CitystringByReplacingOccurrencesOfString:@"\""withString:@"&quot;" 

 

Be advised that when you start inserting or updating data, you will also need to change some generated code. You will need to add the namespace to the serialization code in the Soap.h and Soap.m file. The I created an extra method which will add the namespace to the envelope: 

// Creates the XML request for the SOAP envelope with optional SOAP headers and an extra given namespace.

+ (NSString*) createEnvelope: (NSString*) method forNamespace: (NSString*) ns withParameters: (NSArray*) params withHeaders: (NSDictionary*) headers  withExtraNameSpace: (NSString *) extraNameSpace;

 

Then in the Soap.m file we implement this method like this:


 

NSString* const SOAP_PREFIX = @"soapenv";

NSString* const NS_PREFIX = @"tem";

NSString* const SER_PREFIX_URL = @"xmlns:ser=\"http://schemas.microsoft.com/2003/10/Serialization/\"";

 

NSString* const HTTP_PREFIX = @"http://";

NSUInteger const FORWARD_FLASH_CHARACTER_VALUE = 47;

// Creates the XML request for the SOAP envelope with optional SOAP headers.

+ (NSString*) createEnvelope: (NSString*) method forNamespace: (NSString*) ns

forParameters: (NSString*) params withHeaders: (NSDictionary*) headers withExtraNameSpace: (NSString *) extraNameSpace

{

    

    NSMutableString* s = [NSMutableStringstring];

    /* example header <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/" xmlns:ser="http://schemas.microsoft.com/2003/10/Serialization/" xmlns:gal="http://schemas.datacontract.org/2004/07/MyNamespace">*/

    [s appendString: @"<?xml version=\"1.0\" encoding=\"utf-8\"?>"];

 

    [s appendString: @"<"];

    [s appendString: SOAP_PREFIX];

    [s appendString:@":Envelope xmlns:"];

    [s appendString: SOAP_PREFIX];

    [s appendString: @"=\"http://schemas.xmlsoap.org/soap/envelope/\" "];

    [s appendString:@" xmlns:"];

    [s appendString: NS_PREFIX];

    [s appendFormat:@"=\"%@\" ",ns ];

    [s appendFormat:@"%@ ",SER_PREFIX_URL];

    if(extraNameSpace)

    {

        [s appendFormat:@" %@ >",extraNameSpace];

    }

    

    if(headers != nil && headers.count > 0) {

        [s appendString: @"<"];

        [s appendString: SOAP_PREFIX];

        [s appendString:@":Header>"];

        

        for(id key in [headers allKeys]) {

            if([[headers objectForKey: key] isMemberOfClass: [SoapNil class]])

            {

                [s appendFormat: @"<%@ xsi:nil=\"true\"/>", key];

            } else {

                [s appendString:[Soap serializeHeader:headers forKey:key]];

            }

        }

        [s appendString: @"</"];

        [s appendString: SOAP_PREFIX];

        [s appendString:@":Header>"];

    }

    

    [s appendString: @"<"];

    [s appendString: SOAP_PREFIX];

    [s appendString:@":Body>"];

    

    NSMutableString* fullMethodName = [NSMutableStringstring];

    [fullMethodName appendString:NS_PREFIX];

    [fullMethodName appendString:@":"];

    [fullMethodName appendString:method];

    

    [s appendFormat: @"<%@>%@</%@>", fullMethodName,[params

                                                     stringByReplacingOccurrencesOfString:@"&" withString:@"&amp;"],

     fullMethodName];

    

    

    [s appendString: @"</"];

    [s appendString: SOAP_PREFIX];

    [s appendString:@":Body>"];

    [s appendString: @"</"];

    [s appendString: SOAP_PREFIX];

    [s appendString:@":Envelope>"];

    return s;

}

 

So in this implementation you see there are more namespaces given. This I discovered after inspecting the WSDL xml and looking for the envelope structure. It could be that in your case the namespace prefix are different. Inspect this yourself.

Then when you call the insert function, just add the extra namespace to the create envelope:

NSString* _envelope = [SoapcreateEnvelope: @"InsertSomething"forNamespace: self.namespacewithParameters: _params withHeaders: self.headers  withExtraNameSpace:SOAP_FUNCTION_PREFIX];


The constant SOAP_FUNCTION_PREFIX looks like this: 

NSString* const SOAP_FUNCTION_PREFIX = @"xmlns:a=\"http://schemas.datacontract.org/2004/07/MyNamespace\""; 


implicit declaration of function is invalid in c99

As a c# developer, I'm sinning against a lot of syntax in objective C.

For one is the explicit calls to functions. I keep forgetting the square braces and hence getting the error:

implicit declaration of function is invalid in c99

Eg : FillValues(); should be [self FillValues];

- (void) FillValues

{

...

}