diff --git a/Sources/Unbox.swift b/Sources/Unbox.swift index b64804b..59faca9 100644 --- a/Sources/Unbox.swift +++ b/Sources/Unbox.swift @@ -518,13 +518,15 @@ public class Unboxer { } /// Unbox a required Array of values that can be transformed into its final form - public func unbox(key: String, isKeyPath: Bool = true) -> [T] { - return UnboxValueResolver<[T]>(self).resolveRequiredValueForKey(key, isKeyPath: isKeyPath, fallbackValue: []) + public func unbox(key: String, isKeyPath: Bool = true, allowInvalidElements: Bool = false) -> [T] { + let transform = T.makeArrayTransformClosure(allowInvalidElements: allowInvalidElements) + return UnboxValueResolver<[T.UnboxRawValueType]>(self).resolveRequiredValueForKey(key, isKeyPath: isKeyPath, fallbackValue: [], transform: transform) } /// Unbox an optional Array of values that can be transformed into its final form - public func unbox(key: String, isKeyPath: Bool = true) -> [T]? { - return UnboxValueResolver<[T]>(self).resolveOptionalValueForKey(key, isKeyPath: isKeyPath) + public func unbox(key: String, isKeyPath: Bool = true, allowInvalidElements: Bool = false) -> [T]? { + let transform = T.makeArrayTransformClosure(allowInvalidElements: allowInvalidElements) + return UnboxValueResolver<[T.UnboxRawValueType]>(self).resolveOptionalValueForKey(key, isKeyPath: isKeyPath, transform: transform) } /// Unbox a required raw value from a certain index in a nested Array @@ -603,7 +605,7 @@ public class Unboxer { /// Unbox an optional Dictionary containing array of Unboxables public func unbox(key: String, isKeyPath: Bool = true, allowInvalidElements: Bool = false) -> [K : [V]]? { return UnboxValueResolver<[String: [UnboxableDictionary]]>(self).resolveDictionaryValuesForKey(key, isKeyPath: isKeyPath, required: false, allowInvalidElements: allowInvalidElements) { - return try? Unbox($0, context: self.context, allowInvalidElements: allowInvalidElements) + return try? Unbox($0, context: self.context, allowInvalidElements: allowInvalidElements) } } @@ -924,6 +926,28 @@ private extension UnboxableWithContext { } } +private extension UnboxableByTransform { + static func makeArrayTransformClosure(allowInvalidElements allowInvalidElements: Bool) -> ([UnboxRawValueType]) -> [Self]? { + return { + if allowInvalidElements { + return $0.flatMap { Self.transformUnboxedValue($0) } + } + + var transformedValues = [Self]() + + for rawValue in $0 { + guard let transformedvalue = Self.transformUnboxedValue(rawValue) else { + return nil + } + + transformedValues.append(transformedvalue) + } + + return transformedValues + } + } +} + private extension Unboxer { static func unboxer(from data: NSData, context: Any?) throws -> Unboxer { do { diff --git a/Tests/UnboxTests.swift b/Tests/UnboxTests.swift index 3801b97..4f9850f 100644 --- a/Tests/UnboxTests.swift +++ b/Tests/UnboxTests.swift @@ -196,7 +196,33 @@ class UnboxTests: XCTestCase { XCTAssertTrue(unboxed.bool3) XCTAssertEqual(unboxed.double, Double(27)) XCTAssertEqual(unboxed.float, Float(39)) - XCTAssertNil(unboxed.string) + XCTAssertEqual(unboxed.string, "7") + } catch { + XCTFail("\(error)") + } + } + + func testArrayOfURLs() { + struct Model: Unboxable { + let optional: [NSURL]? + let required: [NSURL] + + init(unboxer: Unboxer) { + self.optional = unboxer.unbox("optional") + self.required = unboxer.unbox("required") + } + } + + let dictionary: UnboxableDictionary = [ + "optional" : ["https://www.google.com"], + "required" : ["https://github.com/johnsundell/unbox"] + ] + + do { + let unboxed: Model = try Unbox(dictionary) + XCTAssertEqual(unboxed.optional?.count, 1) + XCTAssertEqual(unboxed.optional?.first, NSURL(string: "https://www.google.com")) + XCTAssertEqual(unboxed.required, [NSURL(string: "https://github.com/johnsundell/unbox")!]) } catch { XCTFail("\(error)") }