S.Schweng
S.Schweng

Reputation: 81

Swift: Check if datatype can be converted to Double

I want to check if the received data from a MySQL-database can be converted to Double and if that's possible I want to append it to an array.

From another question i got the following code:

extension String {
    struct NumberFormatter {
        static let instance = NSNumberFormatter()
    }
    var doubleValue:Double? {
        return NumberFormatter.instance.numberFromString(self)?.doubleValue
    }
    var integerValue:Int? {
        return NumberFormatter.instance.numberFromString(self)?.integerValue
    }
}

Here's my concerned Code (which is in a for-loop):

if let value = datas[i].puls.doubleValue {
    pulsWerte.append(value)
    print(datas[i].puls)
}else {
    badIndex.append(i)
    continue
}

In case an entry of my database is NULL, my program should proceed in the else-branch. But if I test such a case I end up with a runtime-error and the following two messages:

-[NSNull length]: unrecognized selector sent to instance 0x1451238

&

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSNull length]: unrecognized selector sent to instance 0x1451238'

Does anyone know my mistake?

UPDATE

This is how my datas-array gets created:
For downloading and allocating the data I'm using Objectiv-C.
In my Data.h-file I create my Data-class.

@interface Data : NSObject

@property (nonatomic, strong) NSString *sozialversicherungsnummer;
@property (nonatomic, strong) NSString *messzeitpunkt;
@property (nonatomic, strong) NSString *puls;
@property (nonatomic, strong) NSString *sauerstoffgehalt;

@end

And in my HomeModel.m I create a NSMutableArray named "_data". After my download is finished this array gets filled as follows:

for (int i = 0; i < jsonArray.count; i++)
{
    NSDictionary *jsonElement = jsonArray[i];

    // Create a new data object and set its props to JsonElement properties
    Data *newData = [[Data alloc] init];
    newData.sozialversicherungsnummer = jsonElement[@"Sozialversicherungsnummer"];
    newData.messzeitpunkt = jsonElement[@"Messzeitpunkt"];
    newData.puls = jsonElement[@"Puls"];
    newData.sauerstoffgehalt = jsonElement[@"Sauerstoffgehalt"];

    // Add this question to the locations array
    [_data addObject:newData];

}

When this step is completed I get this "_data"-array under the name of a parameter called "items" by a function called "itemsDownloaded".
And now I call this function in my Swift-file and here I'm able to typecast the downloaded "items" as "Data" (my self created class).

func itemsDownloaded(items: [AnyObject]!) {
    let datas = items as! [Data]
.
.
.

Upvotes: 0

Views: 509

Answers (2)

Jan Weinkauff
Jan Weinkauff

Reputation: 224

Your implementation of doubleValue:Double? assumes that self is a String.

    var doubleValue:Double? {
        return NumberFormatter.instance.numberFromString(self)?.doubleValue
    }

The datas[i].puls is created by an Objective-C JSON Parser which produces in the case of NULL an instance of NSNull but you expect to set nil.

The easiest way is to check jsonElement[@"Puls"] for NSNull and then set newData.puls to NULL:

id puls = jsonElement[@"Puls"];
if puls == [NSNull null] {
  newData.puls = null;
} else {
  newData.puls = puls;
}

Upvotes: 0

Luca Angeletti
Luca Angeletti

Reputation: 59496

First of all you can define the following protocol.

DoubleConvertible

protocol DoubleConvertible {
    func toDouble() -> Double?
}

Making String, Int and Double conform DoubleConvertible

Next, for each type that you want to be convertible to Double you need to make that type conform to DoubleConvertible.

Let's do it for String

extension String: DoubleConvertible {
    func toDouble() -> Double? {
        return Double(self)
    }
}

and Int

extension Int: DoubleConvertible {
    func toDouble() -> Double? {
        return Double(self)
    }
}

and ... well Double

extension Double: DoubleConvertible {
    func toDouble() -> Double? {
        return self
    }
}

From [Any] to [Double]

Now given a list of values of several different types

let list: [Any?] = ["123", nil, "Hello", 456, true, 789.1]

We can easily convert it to a list of Double.

let listOfDouble = list
    .flatMap { $0 as? DoubleConvertible }
    .flatMap { $0.toDouble() }

listOfDouble // [123.0, 456.0, 789.1]

Upvotes: 3

Related Questions