ModuleMolecule is now a self contained view.

Fixed priority defect in view constraining view.
Change the way names are set for reuse
improve current margin logic
This commit is contained in:
Pfeil, Scott Robert 2019-06-26 12:01:47 -04:00
parent ab33ceebde
commit 0db0f91b3b
12 changed files with 260 additions and 199 deletions

View File

@ -39,7 +39,6 @@
D28B4F8B21FF967C00712C7A /* MVMCoreUIObject.m in Sources */ = {isa = PBXBuildFile; fileRef = D28B4F8921FF967C00712C7A /* MVMCoreUIObject.m */; };
D296E13C229598BF0051EBE7 /* MoleculeListCellProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D296E13B2295969C0051EBE7 /* MoleculeListCellProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
D296E1412295EBBA0051EBE7 /* MoleculeDelegateProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D296E1402295EBBA0051EBE7 /* MoleculeDelegateProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
D296E143229729C30051EBE7 /* MoleculeMappingObject+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D296E142229729C30051EBE7 /* MoleculeMappingObject+Extension.swift */; };
D296E14722A5984C0051EBE7 /* MVMCoreUIViewConstrainingProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D296E14622A597490051EBE7 /* MVMCoreUIViewConstrainingProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
D29770C821F7C4AE00B2F0D0 /* TopLabelsView.m in Sources */ = {isa = PBXBuildFile; fileRef = D29770C621F7C4AE00B2F0D0 /* TopLabelsView.m */; };
D29770C921F7C4AE00B2F0D0 /* TopLabelsView.h in Headers */ = {isa = PBXBuildFile; fileRef = D29770C721F7C4AE00B2F0D0 /* TopLabelsView.h */; settings = {ATTRIBUTES = (Public, ); }; };
@ -49,6 +48,7 @@
D29770F521F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D29770F121F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsViewController.m */; };
D29770FC21F7C77400B2F0D0 /* MVMCoreUITextFieldView.m in Sources */ = {isa = PBXBuildFile; fileRef = D29770FA21F7C77400B2F0D0 /* MVMCoreUITextFieldView.m */; };
D29770FD21F7C77400B2F0D0 /* MVMCoreUITextFieldView.h in Headers */ = {isa = PBXBuildFile; fileRef = D29770FB21F7C77400B2F0D0 /* MVMCoreUITextFieldView.h */; settings = {ATTRIBUTES = (Public, ); }; };
D29B771022C281F400D6ACE0 /* ModuleMolecule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D29B770F22C281F400D6ACE0 /* ModuleMolecule.swift */; };
D29DF0D121E404D4003B2FB9 /* MVMCoreUI.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF0CF21E404D4003B2FB9 /* MVMCoreUI.h */; settings = {ATTRIBUTES = (Public, ); }; };
D29DF0E621E4F3C7003B2FB9 /* MVMCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D29DF0E521E4F3C7003B2FB9 /* MVMCore.framework */; };
D29DF11521E6805F003B2FB9 /* UIColor+MFConvenience.h in Headers */ = {isa = PBXBuildFile; fileRef = D29DF11121E6805F003B2FB9 /* UIColor+MFConvenience.h */; settings = {ATTRIBUTES = (Public, ); }; };
@ -207,7 +207,6 @@
D28B4F8921FF967C00712C7A /* MVMCoreUIObject.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUIObject.m; sourceTree = "<group>"; };
D296E13B2295969C0051EBE7 /* MoleculeListCellProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MoleculeListCellProtocol.h; sourceTree = "<group>"; };
D296E1402295EBBA0051EBE7 /* MoleculeDelegateProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MoleculeDelegateProtocol.h; sourceTree = "<group>"; };
D296E142229729C30051EBE7 /* MoleculeMappingObject+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MoleculeMappingObject+Extension.swift"; sourceTree = "<group>"; };
D296E14622A597490051EBE7 /* MVMCoreUIViewConstrainingProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUIViewConstrainingProtocol.h; sourceTree = "<group>"; };
D29770C621F7C4AE00B2F0D0 /* TopLabelsView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TopLabelsView.m; sourceTree = "<group>"; };
D29770C721F7C4AE00B2F0D0 /* TopLabelsView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TopLabelsView.h; sourceTree = "<group>"; };
@ -217,6 +216,7 @@
D29770F121F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TopLabelsAndBottomButtonsViewController.m; sourceTree = "<group>"; };
D29770FA21F7C77400B2F0D0 /* MVMCoreUITextFieldView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUITextFieldView.m; sourceTree = "<group>"; };
D29770FB21F7C77400B2F0D0 /* MVMCoreUITextFieldView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreUITextFieldView.h; sourceTree = "<group>"; };
D29B770F22C281F400D6ACE0 /* ModuleMolecule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModuleMolecule.swift; sourceTree = "<group>"; };
D29DF0CC21E404D4003B2FB9 /* MVMCoreUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MVMCoreUI.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D29DF0CF21E404D4003B2FB9 /* MVMCoreUI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUI.h; sourceTree = "<group>"; };
D29DF0D021E404D4003B2FB9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@ -471,6 +471,7 @@
D2E1FADC2268B25E00AEFD8C /* MoleculeTableViewCell.swift */,
B8200E142280C4CF007245F4 /* ProgressBar.swift */,
B8200E182281DC1A007245F4 /* ProgressBarWithLabel.swift */,
D29B770F22C281F400D6ACE0 /* ModuleMolecule.swift */,
);
path = Molecules;
sourceTree = "<group>";
@ -679,7 +680,6 @@
D296E1402295EBBA0051EBE7 /* MoleculeDelegateProtocol.h */,
D2A514562211C53C00345BFB /* MVMCoreUIMoleculeMappingObject.h */,
D2A514572211C53C00345BFB /* MVMCoreUIMoleculeMappingObject.m */,
D296E142229729C30051EBE7 /* MoleculeMappingObject+Extension.swift */,
);
path = OtherHandlers;
sourceTree = "<group>";
@ -901,6 +901,7 @@
D29DF32121ED0CBA003B2FB9 /* LabelView.m in Sources */,
DBC4391822442197001AB423 /* CaretView.swift in Sources */,
D29770F221F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsTableViewController.m in Sources */,
D29B771022C281F400D6ACE0 /* ModuleMolecule.swift in Sources */,
DBC4391922442197001AB423 /* DashLine.swift in Sources */,
D29DF29621E7ADB8003B2FB9 /* StackableViewController.m in Sources */,
D2E1FADB2260D3D200AEFD8C /* MVMCoreUIDelegateObject.swift in Sources */,
@ -944,7 +945,6 @@
D29DF28321E7AB24003B2FB9 /* MVMCoreUICommonViewsUtility.m in Sources */,
D206997821FB8A0B00CAE0DE /* MVMCoreUINavigationController.m in Sources */,
D29DF27A21E7A533003B2FB9 /* MVMCoreUISession.m in Sources */,
D296E143229729C30051EBE7 /* MoleculeMappingObject+Extension.swift in Sources */,
01DF55E021F8FAA800CC099B /* MFTextFieldListView.swift in Sources */,
D2A5146B2214905000345BFB /* ThreeLayerViewController.swift in Sources */,
D29DF2C921E7BFC6003B2FB9 /* MFSizeObject.m in Sources */,

View File

@ -48,11 +48,21 @@
#pragma mark - Constraining
- (void)pinViewToSuperView:(nonnull UIView *)view {
NSDictionary *dictionary = [NSLayoutConstraint constraintPinSubviewToSuperview:view];
self.leftPin = dictionary[ConstraintLeading];
self.topPin = dictionary[ConstraintTop];
self.bottomPin = dictionary[ConstraintBot];
self.rightPin = dictionary[ConstraintTrailing];
NSLayoutConstraint *constraint = [view.leftAnchor constraintEqualToAnchor:view.superview.leftAnchor];
constraint.active = YES;
self.leftPin = constraint;
constraint = [view.topAnchor constraintEqualToAnchor:view.superview.topAnchor];
constraint.active = YES;
self.topPin = constraint;
constraint = [view.superview.rightAnchor constraintEqualToAnchor:view.rightAnchor];
constraint.active = YES;
self.rightPin = constraint;
constraint = [view.superview.bottomAnchor constraintEqualToAnchor:view.bottomAnchor];
constraint.active = YES;
self.bottomPin = constraint;
self.alignCenterPin = [view.centerXAnchor constraintEqualToAnchor:view.superview.centerXAnchor];
self.alignCenterLeftPin = [view.leftAnchor constraintGreaterThanOrEqualToAnchor:view.superview.leftAnchor];

View File

@ -64,7 +64,7 @@ import UIKit
primaryButton?.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
}
public override static func estimatedHeight(forRow json: [AnyHashable : Any]?) -> CGFloat {
public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
return 42
}

View File

@ -9,6 +9,7 @@
#import <UIKit/UIKit.h>
@import MVMCore.MVMCoreViewProtocol;
@class MVMCoreUIDelegateObject;
@class MVMCoreErrorObject;
@protocol MVMCoreUIMoleculeViewProtocol <NSObject, MVMCoreViewProtocol>
@ -25,11 +26,14 @@
/// For the molecule list to load more efficiently.
+ (CGFloat)estimatedHeightForRow:(nullable NSDictionary *)json;
+ (CGFloat)estimatedHeightForRow:(nullable NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject;
/// Allows the molecule to set its name for reuse. Default could be moleculeName.
+ (nullable NSString *)nameForReuse:(nullable NSDictionary *)molecule delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject;
/// Can return the required modules
+ (nullable NSArray <NSString *>*)requiredModules:(nullable NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject error:(MVMCoreErrorObject *_Nullable *_Nullable)error;
@end

View File

@ -0,0 +1,98 @@
//
// ModuleMolecule.swift
// MVMCoreUI
//
// Created by Scott Pfeil on 6/25/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import UIKit
open class ModuleMolecule: ViewConstrainingView {
open var molecule: (UIView & MVMCoreUIMoleculeViewProtocol)?
open override func updateView(_ size: CGFloat) {
super.updateView(size)
molecule?.updateView(size)
}
// MARK: - MVMCoreUIMoleculeViewProtocol
open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
guard let moduleName = json?.optionalStringForKey("moduleName"), let module = delegateObject?.moleculeDelegate?.getModuleWithName(moduleName) else {
// Critical error
return
}
if molecule == nil {
if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: module, delegateObject: delegateObject, constrainIfNeeded: true) {
addSubview(moleculeView)
NSLayoutConstraint.activate(Array(NSLayoutConstraint.pinView(toSuperview: moleculeView, useMargins: false).values))
molecule = moleculeView
}
} else {
molecule?.setWithJSON(module, delegateObject: delegateObject, additionalData: additionalData)
}
}
open override func setAsMolecule() {
super.setAsMolecule()
updateViewHorizontalDefaults = false
molecule?.setAsMolecule?()
}
open override func reset() {
super.reset()
molecule?.reset?()
}
public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
guard let moduleName = json?.optionalStringForKey("moduleName"), let module = delegateObject?.moleculeDelegate?.getModuleWithName(moduleName) else {
// Critical error
return 0
}
return MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: module)?.estimatedHeight?(forRow: module, delegateObject: delegateObject) ?? 80
}
public override static func name(forReuse molecule: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? {
guard let moduleName = molecule?.optionalStringForKey("moduleName"), let module = delegateObject?.moleculeDelegate?.getModuleWithName(moduleName) else {
// Critical error
return "moduleMolecule<>"
}
return "moduleMolecule<" + (MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: module)?.name?(forReuse: module, delegateObject: delegateObject) ?? module.stringForkey(KeyMoleculeName)) + ">"
}
public override static func requiredModules(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> [String]? {
guard let moduleName = json?.optionalStringForKey("moduleName"), let _ = delegateObject?.moleculeDelegate?.getModuleWithName(moduleName) else {
if let errorObject = MVMCoreErrorObject(title: nil, message: MVMCoreGetterUtility.hardcodedString(withKey: HardcodedErrorUnableToProcess), code: CoreUIErrorCode.ErrorCodeModuleMolecule.rawValue, domain: ErrorDomainNative, location: String(describing: self)) {
error?.pointee = errorObject
MVMCoreUILoggingHandler.shared()?.addError(toLog: errorObject)
}
return nil
}
return [moduleName]
}
// MARK: - MVMCoreUIViewConstrainingProtocol
open override func useStandardConstraints() -> Bool {
return (molecule as? MVMCoreUIViewConstrainingProtocol)?.useStandardConstraints?() ?? true
}
open override func alignHorizontal(_ alignment: UIStackView.Alignment) {
(molecule as? MVMCoreUIViewConstrainingProtocol)?.alignHorizontal?(alignment)
}
open override func alignVertical(_ alignment: UIStackView.Alignment) {
(molecule as? MVMCoreUIViewConstrainingProtocol)?.alignVertical?(alignment)
}
open override func shouldSetHorizontalMargins(_ shouldSet: Bool) {
(molecule as? MVMCoreUIViewConstrainingProtocol)?.shouldSetHorizontalMargins?(shouldSet)
}
open override func shouldSetVerticalMargins(_ shouldSet: Bool) {
(molecule as? MVMCoreUIViewConstrainingProtocol)?.shouldSetVerticalMargins?(shouldSet)
}
}

View File

@ -47,6 +47,7 @@ public class MoleculeStackView: ViewConstrainingView {
/// For setting the direction of the stack
var axis: NSLayoutConstraint.Axis = .vertical {
didSet {
moleculesShouldSetHorizontalMargins = (moleculesShouldSetHorizontalMargins && axis == .vertical)
if axis != oldValue {
restack()
}
@ -136,15 +137,20 @@ public class MoleculeStackView: ViewConstrainingView {
}
}
// If this item is in another container, do have the child molecules not use alignment.
public override func shouldSetHorizontalMargins(_ shouldSet: Bool) {
super.shouldSetHorizontalMargins(shouldSet)
moleculesShouldSetHorizontalMargins = false
moleculesShouldSetHorizontalMargins = (shouldSet && axis == .vertical)
for item in items {
(item.view as? MVMCoreUIViewConstrainingProtocol)?.shouldSetHorizontalMargins?(moleculesShouldSetHorizontalMargins)
}
}
public override func shouldSetVerticalMargins(_ shouldSet: Bool) {
super.shouldSetVerticalMargins(shouldSet)
moleculesShouldSetVerticalMargins = false
for item in items {
(item.view as? MVMCoreUIViewConstrainingProtocol)?.shouldSetVerticalMargins?(moleculesShouldSetVerticalMargins)
}
}
open override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
@ -187,32 +193,51 @@ public class MoleculeStackView: ViewConstrainingView {
if let item = items?[index] {
item.update(with: moleculeJSON)
view = item.view
(view as? MVMCoreUIMoleculeViewProtocol)?.setWithJSON(moleculeJSON, delegateObject: delegateObject, additionalData: nil)
addStackItem(item, lastItem: index == molecules.count - 1)
} else if let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject, constrainIfNeeded: true) {
view = molecule
addStackItem(StackItem(with: molecule, json: map), lastItem: index == molecules.count - 1)
}
(view as? MVMCoreUIViewConstrainingProtocol)?.shouldSetHorizontalMargins?(moleculesShouldSetHorizontalMargins && axis == .vertical)
(view as? MVMCoreUIViewConstrainingProtocol)?.shouldSetHorizontalMargins?(moleculesShouldSetHorizontalMargins)
(view as? MVMCoreUIViewConstrainingProtocol)?.shouldSetVerticalMargins?(moleculesShouldSetVerticalMargins)
(view as? MVMCoreUIMoleculeViewProtocol)?.setWithJSON(moleculeJSON, delegateObject: delegateObject, additionalData: nil)
}
}
}
public override static func name(forReuse molecule: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? {
// This will aggregate names of molecules to make an id.
var name = ""
guard let molecules = molecule?.optionalArrayForKey(KeyMolecules) else {
return name
return "stack<>"
}
var name = "stack<"
for case let item as [AnyHashable: AnyHashable] in molecules {
if let moleculeName = item.stringOptionalWithChainOfKeysOrIndexes([KeyMolecule, KeyMoleculeName]) {
name.append(moleculeName)
if let molecule = item.optionalDictionaryForKey(KeyMolecule), let moleculeName = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: molecule)?.name?(forReuse: molecule, delegateObject: delegateObject) ?? molecule.optionalStringForKey(KeyMoleculeName) {
name.append(moleculeName + ",")
}
}
name.append(">")
return name
}
public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
// if horizontal, max, if vertical, append.
return 100
}
public override static func requiredModules(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> [String]? {
guard let items = json?.optionalArrayForKey(KeyMolecules) else {
return nil
}
var modules: [String] = []
for case let item as [AnyHashable: AnyHashable] in items {
if let molecule = item.optionalDictionaryForKey(KeyMolecule), let modulesForMolecule = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: molecule)?.requiredModules?(molecule, delegateObject: delegateObject, error: error) {
modules += modulesForMolecule
}
}
return modules.count > 0 ? modules : nil
}
// MARK: - Adding to stack
/// Adds the view to the stack.
func addView(_ view: UIView, lastItem: Bool) {

View File

@ -98,13 +98,14 @@ import UIKit
}
molecule = moleculeView
}
} else {
molecule?.setWithJSON(moleculeJSON, delegateObject: delegateObject, additionalData: additionalData)
}
if let castView = molecule as? MVMCoreUIViewConstrainingProtocol {
let standardConstraints = castView.useStandardConstraints?() ?? true
castView.shouldSetHorizontalMargins?(!standardConstraints)
castView.shouldSetVerticalMargins?(!standardConstraints)
}
molecule?.setWithJSON(moleculeJSON, delegateObject: delegateObject, additionalData: additionalData)
backgroundColor = molecule?.backgroundColor
@ -126,25 +127,26 @@ import UIKit
molecule?.reset?()
}
public static func estimatedHeight(forRow json: [AnyHashable: Any]?) -> CGFloat {
guard let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule),
let theClass = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: moleculeJSON, delegateObject: nil),
let estimatedHeightFor = theClass.estimatedHeight else {
public static func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
guard let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule), let height = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: moleculeJSON)?.estimatedHeight?(forRow: moleculeJSON, delegateObject: delegateObject) else {
return 80
}
return estimatedHeightFor(moleculeJSON)
return height
}
public static func name(forReuse molecule: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? {
if let molecule = molecule?.optionalDictionaryForKey(KeyMolecule),
let moleculeName = molecule.optionalStringForKey(KeyMoleculeName),
let moleculeClass = MVMCoreUIMoleculeMappingObject.shared()?.moleculeMapping[moleculeName] as? AnyClass,
let castClass = moleculeClass as? MVMCoreUIMoleculeViewProtocol.Type,
let nameFunc = castClass.name {
return nameFunc(molecule, delegateObject)
} else {
return molecule?.optionalDictionaryForKey(KeyMolecule)?.optionalStringForKey(KeyMoleculeName)
guard let molecule = molecule?.optionalDictionaryForKey(KeyMolecule) else {
return nil
}
return MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: molecule)?.name?(forReuse: molecule, delegateObject: delegateObject) ?? molecule.optionalStringForKey(KeyMoleculeName)
}
public static func requiredModules(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> [String]? {
guard let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule),
let theClass = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: moleculeJSON) else {
return nil
}
return theClass.requiredModules?(moleculeJSON, delegateObject: delegateObject, error: error)
}
// MARK: - Arrow

View File

@ -21,22 +21,19 @@
+ (nullable instancetype)sharedMappingObject;
/// Returns the molecule class.
- (nullable Class)getMoleculeClassWithJSON:(nonnull NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject;
- (nullable Class)getMoleculeClassWithJSON:(nonnull NSDictionary *)json;
#pragma mark - Molecule Creation
/// Creates the molecule for the given name.
- (nullable UIView <MVMCoreUIMoleculeViewProtocol>*)createMoleculeForName:(nonnull NSString *)name;
/// Creates the molecule for the molecule json. Takes into account moduleMolecule as well.
/// Creates the molecule for the molecule json.
- (nullable UIView <MVMCoreUIMoleculeViewProtocol>*)createMoleculeForJSON:(nonnull NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject;
/// Creates the molecule for the molecule json. Takes into account moduleMolecule as well. Also checks if the molecule needs to be constrained for a stack/list style situation.
/// Creates the molecule for the molecule json. Also checks if the molecule needs to be constrained for a stack/list style situation.
- (nullable UIView <MVMCoreUIMoleculeViewProtocol>*)createMoleculeForJSON:(nonnull NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject constrainIfNeeded:(BOOL)constrainIfNeeded;
#pragma mark - ModuleMolecule Helpers
#pragma mark - Convenience
/// If the molecule is a module molecule, will get the map for the molecule to load from a module. Otherwise nil.
+ (nullable NSDictionary *)getMoleculeMapForModuleMolecule:(nullable NSDictionary *)moduleMolecule delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject error:(MVMCoreErrorObject *_Nullable *_Nullable)error;
+ (nullable NSArray <NSString *>*)getRequiredModulesForJSON:(nullable NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject error:(MVMCoreErrorObject *_Nullable *_Nullable)error;
+ (void)addRequiredModulesForJSON:(nullable NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject moduleList:(nullable NSMutableArray <NSDictionary *>*)moduleList errorList:(nullable NSMutableArray <MVMCoreErrorObject *>*)errorList;
@end

View File

@ -10,6 +10,7 @@
@import MVMCore.MVMCoreActionUtility;
@import MVMCore.NSDictionary_MFConvenience;
@import MVMCore.MVMCoreLoadObject;
@import MVMCore.MVMCoreErrorObject;
#import "MVMCoreUIObject.h"
#import <MVMCoreUI/MVMCoreUI-Swift.h>
#import "MFTextField.h"
@ -44,7 +45,8 @@
@"switchLineItem": SwitchLineItem.class,
@"switch": Switch.class,
@"image": MFLoadImageView.class,
@"leftRightLabelView": LeftRightLabelView.class
@"leftRightLabelView": LeftRightLabelView.class,
@"moduleMolecule": ModuleMolecule.class
} mutableCopy];
});
return mapping;
@ -55,9 +57,8 @@
return [MVMCoreActionUtility initializerClassCheck:[MVMCoreUIObject sharedInstance].moleculeMap classToVerify:self];
}
- (nullable Class)getMoleculeClassWithJSON:(nonnull NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject {
NSDictionary *moleculeJSON = [MVMCoreUIMoleculeMappingObject getMoleculeMapForModuleMolecule:json delegateObject:delegateObject error:nil] ?: json;
NSString *moleculeName = [moleculeJSON string:KeyMoleculeName];
- (nullable Class)getMoleculeClassWithJSON:(nonnull NSDictionary *)json {
NSString *moleculeName = [json string:KeyMoleculeName];
if (moleculeName) {
return [self.moleculeMapping objectForKey:moleculeName];
}
@ -83,13 +84,13 @@
}
- (nullable UIView <MVMCoreUIMoleculeViewProtocol>*)createMoleculeForJSON:(nonnull NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject constrainIfNeeded:(BOOL)constrainIfNeeded {
NSDictionary *moleculeJSON = [MVMCoreUIMoleculeMappingObject getMoleculeMapForModuleMolecule:json delegateObject:delegateObject error:nil] ?: json;
NSString *moleculeName = [moleculeJSON string:KeyMoleculeName];
NSString *moleculeName = [json string:KeyMoleculeName];
if (!moleculeName) {
return nil;
}
UIView <MVMCoreUIMoleculeViewProtocol>*molecule = [self createMoleculeForName:moleculeName];
[molecule setWithJSON:json delegateObject:delegateObject additionalData:nil];
// Check if we need to constrain this view.
UIView <MVMCoreUIViewConstrainingProtocol> *castMolecule = [molecule conformsToProtocol:@protocol(MVMCoreUIViewConstrainingProtocol)] ? (UIView <MVMCoreUIViewConstrainingProtocol> *)molecule : nil;
if (constrainIfNeeded && [castMolecule respondsToSelector:@selector(needsToBeConstrained)] && [castMolecule needsToBeConstrained]) {
@ -98,20 +99,26 @@
return molecule;
}
#pragma mark - ModuleMolecule Helpers
#pragma mark - Convenience
+ (nullable NSDictionary *)getMoleculeMapForModuleMolecule:(nullable NSDictionary *)moduleMolecule delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject error:(MVMCoreErrorObject *_Nullable *_Nullable)error {
NSString *moleculeName = [moduleMolecule string:KeyMoleculeName];
if ([moleculeName isEqualToString:@"moduleMolecule"]) {
NSString *moduleName = [moduleMolecule string:@"moduleName"];
NSDictionary *module = moduleName ? [delegateObject.moleculeDelegate getModuleWithName:moduleName] : nil;
if (!module && error) {
*error = [[MVMCoreErrorObject alloc] initWithTitle:nil message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorUnableToProcess] code:ErrorCodeModuleMolecule domain:ErrorDomainNative location:NSStringFromClass(self)];
}
return module;
+ (nullable NSArray <NSString *>*)getRequiredModulesForJSON:(nullable NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject error:(MVMCoreErrorObject *_Nullable *_Nullable)error {
Class <MVMCoreUIMoleculeViewProtocol>theClass = [[MVMCoreUIMoleculeMappingObject sharedMappingObject] getMoleculeClassWithJSON:json];
if ([theClass respondsToSelector:@selector(requiredModules:delegateObject:error:)]) {
return [theClass requiredModules:json delegateObject:delegateObject error:error];
} else {
return nil;
}
}
+ (void)addRequiredModulesForJSON:(nullable NSDictionary *)json delegateObject:(nullable MVMCoreUIDelegateObject *)delegateObject moduleList:(nullable NSMutableArray <NSDictionary *>*)moduleList errorList:(nullable NSMutableArray <MVMCoreErrorObject *>*)errorList {
MVMCoreErrorObject *error = nil;
NSArray *modules = [self getRequiredModulesForJSON:json delegateObject:delegateObject error:&error];
if (modules) {
[moduleList addObjectsFromArray:modules];
}
if (error) {
[errorList addObject:error];
}
}
@end

View File

@ -1,47 +0,0 @@
//
// MoleculeMappingObject+Extension.swift
// MVMCoreUI
//
// Created by Scott Pfeil on 5/23/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import Foundation
public extension MVMCoreUIMoleculeMappingObject {
/// Gets the molecule, and if it belonged to a moduleMolecule, the module name or error.
static func getMoleculeJSON(for map: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> (molecule: [AnyHashable: Any]?, moduleName: String?, error: MVMCoreErrorObject?)? {
guard let map = map, let moleculeName = map.optionalStringForKey(KeyMoleculeName) else {
return nil
}
guard moleculeName == "moduleMolecule" else {
// Not a module molecule.
return (map, nil, nil)
}
guard let moduleName = map.optionalStringForKey("moduleName"),
let module = delegateObject?.moleculeDelegate?.getModuleWithName(moduleName) else {
guard let error = MVMCoreErrorObject(title: nil, message: MVMCoreGetterUtility.hardcodedString(withKey: HardcodedErrorUnableToProcess), code: CoreUIErrorCode.ErrorCodeModuleMolecule.rawValue, domain: ErrorDomainNative, location: String(describing: self)) else {
return nil
}
MVMCoreUILoggingHandler.shared()?.addError(toLog: error)
return (nil, nil, error)
}
return (module, moduleName, nil)
}
/// Gets the molecule, and if it belonged to a moduleMolecule adds the module name or error to the passed lists.
static func getMoleculeJSON(for map: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, moduleNames: inout [String]?, errors: inout [MVMCoreErrorObject]?) -> [AnyHashable: Any]? {
guard let molecule = getMoleculeJSON(for: map, delegateObject: delegateObject) else {
return nil
}
if let moduleName = molecule.moduleName {
moduleNames?.append(moduleName)
}
if let error = molecule.error {
errors?.append(error)
}
return molecule.molecule
}
}

View File

@ -9,15 +9,16 @@
import UIKit
open class MoleculeListTemplate: ThreeLayerTableViewController {
var molecules: [(molecule: [AnyHashable: Any]?, moduleName: String?, error: MVMCoreErrorObject?)]?
var moleculesInfo: [(identifier: String, class: AnyClass, molecule: [AnyHashable: Any])]?
var modulesRequired: NSMutableArray?
open override func shouldFinishProcessingLoad(_ loadObject: MVMCoreLoadObject, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject>) -> Bool {
var shouldFinish = super.shouldFinishProcessingLoad(loadObject, error: error)
guard shouldFinish else {
return shouldFinish
}
if let firstError = setup()?.first {
if let firstError = setup()?.firstObject as? MVMCoreErrorObject {
// Don't continue if there was an error loading needed modules.
error.pointee = firstError
shouldFinish = false
@ -30,7 +31,6 @@ open class MoleculeListTemplate: ThreeLayerTableViewController {
let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, constrainIfNeeded: true) else {
return super.viewForTop()
}
molecule.setWithJSON(moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, additionalData: nil)
return molecule
}
@ -39,47 +39,43 @@ open class MoleculeListTemplate: ThreeLayerTableViewController {
let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, constrainIfNeeded: true) else {
return super.viewForBottom()
}
molecule.setWithJSON(moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, additionalData: nil)
return molecule
}
open override func newDataBuildScreen() {
super.newDataBuildScreen()
_ = setupMoleculeList()
_ = setup()
registerWithTable()
}
// MARK: - table
open override func registerWithTable() {
super.registerWithTable()
guard let molecules = molecules else {
guard let moleculesInfo = moleculesInfo else {
return
}
for molecule in molecules {
if let moleculeInfo = getMoleculeInfo(with: molecule), let moleculeToRegister = moleculeInfo.name {
tableView?.register(moleculeInfo.class, forCellReuseIdentifier: moleculeToRegister)
}
for moleculeInfo in moleculesInfo {
print(moleculeInfo.identifier)
tableView?.register(moleculeInfo.class, forCellReuseIdentifier: moleculeInfo.identifier)
}
}
open override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
guard let molecule = molecules?[indexPath.row],
let moleculeInfo = getMoleculeInfo(with: molecule),
let estimatedHeight = moleculeInfo.class.estimatedHeight else {
guard let moleculeInfo = moleculesInfo?[indexPath.row],
let estimatedHeight = moleculeInfo.class.estimatedHeight?(forRow: moleculeInfo.molecule, delegateObject: delegateObject() as? MVMCoreUIDelegateObject) else {
return 0
}
return estimatedHeight(molecule.molecule)
print("height :" + moleculeInfo.class.description() + " :" + estimatedHeight.description)
return estimatedHeight
}
open override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return molecules?.count ?? 0
return moleculesInfo?.count ?? 0
}
open override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let molecule = molecules?[indexPath.row],
let moleculeInfo = getMoleculeInfo(with: molecule),
let moleculeName = moleculeInfo.name,
let cell = tableView.dequeueReusableCell(withIdentifier: moleculeName) else {
guard let moleculeInfo = moleculesInfo?[indexPath.row],
let cell = tableView.dequeueReusableCell(withIdentifier: moleculeInfo.identifier) else {
return UITableViewCell()
}
let delegate = delegateObject() as? MVMCoreUIDelegateObject
@ -88,7 +84,7 @@ open class MoleculeListTemplate: ThreeLayerTableViewController {
}
if let protocolCell = cell as? MVMCoreUIMoleculeViewProtocol {
protocolCell.reset?()
protocolCell.setWithJSON(molecule.molecule, delegateObject: delegate, additionalData: nil)
protocolCell.setWithJSON(moleculeInfo.molecule, delegateObject: delegate, additionalData: nil)
protocolCell.updateView(tableView.bounds.width)
}
return cell
@ -110,78 +106,52 @@ open class MoleculeListTemplate: ThreeLayerTableViewController {
open override func modulesToListenFor() -> [Any]? {
// Get all of the molecules that need modules.
return modulesNeeded()
return modulesRequired as? [Any]
}
// MARK: - Module Molecule Handling
/// Returns the (name, class) of the molecule for the given map.
func getMoleculeInfo(with molecule: (molecule: [AnyHashable: Any]?, moduleName: String?, error: MVMCoreErrorObject?)) -> (name: String?, class: AnyClass)? {
guard let map = molecule.molecule, let moleculeName = map.optionalStringForKey(KeyMoleculeName), let moleculeClass = MVMCoreUIMoleculeMappingObject.shared()?.moleculeMapping[moleculeName] as? AnyClass else {
// MARK: - Convenience
/// Returns the (identifier, class) of the molecule for the given map.
func getMoleculeInfo(with molecule: [AnyHashable: Any]?) -> (identifier: String, class: AnyClass, molecule: [AnyHashable: Any])? {
guard let molecule = molecule,
let moleculeClass = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: molecule),
let moleculeName = moleculeClass.name?(forReuse: molecule, delegateObject: delegateObject() as? MVMCoreUIDelegateObject) ?? molecule.optionalStringForKey(KeyMoleculeName) else {
return nil
}
if let moleculeClass = moleculeClass as? MVMCoreUIMoleculeViewProtocol.Type, let moleculeNameFunc = moleculeClass.name {
return (moleculeNameFunc(map, delegateObject() as? MVMCoreUIDelegateObject), moleculeClass)
} else {
return (moleculeName, moleculeClass)
}
return (moleculeName, moleculeClass, molecule)
}
/// Sets up the molecule list and ensures no errors loading all content.
func setupMoleculeList() -> [MVMCoreErrorObject]? {
var errors: [MVMCoreErrorObject] = []
let delegate = delegateObject() as? MVMCoreUIDelegateObject
var moleculeList: [(molecule: [AnyHashable: Any]?, moduleName: String?, error: MVMCoreErrorObject?)] = []
func getMoleculeInfoList() -> [(identifier: String, class: AnyClass, molecule: [AnyHashable: Any])]? {
var moleculeList: [(identifier: String, class: AnyClass, molecule: [AnyHashable: Any])] = []
if let molecules = loadObject?.pageJSON?.optionalArrayForKey(KeyMolecules) as? [[AnyHashable: Any]] {
for molecule in molecules {
if let object = MVMCoreUIMoleculeMappingObject.getMoleculeJSON(for: molecule, delegateObject: delegate) {
if let error = object.error {
errors.append(error)
} else {
moleculeList.append(object)
}
if let info = getMoleculeInfo(with: molecule) {
moleculeList.append(info)
}
}
}
molecules = moleculeList
return errors.count > 0 ? errors : nil
return moleculeList.count > 0 ? moleculeList : nil
}
/// Sets up the header, footer, molecule list and ensures no errors loading all content.
func setup() -> [MVMCoreErrorObject]? {
var errors: [MVMCoreErrorObject] = []
func setup() -> NSMutableArray? {
let modules: NSMutableArray = []
let errors: NSMutableArray = []
let delegate = delegateObject() as? MVMCoreUIDelegateObject
MoleculeListTemplate.addToErrorList(with: MVMCoreUIMoleculeMappingObject.getMoleculeJSON(for: loadObject?.pageJSON?.optionalDictionaryForKey("header"), delegateObject: delegate), errors: &errors)
MoleculeListTemplate.addToErrorList(with: MVMCoreUIMoleculeMappingObject.getMoleculeJSON(for: loadObject?.pageJSON?.optionalDictionaryForKey("footer"), delegateObject: delegate), errors: &errors)
if let newErrors = setupMoleculeList() {
errors.append(contentsOf: newErrors)
}
return errors.count > 0 ? errors : nil
}
static func addToErrorList(with moleculeObject: (molecule: [AnyHashable: Any]?, moduleName: String?, error: MVMCoreErrorObject?)?, errors: inout [MVMCoreErrorObject]) {
if let error = moleculeObject?.error {
errors.append(error)
}
}
static func addToModuleList(with moleculeObject: (molecule: [AnyHashable: Any]?, moduleName: String?, error: MVMCoreErrorObject?)?, moduleNames: inout [String]) {
if let moduleName = moleculeObject?.moduleName {
moduleNames.append(moduleName)
}
}
/// Gets a list of required modules
func modulesNeeded() -> [String]? {
var modules: [String] = []
let delegate = delegateObject() as? MVMCoreUIDelegateObject
MoleculeListTemplate.addToModuleList(with: MVMCoreUIMoleculeMappingObject.getMoleculeJSON(for: loadObject?.pageJSON?.optionalDictionaryForKey("header"), delegateObject: delegate), moduleNames: &modules)
MoleculeListTemplate.addToModuleList(with: MVMCoreUIMoleculeMappingObject.getMoleculeJSON(for: loadObject?.pageJSON?.optionalDictionaryForKey("footer"), delegateObject: delegate), moduleNames: &modules)
if let molecules = molecules {
MVMCoreUIMoleculeMappingObject.addRequiredModules(forJSON: loadObject?.pageJSON?.optionalDictionaryForKey("header"), delegateObject: delegate, moduleList: modules, errorList: errors)
MVMCoreUIMoleculeMappingObject.addRequiredModules(forJSON: loadObject?.pageJSON?.optionalDictionaryForKey("footer"), delegateObject: delegate, moduleList: modules, errorList: errors)
var moleculeList: [(identifier: String, class: AnyClass, molecule: [AnyHashable: Any])] = []
if let molecules = loadObject?.pageJSON?.optionalArrayForKey(KeyMolecules) as? [[AnyHashable: Any]] {
for molecule in molecules {
MoleculeListTemplate.addToModuleList(with: molecule, moduleNames: &modules)
if let info = getMoleculeInfo(with: molecule) {
moleculeList.append(info)
MVMCoreUIMoleculeMappingObject.addRequiredModules(forJSON: molecule, delegateObject: delegate, moduleList: modules, errorList: errors)
}
}
}
return (modules.count > 0 ? modules : nil)
moleculesInfo = moleculeList
modulesRequired = modules
return errors.count > 0 ? errors : nil
}
}

View File

@ -9,10 +9,11 @@
import UIKit
public class MoleculeStackTemplate: ThreeLayerViewController {
var modulesRequired: NSMutableArray?
public override func shouldFinishProcessingLoad(_ loadObject: MVMCoreLoadObject, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject>) -> Bool {
var shouldFinish = super.shouldFinishProcessingLoad(loadObject, error: error)
if shouldFinish, let firstError = modulesNeeded().errors?.first {
if shouldFinish, let firstError = modulesNeeded().errors?.firstObject as? MVMCoreErrorObject {
// Don't continue if there was an error loading needed modules.
error.pointee = firstError
shouldFinish = false
@ -28,7 +29,6 @@ public class MoleculeStackTemplate: ThreeLayerViewController {
guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("header"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, constrainIfNeeded: true) else {
return nil
}
molecule.setWithJSON(moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, additionalData: nil)
return molecule
}
@ -46,7 +46,6 @@ public class MoleculeStackTemplate: ThreeLayerViewController {
guard let moleculeJSON = loadObject?.pageJSON?.optionalDictionaryForKey("footer"), let molecule = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, constrainIfNeeded: true) else {
return nil
}
molecule.setWithJSON(moleculeJSON, delegateObject: delegateObject() as? MVMCoreUIDelegateObject, additionalData: nil)
return molecule
}
@ -60,22 +59,18 @@ public class MoleculeStackTemplate: ThreeLayerViewController {
public override func modulesToListenFor() -> [Any]? {
// Get all of the molecules that need modules.
return modulesNeeded().modules
return modulesNeeded().modules as? [Any]
}
// MARK: - Module Molecule Handling
func modulesNeeded() -> (modules: [String]?, errors: [MVMCoreErrorObject]?) {
var modules: [String]? = []
var errors: [MVMCoreErrorObject]? = []
/// Gets the modules needed.
func modulesNeeded() -> (modules: NSMutableArray?, errors: NSMutableArray?) {
let modules: NSMutableArray = []
let errors: NSMutableArray = []
let delegate = delegateObject() as? MVMCoreUIDelegateObject
let _ = MVMCoreUIMoleculeMappingObject.getMoleculeJSON(for: loadObject?.pageJSON?.optionalDictionaryForKey("header"), delegateObject: delegate, moduleNames: &modules, errors: &errors)
let _ = MVMCoreUIMoleculeMappingObject.getMoleculeJSON(for: loadObject?.pageJSON?.optionalDictionaryForKey("footer"), delegateObject: delegate, moduleNames: &modules, errors: &errors)
if let molecules = loadObject?.pageJSON?.optionalArrayForChainOfKeysOrIndexes(["moleculeStack",KeyMolecules]) as? [[AnyHashable: Any]] {
for molecule in molecules {
let _ = MVMCoreUIMoleculeMappingObject.getMoleculeJSON(for: molecule, delegateObject: delegate, moduleNames: &modules, errors: &errors)
}
}
return (modules?.count ?? 0 > 0 ? modules : nil, errors?.count ?? 0 > 0 ? errors : nil)
MVMCoreUIMoleculeMappingObject.addRequiredModules(forJSON: loadObject?.pageJSON?.optionalDictionaryForKey("header"), delegateObject: delegate, moduleList: modules, errorList: errors)
MVMCoreUIMoleculeMappingObject.addRequiredModules(forJSON: loadObject?.pageJSON?.optionalDictionaryForKey("footer"), delegateObject: delegate, moduleList: modules, errorList: errors)
MVMCoreUIMoleculeMappingObject.addRequiredModules(forJSON: loadObject?.pageJSON?.optionalDictionaryForKey("moleculeStack"), delegateObject: delegate, moduleList: modules, errorList: errors)
modulesRequired = modules
return (modules.count > 0 ? modules : nil, errors.count > 0 ? errors : nil)
}
}