From 19fd207470854299ae6b90287d6a451f117e56dc Mon Sep 17 00:00:00 2001 From: Kyle Matthew Hedden Date: Wed, 13 Jul 2022 11:32:12 -0400 Subject: [PATCH 1/6] insert label range validations to prevent crashes --- MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift b/MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift index c524b7b3..edb8c1a2 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift @@ -829,7 +829,14 @@ extension Label { private func addActionAttributes(range: NSRange, string: NSMutableAttributedString?) { - guard let string = string else { return } + guard let string = string, + range.location > 0 && range.location < string.length + else { return } + + var range = range + if range.upperBound > string.length { + range = NSRange(location: range.location, length: string.length - range.location) + } string.addAttributes([NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue], range: range) } From fc512ca811bf0c5b83ee1f64f48639e97ced4a79 Mon Sep 17 00:00:00 2001 From: Kyle Matthew Hedden Date: Tue, 19 Jul 2022 12:56:35 -0400 Subject: [PATCH 2/6] add logging and model handling --- .../Atomic/Atoms/Views/Label/Label.swift | 9 +++++++-- .../Label/LabelAttributeImageModel.swift | 8 ++++++++ .../Views/Label/LabelAttributeModel.swift | 17 +++++++++++++++++ .../Atomic/Atoms/Views/Label/LabelModel.swift | 19 ++++++++++++++++++- 4 files changed, 50 insertions(+), 3 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift b/MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift index edb8c1a2..4f567600 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift @@ -831,11 +831,16 @@ extension Label { guard let string = string, range.location > 0 && range.location < string.length - else { return } + else { + MVMCoreLoggingHandler.shared()?.addError(toLog: MVMCoreErrorObject(title: nil, messageToLog: "Attribute starting location \(range.lowerBound) is out of bounds for '\(string?.string ?? "")'. Attribute is discarded.", code: ErrorCode.default.rawValue, domain: ErrorDomainNative, location: "\(#file): \(#function)")!) + return + } var range = range if range.upperBound > string.length { - range = NSRange(location: range.location, length: string.length - range.location) + let newRange = NSRange(location: range.location, length: string.length - range.location) + MVMCoreLoggingHandler.shared()?.addError(toLog: MVMCoreErrorObject(title: nil, messageToLog: "Attribute ending location \(range.upperBound) is out of bounds for '\(string)'. Adjusting to \(newRange.upperBound).", code: ErrorCode.default.rawValue, domain: ErrorDomainNative, location: "\(#file): \(#function)")!) + range = newRange } string.addAttributes([NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue], range: range) diff --git a/MVMCoreUI/Atomic/Atoms/Views/Label/LabelAttributeImageModel.swift b/MVMCoreUI/Atomic/Atoms/Views/Label/LabelAttributeImageModel.swift index 7396e749..9ec6b4f6 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/Label/LabelAttributeImageModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/Label/LabelAttributeImageModel.swift @@ -36,6 +36,14 @@ class LabelAttributeImageModel: LabelAttributeModel { case URL } + public override func validateInRange(of text: String) -> Bool { + guard location > 0 && location <= text.count else { + MVMCoreLoggingHandler.shared()?.addError(toLog: MVMCoreErrorObject(title: nil, messageToLog: "Attribute starting location \(location) is out of bounds for '\(text)'. Attribute is discarded.", code: ErrorCode.default.rawValue, domain: ErrorDomainNative, location: "\(#file): \(#function)")!) + return false + } + return true + } + //-------------------------------------------------- // MARK: - Codec //-------------------------------------------------- diff --git a/MVMCoreUI/Atomic/Atoms/Views/Label/LabelAttributeModel.swift b/MVMCoreUI/Atomic/Atoms/Views/Label/LabelAttributeModel.swift index 7df4097a..37da30a4 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/Label/LabelAttributeModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/Label/LabelAttributeModel.swift @@ -44,6 +44,23 @@ case length } + public func validateInRange(of text: String) -> Bool { + // Prevent invalid starting locations. + guard location > 0 && location <= text.count else { + MVMCoreLoggingHandler.shared()?.addError(toLog: MVMCoreErrorObject(title: nil, messageToLog: "Attribute starting location \(location) is out of bounds for '\(text)'. Attribute is discarded.", code: ErrorCode.default.rawValue, domain: ErrorDomainNative, location: "\(#file): \(#function)")!) + return false + } + + // Truncate long lengths + guard length + location <= text.count else { + MVMCoreLoggingHandler.shared()?.addError(toLog: MVMCoreErrorObject(title: nil, messageToLog: "Attribute length \(length) is out of bounds for '\(text)'. Adjusting to \(text.count - location).", code: ErrorCode.default.rawValue, domain: ErrorDomainNative, location: "\(#file): \(#function)")!) + length = text.count - location + return true + } + + return true + } + //-------------------------------------------------- // MARK: - Codec //-------------------------------------------------- diff --git a/MVMCoreUI/Atomic/Atoms/Views/Label/LabelModel.swift b/MVMCoreUI/Atomic/Atoms/Views/Label/LabelModel.swift index 2eec132f..02c58f8e 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/Label/LabelModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/Label/LabelModel.swift @@ -21,7 +21,17 @@ public var fontName: String? public var fontSize: CGFloat? public var textAlignment: NSTextAlignment? - public var attributes: [LabelAttributeModel]? + private var _attributes: [LabelAttributeModel]? + public var attributes: [LabelAttributeModel]? { + get { _attributes } + set { + if let attributes = newValue { + _attributes = validate(attributes) + } else { + _attributes = nil + } + } + } public var html: String? public var hero: Int? public var makeWholeViewClickable: Bool? @@ -60,6 +70,13 @@ self.text = text } + //-------------------------------------------------- + // MARK: - Validations + //-------------------------------------------------- + public func validate(_ attributes: [LabelAttributeModel]) -> [LabelAttributeModel] { + return attributes.filter { $0.validateInRange(of: text) } + } + //-------------------------------------------------- // MARK: - Codec //-------------------------------------------------- From 982f65ab0f57f605fed8e2e9ac639fa1258aceb6 Mon Sep 17 00:00:00 2001 From: Scott Pfeil Date: Fri, 12 Aug 2022 16:21:07 -0400 Subject: [PATCH 3/6] fix threading issue --- MVMCoreUI/Managers/SubNav/SubNavManagerController.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/MVMCoreUI/Managers/SubNav/SubNavManagerController.swift b/MVMCoreUI/Managers/SubNav/SubNavManagerController.swift index f5c4023a..ce3f59e0 100644 --- a/MVMCoreUI/Managers/SubNav/SubNavManagerController.swift +++ b/MVMCoreUI/Managers/SubNav/SubNavManagerController.swift @@ -145,7 +145,9 @@ open class SubNavManagerController: ViewController, MVMCoreViewManagerProtocol, open func shouldContinue(toErrorPage loadObject: MVMCoreLoadObject, error: MVMCoreErrorObject?) -> Bool { // Push error screens so they do not replace the tab page. - loadObject.requestParameters?.navigationController = navigationController + MVMCoreDispatchUtility.performSyncBlock(onMainThread: { + loadObject.requestParameters?.navigationController = self.navigationController + }) loadObject.requestParameters?.loadStyle = .push return true } From 3765c771ec72eb5410dde68757427aea1134bdea Mon Sep 17 00:00:00 2001 From: Kyle Matthew Hedden Date: Tue, 16 Aug 2022 20:15:43 -0400 Subject: [PATCH 4/6] model throw, view adapt --- .../Atomic/Atoms/Views/Label/Label.swift | 50 ++++++++++++------- .../Label/LabelAttributeImageModel.swift | 13 +++-- .../Views/Label/LabelAttributeModel.swift | 21 ++++---- .../Atomic/Atoms/Views/Label/LabelModel.swift | 27 +++++----- .../MoleculeModelProtocol.swift | 1 + 5 files changed, 65 insertions(+), 47 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift b/MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift index 47d6c69b..3fe4ab77 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift @@ -326,7 +326,9 @@ public typealias ActionBlock = () -> () let attributedString = NSMutableAttributedString(string: labelText, attributes: [NSAttributedString.Key.font: font.updateSize(standardFontSize), NSAttributedString.Key.foregroundColor: textColor as UIColor]) for attribute in attributes { - let range = NSRange(location: attribute.location, length: attribute.length) + guard let range = validateAttribute(range: NSRange(location: attribute.location, length: attribute.length) , in: attributedString) + else { continue } + switch attribute { case let underlineAtt as LabelAttributeUnderlineModel: attributedString.addAttribute(.underlineStyle, value: underlineAtt.underlineValue.rawValue, range: range) @@ -458,10 +460,9 @@ public typealias ActionBlock = () -> () for case let attribute as [String: Any] in attributes { guard let attributeType = attribute.optionalStringForKey(KeyType), let location = attribute["location"] as? Int, - let length = attribute["length"] as? Int - else { continue } - - let range = NSRange(location: location, length: length) + let length = attribute["length"] as? Int, + let range = validateAttribute(range: NSRange(location: location, length: length), in: attributedString) + else { continue } switch attributeType { case "underline": @@ -834,19 +835,9 @@ extension Label { private func addActionAttributes(range: NSRange, string: NSMutableAttributedString?) { guard let string = string, - range.location > 0 && range.location < string.length - else { - MVMCoreLoggingHandler.shared()?.addError(toLog: MVMCoreErrorObject(title: nil, messageToLog: "Attribute starting location \(range.lowerBound) is out of bounds for '\(string?.string ?? "")'. Attribute is discarded.", code: ErrorCode.default.rawValue, domain: ErrorDomainNative, location: "\(#file): \(#function)")!) - return - } - - var range = range - if range.upperBound > string.length { - let newRange = NSRange(location: range.location, length: string.length - range.location) - MVMCoreLoggingHandler.shared()?.addError(toLog: MVMCoreErrorObject(title: nil, messageToLog: "Attribute ending location \(range.upperBound) is out of bounds for '\(string)'. Adjusting to \(newRange.upperBound).", code: ErrorCode.default.rawValue, domain: ErrorDomainNative, location: "\(#file): \(#function)")!) - range = newRange - } - + let range = validateAttribute(range: range, in: string) + else { return } + string.addAttributes([NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue], range: range) } @@ -1005,3 +996,26 @@ extension Label { return false } } + +//------------------------------------------------------ +// MARK: - Validations +//------------------------------------------------------ + +func validateAttribute(range: NSRange, in string: NSAttributedString) -> NSRange? { + guard range.location >= 0 && range.location < string.length else { + if let loggingHandler = MVMCoreLoggingHandler.shared(), loggingHandler.responds(to: #selector(MVMCoreLoggingHandler.addError(toLog:))) { + loggingHandler.addError(toLog: MVMCoreErrorObject(title: nil, messageToLog: "Attribute starting location \(range.lowerBound) is out of bounds for '\(string.string)'. Attribute is discarded.", code: ErrorCode.default.rawValue, domain: ErrorDomainNative, location: "\(#file): \(#function)")!) + } + return nil + } + + if range.upperBound > string.length { + let newRange = NSRange(location: range.location, length: string.length - range.location) + if let loggingHandler = MVMCoreLoggingHandler.shared(), loggingHandler.responds(to: #selector(MVMCoreLoggingHandler.addError(toLog:))) { + loggingHandler.addError(toLog: MVMCoreErrorObject(title: nil, messageToLog: "Attribute ending location \(range.upperBound) is out of bounds for '\(string)'. Adjusting to \(newRange.upperBound).", code: ErrorCode.default.rawValue, domain: ErrorDomainNative, location: "\(#file): \(#function)")!) + } + return newRange + } + + return range +} diff --git a/MVMCoreUI/Atomic/Atoms/Views/Label/LabelAttributeImageModel.swift b/MVMCoreUI/Atomic/Atoms/Views/Label/LabelAttributeImageModel.swift index 9ec6b4f6..2f8235e0 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/Label/LabelAttributeImageModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/Label/LabelAttributeImageModel.swift @@ -35,13 +35,16 @@ class LabelAttributeImageModel: LabelAttributeModel { case name case URL } + + //-------------------------------------------------- + // MARK: - Validations + //-------------------------------------------------- - public override func validateInRange(of text: String) -> Bool { - guard location > 0 && location <= text.count else { - MVMCoreLoggingHandler.shared()?.addError(toLog: MVMCoreErrorObject(title: nil, messageToLog: "Attribute starting location \(location) is out of bounds for '\(text)'. Attribute is discarded.", code: ErrorCode.default.rawValue, domain: ErrorDomainNative, location: "\(#file): \(#function)")!) - return false + public override func validateInRange(of text: String) -> MolecularError? { + guard location >= 0 && location <= text.count else { + return MolecularError.validationError("Attribute starting location \(location) is out of bounds for '\(text)'.") } - return true + return nil } //-------------------------------------------------- diff --git a/MVMCoreUI/Atomic/Atoms/Views/Label/LabelAttributeModel.swift b/MVMCoreUI/Atomic/Atoms/Views/Label/LabelAttributeModel.swift index 37da30a4..590e79b9 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/Label/LabelAttributeModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/Label/LabelAttributeModel.swift @@ -44,21 +44,20 @@ case length } - public func validateInRange(of text: String) -> Bool { + //-------------------------------------------------- + // MARK: - Validations + //-------------------------------------------------- + + public func validateInRange(of text: String) -> MolecularError? { // Prevent invalid starting locations. - guard location > 0 && location <= text.count else { - MVMCoreLoggingHandler.shared()?.addError(toLog: MVMCoreErrorObject(title: nil, messageToLog: "Attribute starting location \(location) is out of bounds for '\(text)'. Attribute is discarded.", code: ErrorCode.default.rawValue, domain: ErrorDomainNative, location: "\(#file): \(#function)")!) - return false + guard location >= 0 && location <= text.count else { + return MolecularError.validationError("Attribute starting location \(location) is out of bounds for '\(text)'.") } - - // Truncate long lengths + // Prevent lengths extending beyond the bounds of the string. guard length + location <= text.count else { - MVMCoreLoggingHandler.shared()?.addError(toLog: MVMCoreErrorObject(title: nil, messageToLog: "Attribute length \(length) is out of bounds for '\(text)'. Adjusting to \(text.count - location).", code: ErrorCode.default.rawValue, domain: ErrorDomainNative, location: "\(#file): \(#function)")!) - length = text.count - location - return true + return MolecularError.validationError("Attribute length \(length) starting at \(location) is out of bounds for '\(text)'.") } - - return true + return nil } //-------------------------------------------------- diff --git a/MVMCoreUI/Atomic/Atoms/Views/Label/LabelModel.swift b/MVMCoreUI/Atomic/Atoms/Views/Label/LabelModel.swift index d7408be1..f23b3f90 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/Label/LabelModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/Label/LabelModel.swift @@ -21,17 +21,7 @@ public var fontName: String? public var fontSize: CGFloat? public var textAlignment: NSTextAlignment? - private var _attributes: [LabelAttributeModel]? - public var attributes: [LabelAttributeModel]? { - get { _attributes } - set { - if let attributes = newValue { - _attributes = validate(attributes) - } else { - _attributes = nil - } - } - } + public var attributes: [LabelAttributeModel]? public var html: String? public var hero: Int? public var makeWholeViewClickable: Bool? @@ -75,8 +65,14 @@ //-------------------------------------------------- // MARK: - Validations //-------------------------------------------------- - public func validate(_ attributes: [LabelAttributeModel]) -> [LabelAttributeModel] { - return attributes.filter { $0.validateInRange(of: text) } + + public func validate(_ attributes: [LabelAttributeModel]) -> MolecularError? { + for attribute in attributes { + if let molecularError = attribute.validateInRange(of: text) { + return molecularError + } + } + return nil } //-------------------------------------------------- @@ -99,6 +95,11 @@ makeWholeViewClickable = try typeContainer.decodeIfPresent(Bool.self, forKey: .makeWholeViewClickable) numberOfLines = try typeContainer.decodeIfPresent(Int.self, forKey: .numberOfLines) shouldMaskRecordedView = try typeContainer.decodeIfPresent(Bool.self, forKey: .shouldMaskRecordedView) ?? false + + // Later make protocol based validate outside of decoding? + if let attributes = attributes, let error = validate(attributes) { + throw error + } } open func encode(to encoder: Encoder) throws { diff --git a/MVMCoreUI/Atomic/Protocols/ModelProtocols/MoleculeModelProtocol.swift b/MVMCoreUI/Atomic/Protocols/ModelProtocols/MoleculeModelProtocol.swift index 1f1fdc1e..6845d44b 100644 --- a/MVMCoreUI/Atomic/Protocols/ModelProtocols/MoleculeModelProtocol.swift +++ b/MVMCoreUI/Atomic/Protocols/ModelProtocols/MoleculeModelProtocol.swift @@ -1,6 +1,7 @@ public enum MolecularError: Swift.Error { case error(String) + case validationError(String) case countImbalance(String) } From bac00ad0fa62fa2dfd1919f053fbf14eed9b36b4 Mon Sep 17 00:00:00 2001 From: Kyle Matthew Hedden Date: Tue, 16 Aug 2022 20:29:57 -0400 Subject: [PATCH 5/6] image range fix & silence warnings --- MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift b/MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift index 3fe4ab77..069b1dc5 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift @@ -326,7 +326,7 @@ public typealias ActionBlock = () -> () let attributedString = NSMutableAttributedString(string: labelText, attributes: [NSAttributedString.Key.font: font.updateSize(standardFontSize), NSAttributedString.Key.foregroundColor: textColor as UIColor]) for attribute in attributes { - guard let range = validateAttribute(range: NSRange(location: attribute.location, length: attribute.length) , in: attributedString) + guard let range = validateAttribute(range: NSRange(location: attribute.location, length: attribute.length) , in: attributedString, type: attribute.type) else { continue } switch attribute { @@ -461,7 +461,7 @@ public typealias ActionBlock = () -> () guard let attributeType = attribute.optionalStringForKey(KeyType), let location = attribute["location"] as? Int, let length = attribute["length"] as? Int, - let range = validateAttribute(range: NSRange(location: location, length: length), in: attributedString) + let range = validateAttribute(range: NSRange(location: location, length: length), in: attributedString, type: attributeType) else { continue } switch attributeType { @@ -1001,15 +1001,15 @@ extension Label { // MARK: - Validations //------------------------------------------------------ -func validateAttribute(range: NSRange, in string: NSAttributedString) -> NSRange? { - guard range.location >= 0 && range.location < string.length else { +func validateAttribute(range: NSRange, in string: NSAttributedString, type: String = "") -> NSRange? { + guard range.location >= 0 && range.location <= string.length else { if let loggingHandler = MVMCoreLoggingHandler.shared(), loggingHandler.responds(to: #selector(MVMCoreLoggingHandler.addError(toLog:))) { loggingHandler.addError(toLog: MVMCoreErrorObject(title: nil, messageToLog: "Attribute starting location \(range.lowerBound) is out of bounds for '\(string.string)'. Attribute is discarded.", code: ErrorCode.default.rawValue, domain: ErrorDomainNative, location: "\(#file): \(#function)")!) } return nil } - if range.upperBound > string.length { + if type != "image" && range.upperBound > string.length { let newRange = NSRange(location: range.location, length: string.length - range.location) if let loggingHandler = MVMCoreLoggingHandler.shared(), loggingHandler.responds(to: #selector(MVMCoreLoggingHandler.addError(toLog:))) { loggingHandler.addError(toLog: MVMCoreErrorObject(title: nil, messageToLog: "Attribute ending location \(range.upperBound) is out of bounds for '\(string)'. Adjusting to \(newRange.upperBound).", code: ErrorCode.default.rawValue, domain: ErrorDomainNative, location: "\(#file): \(#function)")!) From 3e00e294a0d33417514eae6848890f5331d98201 Mon Sep 17 00:00:00 2001 From: Kyle Matthew Hedden Date: Wed, 17 Aug 2022 10:07:49 -0400 Subject: [PATCH 6/6] Convert to barfing. --- .../Atoms/Views/Label/LabelAttributeImageModel.swift | 5 ++--- .../Atoms/Views/Label/LabelAttributeModel.swift | 7 +++---- MVMCoreUI/Atomic/Atoms/Views/Label/LabelModel.swift | 11 ++++------- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Views/Label/LabelAttributeImageModel.swift b/MVMCoreUI/Atomic/Atoms/Views/Label/LabelAttributeImageModel.swift index 2f8235e0..d6ec1b74 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/Label/LabelAttributeImageModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/Label/LabelAttributeImageModel.swift @@ -40,11 +40,10 @@ class LabelAttributeImageModel: LabelAttributeModel { // MARK: - Validations //-------------------------------------------------- - public override func validateInRange(of text: String) -> MolecularError? { + public override func validateInRange(of text: String) throws { guard location >= 0 && location <= text.count else { - return MolecularError.validationError("Attribute starting location \(location) is out of bounds for '\(text)'.") + throw MolecularError.validationError("Attribute starting location \(location) is out of bounds for '\(text)'.") } - return nil } //-------------------------------------------------- diff --git a/MVMCoreUI/Atomic/Atoms/Views/Label/LabelAttributeModel.swift b/MVMCoreUI/Atomic/Atoms/Views/Label/LabelAttributeModel.swift index 590e79b9..88192720 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/Label/LabelAttributeModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/Label/LabelAttributeModel.swift @@ -48,16 +48,15 @@ // MARK: - Validations //-------------------------------------------------- - public func validateInRange(of text: String) -> MolecularError? { + public func validateInRange(of text: String) throws { // Prevent invalid starting locations. guard location >= 0 && location <= text.count else { - return MolecularError.validationError("Attribute starting location \(location) is out of bounds for '\(text)'.") + throw MolecularError.validationError("Attribute starting location \(location) is out of bounds for '\(text)'.") } // Prevent lengths extending beyond the bounds of the string. guard length + location <= text.count else { - return MolecularError.validationError("Attribute length \(length) starting at \(location) is out of bounds for '\(text)'.") + throw MolecularError.validationError("Attribute length \(length) starting at \(location) is out of bounds for '\(text)'.") } - return nil } //-------------------------------------------------- diff --git a/MVMCoreUI/Atomic/Atoms/Views/Label/LabelModel.swift b/MVMCoreUI/Atomic/Atoms/Views/Label/LabelModel.swift index f23b3f90..10e6a4e5 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/Label/LabelModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/Label/LabelModel.swift @@ -66,13 +66,10 @@ // MARK: - Validations //-------------------------------------------------- - public func validate(_ attributes: [LabelAttributeModel]) -> MolecularError? { + public func validate(_ attributes: [LabelAttributeModel]) throws { for attribute in attributes { - if let molecularError = attribute.validateInRange(of: text) { - return molecularError - } + try attribute.validateInRange(of: text) } - return nil } //-------------------------------------------------- @@ -97,8 +94,8 @@ shouldMaskRecordedView = try typeContainer.decodeIfPresent(Bool.self, forKey: .shouldMaskRecordedView) ?? false // Later make protocol based validate outside of decoding? - if let attributes = attributes, let error = validate(attributes) { - throw error + if let attributes = attributes { + try validate(attributes) } }