Search code examples
objective-cswiftswitch-statementnsrange

Convert Swift convenience init with Switch statement to Objective-C


I am trying to convert this swift code to Objective-C

convenience init(fromString string: String, format:DateFormat)
    {
        if string.isEmpty {
            self.init()
            return
        }

        let string = string as NSString

        switch format {

        case .DotNet:

            let startIndex = string.rangeOfString("(").location + 1
            let endIndex = string.rangeOfString(")").location
            let range = NSRange(location: startIndex, length: endIndex-startIndex)
            let milliseconds = (string.substringWithRange(range) as NSString).longLongValue
            let interval = NSTimeInterval(milliseconds / 1000)
            self.init(timeIntervalSince1970: interval)

So far, I am doing this:

-(id) initFromString: (NSString *) string format: (DateFormat *) format{
    if (string == nil) {
        self = [self init];
        return self;
    }


    switch (format) {
        case .DotNet:
            NSRange *startIndex = [[string rangeOfString:@"("] location]+1;

    }
}

and have already run into the following errors:

for the switch(format): statement requires expression of integer type (DateFormat * __strong' invalid)

and for the 2 following lines: Expected expression

Any ideas ?


Solution

  • In Objective-C, the string is impliedly optional. Testing for nil merely tests whether a string was supplied. It doesn't check whether an empty string was supplied. You probably want to switch to string.length == 0 as, by the magic of nil-messaging, that'll work to check for either an empty string or no string at all.

    Objective-C uses C's switch statement. So you can switch on integral types only. If this were Objective-C code originally, DateFormat would probably be an NS_ENUM — an integral type rather than an object type. It looks like the original was an enumeration from your use of dot syntax? If you can make it an Objective-C enumeration then do so and simply use:

    - (id)initFromString:(NSString *)string format:(DateFormat)format {
        ....
        switch(format)
        {
            case DateFormatDotNet: {
                ....
            } break;
        }
    

    (with the curly brackets within the case being because you want to declare variables in there).

    Otherwise, if it must be an object format then you're looking at a painful construction like:

    if([format isEqual:[DateFormat dotNetFormat]]) {
    }
    else if([format isEqual:[DateFormat otherFormat]]) {
    }
    ... etc ...
    

    Also Objective-C has a syntactic distinction between structs, which are exactly what they are in C — named fields but no built-in behaviour — and object types, which is again because it's a strict superset of C. NSRange is a struct. So square bracket messaging syntax doesn't work on it. Instead of:

    [[string rangeOfString:@"("] location]
    

    Use:

    [string rangeOfString:@"("].location
    

    Square brackets around the rangeOfString call because it's a message dispatch to an object, then a dot for location because you get back a C struct as a value, and that's how one accesses a field in a C struct.

    (dot syntax also works for properties on Objective-C objects, but explicitly to alias to getter and setter calls, and only for about the most recent of Objective-C's three decades)