views:

331

answers:

1

Hello,

First of all: this is a though question, sorry for that, but I hope someone can help me!

I'm making a UIML renderer on the iPhone. UIML is a language to describe interfaces. I want to render the XML and show the Interface on the iPhone.

To inform you bettter, i first explain what I'm doing:

<?xml version="1.0"?>
<uiml>
    <interface>
        <structure>
          <part id="hoofdView" class="ViewController">
              <part id="viewVoorHoofdview" class="View">
                <part id="label1" class="Label"/>
              </part>
          </part>
        </structure>
        <style>
            <property part-name="label1" name="text">Dit is een label</property>
            <property part-name="label1" name="position">50,50,100,150</property>
        </style>
    </interface>
    <peers>
        <presentation base="cocoa.uiml"/>
    </peers>
</uiml>

This is a UIML document (an interface). It's a simple ViewController with a View and a Label with text "Dit is een label". I'm making something very abstract.

When I parse the document, I find class="ViewController"

Then we have to look into the vocabulary:

<d-class id="Label" used-in-tag="part" maps-type="class" maps-to="UILabel">         
            <d-property id="text" return-type="NSString*" maps-type="getMethod" maps-to="text"/>
            <d-property id="text" maps-type="setMethod" maps-to="setText:">
               <d-param type="NSString*"/>
            </d-property>

            <d-property id="position" maps-type="setMethod" maps-to="setFrame:">
               <d-param type="CGRect"/>
            </d-property>
        </d-class>

To make it easy for you guys, I simply paste a part of the vocabulary.

In this vocabulary, we find:

<d-class id="Label" used-in-tag="part" maps-type="class" maps-to="UILabel">

And I'm making at run-time a UILabel:

NSObject * createdObject = [[NSClassFromString(className) alloc] init];

Then I have to apply the properties to the createdObject. We have 2 properties: text and position.

We look for them in the vocabulary (let's take position for example)

<d-property id="position" maps-type="setMethod" maps-to="setFrame:">
               <d-param type="CGRect"/>
            </d-property>

As you can see, I need the maps-to and the d-param for invoking the method. But there's one problem: In the first document we have:

<property part-name="label1" name="position">50,50,100,150</property>

First of all, I have to "decode" the string 50,50,100,150 to a CGRect because setFrame: needs a CGRect as parameter. But there's one big problem. I have to make this very abstract, but CGRect is not inherited from NSObject, and therefore I cannot make a function

-(NSObject*)convert:(NSString*)stringToConvert;

Because CGRect is not a NSObject*.

The same problem occurs when I have to pass a float (for example to a UISlider)

<d-property id="minimumValue" maps-type="setMethod" maps-to="setMinimumValue:">
           <d-param type="float"/>
        </d-property>

I cannot return a float because NSObject is not its superclass.

My convert-method looks like this:

-(NSObject *)convert:(NSString *)data parameterType:(NSString *)paramType {
    NSObject * result;

    if ( [paramType isEqualToString:@"NSString*"] ) {
        result = data;
    } else if ([paramType isEqualToString:@"float"]) {
        //HOW TO DO THIS?
    } else if ([paramType isEqualToString:@"CGRect"]) {
        //HOW TO DO THIS?
    } else {
        NSLog(@"TypeDecoder: No decoding method found for the given parameter Type: %@", paramType);
    }

    return result;
}

And the method where I'm calling this from is very abstract, and has to be abstract, because we want to extend the UIML document (vocabulary) without adding code. This is the method where this is invoked from:

-(void)invokeMethod:(Uproperty*)property dProperty:(DProperty *)dProperty guiElement:(NSObject *)object {
//Prepare the invocation
        SEL selector = NSSelectorFromString(dProperty.m_mapsTo);
        NSMethodSignature * signature = [ [object class] instanceMethodSignatureForSelector:selector]; 
        NSInvocation * invocation = [NSInvocation invocationWithMethodSignature:signature];

        //target, selector, arguments
        [invocation setTarget:object];
        [invocation setSelector:selector];

        //Convert the argument to the correct type with the type decoder
        DParam *dParam = [dProperty.m_dParams lastObject];
        NSObject * argument = [m_decoder convert:property.m_data parameterType:dParam.m_type]; //only 1 d-param

        //Then we can set the argument
        [invocation setArgument:&argument atIndex:2]; //2 is the first parameter (0 = self, 1 = _cmd)

        //Invoke the method
        [invocation invoke];
}

Sorry for this difficult question, but I hope someone can help me!!

A: 

You may want to build wrapper classes for all the types that are not a subclass of NSObject. An example is NSNumber as an object wrapper for floats, ints etc.

swegi