From dbfd6edc64f33ab0236090d174c59b992de0a111 Mon Sep 17 00:00:00 2001 From: Morgan Chen Date: Thu, 4 Aug 2016 10:19:14 -0700 Subject: [PATCH 01/28] remove broken shell script thing --- FirebaseUI.xcodeproj/project.pbxproj | 77 ++++++++++++---------------- 1 file changed, 32 insertions(+), 45 deletions(-) diff --git a/FirebaseUI.xcodeproj/project.pbxproj b/FirebaseUI.xcodeproj/project.pbxproj index 13af95729f8..72d28a01787 100644 --- a/FirebaseUI.xcodeproj/project.pbxproj +++ b/FirebaseUI.xcodeproj/project.pbxproj @@ -81,6 +81,7 @@ 1073FEB81CE50A8F00E2F73F /* FirebaseTableViewDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 1073FEAF1CE50A8F00E2F73F /* FirebaseTableViewDataSource.m */; }; 79F1B3CFC3F6E157C28C30F5 /* libPods-Auth.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2F28F3BD9C664DEB963595FF /* libPods-Auth.a */; }; 8D7710365523A745DAA1321E /* libPods-FirebaseUI.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 275B4831F13A9ADD39B47692 /* libPods-FirebaseUI.a */; }; + A3737316F1D0A028E08E9183 /* libPods-Database.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E7EBD66D7AB946A019E62B7F /* libPods-Database.a */; }; D8666CB71CEAFCD5002B7C26 /* FirebaseArray.m in Sources */ = {isa = PBXBuildFile; fileRef = 1073FEAC1CE50A8F00E2F73F /* FirebaseArray.m */; }; D8666CB81CEAFCD5002B7C26 /* FirebaseCollectionViewDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 1073FEAD1CE50A8F00E2F73F /* FirebaseCollectionViewDataSource.m */; }; D8666CB91CEAFCD5002B7C26 /* FirebaseDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 1073FEAE1CE50A8F00E2F73F /* FirebaseDataSource.m */; }; @@ -362,6 +363,7 @@ buildActionMask = 2147483647; files = ( D8666D331CEB0187002B7C26 /* FirebaseDatabase.framework in Frameworks */, + A3737316F1D0A028E08E9183 /* libPods-Database.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -802,12 +804,12 @@ isa = PBXNativeTarget; buildConfigurationList = D8666CB61CEAFC93002B7C26 /* Build configuration list for PBXNativeTarget "Database" */; buildPhases = ( - EE4FB8B0A2310732DCF60111 /* 📦 Check Pods Manifest.lock */, + EE4FB8B0A2310732DCF60111 /* [CP] Check Pods Manifest.lock */, D8666CAA1CEAFC93002B7C26 /* Sources */, D8666CAB1CEAFC93002B7C26 /* Frameworks */, D8666CAC1CEAFC93002B7C26 /* CopyFiles */, D8666CBB1CEAFCFB002B7C26 /* Headers */, - EDF383BBC4F3A6CDD217F06A /* 📦 Copy Pods Resources */, + EDF383BBC4F3A6CDD217F06A /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -822,13 +824,13 @@ isa = PBXNativeTarget; buildConfigurationList = D8666CCC1CEAFD40002B7C26 /* Build configuration list for PBXNativeTarget "Auth" */; buildPhases = ( - 4F409FB222EDC7574E52A97F /* 📦 Check Pods Manifest.lock */, + 4F409FB222EDC7574E52A97F /* [CP] Check Pods Manifest.lock */, D8666CC21CEAFD40002B7C26 /* Sources */, D8666CC31CEAFD40002B7C26 /* Frameworks */, D8666CC41CEAFD40002B7C26 /* CopyFiles */, D8666CDD1CEAFD73002B7C26 /* Headers */, D8666CEF1CEAFD9E002B7C26 /* Resources */, - 0F661CA715BBA079DC42B8E0 /* 📦 Copy Pods Resources */, + 0F661CA715BBA079DC42B8E0 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -843,11 +845,11 @@ isa = PBXNativeTarget; buildConfigurationList = D8666D0F1CEAFF29002B7C26 /* Build configuration list for PBXNativeTarget "Facebook" */; buildPhases = ( - D17D52CDF1B7F0B80C57DD59 /* 📦 Check Pods Manifest.lock */, + D17D52CDF1B7F0B80C57DD59 /* [CP] Check Pods Manifest.lock */, D8666D031CEAFF29002B7C26 /* Sources */, D8666D041CEAFF29002B7C26 /* Frameworks */, D8666D051CEAFF29002B7C26 /* CopyFiles */, - 61350DBC677183EF5C0F3C30 /* 📦 Copy Pods Resources */, + 61350DBC677183EF5C0F3C30 /* [CP] Copy Pods Resources */, D8666D1E1CEAFF9D002B7C26 /* Headers */, D8666D211CEAFFA7002B7C26 /* Resources */, ); @@ -865,11 +867,11 @@ isa = PBXNativeTarget; buildConfigurationList = D8666D1A1CEAFF41002B7C26 /* Build configuration list for PBXNativeTarget "Google" */; buildPhases = ( - 072ABD579ED6CE7C8FC98658 /* 📦 Check Pods Manifest.lock */, + 072ABD579ED6CE7C8FC98658 /* [CP] Check Pods Manifest.lock */, D8666D101CEAFF41002B7C26 /* Sources */, D8666D111CEAFF41002B7C26 /* Frameworks */, D8666D121CEAFF41002B7C26 /* CopyFiles */, - 7DC3FAEEEC64FFC78D855373 /* 📦 Copy Pods Resources */, + 7DC3FAEEEC64FFC78D855373 /* [CP] Copy Pods Resources */, D8666D271CEAFFC2002B7C26 /* Headers */, D8666D2A1CEAFFD9002B7C26 /* Resources */, ); @@ -887,14 +889,13 @@ isa = PBXNativeTarget; buildConfigurationList = D8C579AF1B57349000899F86 /* Build configuration list for PBXNativeTarget "FirebaseUI" */; buildPhases = ( - D1854EF2AF0C2648CD5C535D /* 📦 Check Pods Manifest.lock */, + D1854EF2AF0C2648CD5C535D /* [CP] Check Pods Manifest.lock */, D8C579A21B57349000899F86 /* Sources */, D8C579A31B57349000899F86 /* Frameworks */, D8C579A41B57349000899F86 /* Copy Files */, D8B6ACF71B583D31005CDDB2 /* Headers */, - D8B6ADA21B58DB8B005CDDB2 /* Build Framework */, D809A1321BF7F30C000257AA /* Resources */, - 1ECE9CCEBE1B8C2962053639 /* 📦 Copy Pods Resources */, + 1ECE9CCEBE1B8C2962053639 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -1035,14 +1036,14 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 072ABD579ED6CE7C8FC98658 /* 📦 Check Pods Manifest.lock */ = { + 072ABD579ED6CE7C8FC98658 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "📦 Check Pods Manifest.lock"; + name = "[CP] Check Pods Manifest.lock"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; @@ -1050,14 +1051,14 @@ shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; showEnvVarsInLog = 0; }; - 0F661CA715BBA079DC42B8E0 /* 📦 Copy Pods Resources */ = { + 0F661CA715BBA079DC42B8E0 /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "📦 Copy Pods Resources"; + name = "[CP] Copy Pods Resources"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; @@ -1065,14 +1066,14 @@ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Auth/Pods-Auth-resources.sh\"\n"; showEnvVarsInLog = 0; }; - 1ECE9CCEBE1B8C2962053639 /* 📦 Copy Pods Resources */ = { + 1ECE9CCEBE1B8C2962053639 /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "📦 Copy Pods Resources"; + name = "[CP] Copy Pods Resources"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; @@ -1080,14 +1081,14 @@ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-FirebaseUI/Pods-FirebaseUI-resources.sh\"\n"; showEnvVarsInLog = 0; }; - 4F409FB222EDC7574E52A97F /* 📦 Check Pods Manifest.lock */ = { + 4F409FB222EDC7574E52A97F /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "📦 Check Pods Manifest.lock"; + name = "[CP] Check Pods Manifest.lock"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; @@ -1095,14 +1096,14 @@ shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; showEnvVarsInLog = 0; }; - 61350DBC677183EF5C0F3C30 /* 📦 Copy Pods Resources */ = { + 61350DBC677183EF5C0F3C30 /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "📦 Copy Pods Resources"; + name = "[CP] Copy Pods Resources"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; @@ -1110,14 +1111,14 @@ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Facebook/Pods-Facebook-resources.sh\"\n"; showEnvVarsInLog = 0; }; - 7DC3FAEEEC64FFC78D855373 /* 📦 Copy Pods Resources */ = { + 7DC3FAEEEC64FFC78D855373 /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "📦 Copy Pods Resources"; + name = "[CP] Copy Pods Resources"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; @@ -1125,14 +1126,14 @@ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Google/Pods-Google-resources.sh\"\n"; showEnvVarsInLog = 0; }; - D17D52CDF1B7F0B80C57DD59 /* 📦 Check Pods Manifest.lock */ = { + D17D52CDF1B7F0B80C57DD59 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "📦 Check Pods Manifest.lock"; + name = "[CP] Check Pods Manifest.lock"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; @@ -1140,14 +1141,14 @@ shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; showEnvVarsInLog = 0; }; - D1854EF2AF0C2648CD5C535D /* 📦 Check Pods Manifest.lock */ = { + D1854EF2AF0C2648CD5C535D /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "📦 Check Pods Manifest.lock"; + name = "[CP] Check Pods Manifest.lock"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; @@ -1155,28 +1156,14 @@ shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; showEnvVarsInLog = 0; }; - D8B6ADA21B58DB8B005CDDB2 /* Build Framework */ = { + EDF383BBC4F3A6CDD217F06A /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "Build Framework"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "set -e\n\nexport FRAMEWORK_LOCN=\"${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework\"\n\n# Create the path to the real Headers die\nmkdir -p \"${FRAMEWORK_LOCN}/Versions/A/Headers\"\n\n# Create the required symlinks\n/bin/ln -sfh A \"${FRAMEWORK_LOCN}/Versions/Current\"\n/bin/ln -sfh Versions/Current/Headers \"${FRAMEWORK_LOCN}/Headers\"\n/bin/ln -sfh \"Versions/Current/${PRODUCT_NAME}\" \\\n\"${FRAMEWORK_LOCN}/${PRODUCT_NAME}\"\n\n# Copy the public headers into the framework\n/bin/cp -a \"${TARGET_BUILD_DIR}/${PUBLIC_HEADERS_FOLDER_PATH}/\" \\\n\"${FRAMEWORK_LOCN}/Versions/A/Headers\""; - }; - EDF383BBC4F3A6CDD217F06A /* 📦 Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "📦 Copy Pods Resources"; + name = "[CP] Copy Pods Resources"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; @@ -1184,14 +1171,14 @@ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Database/Pods-Database-resources.sh\"\n"; showEnvVarsInLog = 0; }; - EE4FB8B0A2310732DCF60111 /* 📦 Check Pods Manifest.lock */ = { + EE4FB8B0A2310732DCF60111 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "📦 Check Pods Manifest.lock"; + name = "[CP] Check Pods Manifest.lock"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; From 218a38af463d33ea1982817259b81923c1209686 Mon Sep 17 00:00:00 2001 From: Morgan Chen Date: Thu, 4 Aug 2016 10:20:26 -0700 Subject: [PATCH 02/28] fix ignoring pod ldflags --- FirebaseUI.xcodeproj/project.pbxproj | 44 +++++++++++++++++++++------- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/FirebaseUI.xcodeproj/project.pbxproj b/FirebaseUI.xcodeproj/project.pbxproj index 72d28a01787..92313fc7150 100644 --- a/FirebaseUI.xcodeproj/project.pbxproj +++ b/FirebaseUI.xcodeproj/project.pbxproj @@ -1322,7 +1322,10 @@ "$(inherited)", ); IPHONEOS_DEPLOYMENT_TARGET = 9.3; - OTHER_LDFLAGS = "-ObjC"; + OTHER_LDFLAGS = ( + "$(inherited)", + "-ObjC", + ); PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; }; @@ -1339,7 +1342,10 @@ "$(PROJECT_DIR)/Pods/FirebaseDatabase/Frameworks", ); IPHONEOS_DEPLOYMENT_TARGET = 9.3; - OTHER_LDFLAGS = "-ObjC"; + OTHER_LDFLAGS = ( + "$(inherited)", + "-ObjC", + ); PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; }; @@ -1366,7 +1372,10 @@ "$(inherited)", ); IPHONEOS_DEPLOYMENT_TARGET = 9.3; - OTHER_LDFLAGS = "-ObjC"; + OTHER_LDFLAGS = ( + "$(inherited)", + "-ObjC", + ); PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; }; @@ -1389,7 +1398,10 @@ "$(PROJECT_DIR)/Pods/FirebaseInstanceID/Frameworks", ); IPHONEOS_DEPLOYMENT_TARGET = 9.3; - OTHER_LDFLAGS = "-ObjC"; + OTHER_LDFLAGS = ( + "$(inherited)", + "-ObjC", + ); PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; }; @@ -1406,7 +1418,10 @@ "$(inherited)", ); IPHONEOS_DEPLOYMENT_TARGET = 9.3; - OTHER_LDFLAGS = "-ObjC"; + OTHER_LDFLAGS = ( + "$(inherited)", + "-ObjC", + ); PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; }; @@ -1419,7 +1434,10 @@ CLANG_ANALYZER_NONNULL = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; IPHONEOS_DEPLOYMENT_TARGET = 9.3; - OTHER_LDFLAGS = "-ObjC"; + OTHER_LDFLAGS = ( + "$(inherited)", + "-ObjC", + ); PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; }; @@ -1440,7 +1458,10 @@ "$(inherited)", ); IPHONEOS_DEPLOYMENT_TARGET = 9.3; - OTHER_LDFLAGS = "-ObjC"; + OTHER_LDFLAGS = ( + "$(inherited)", + "-ObjC", + ); PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; }; @@ -1457,7 +1478,10 @@ "$(PROJECT_DIR)/Pods/GoogleSignIn/Frameworks", ); IPHONEOS_DEPLOYMENT_TARGET = 9.3; - OTHER_LDFLAGS = "-ObjC"; + OTHER_LDFLAGS = ( + "$(inherited)", + "-ObjC", + ); PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; }; @@ -1577,7 +1601,7 @@ "$(PROJECT_DIR)/target/Products/Release-iphonesimulator", "$(PROJECT_DIR)/sdk/02468137448ba914-Google-1.0.7/Libraries", ); - OTHER_LDFLAGS = ""; + OTHER_LDFLAGS = "$(inherited)"; PRODUCT_NAME = "$(TARGET_NAME)"; PUBLIC_HEADERS_FOLDER_PATH = "include/$(PROJECT_NAME)"; SKIP_INSTALL = YES; @@ -1619,7 +1643,7 @@ "$(PROJECT_DIR)/target/Products/Release-iphonesimulator", "$(PROJECT_DIR)/sdk/02468137448ba914-Google-1.0.7/Libraries", ); - OTHER_LDFLAGS = ""; + OTHER_LDFLAGS = "$(inherited)"; PRODUCT_NAME = "$(TARGET_NAME)"; PUBLIC_HEADERS_FOLDER_PATH = "include/$(PROJECT_NAME)"; SKIP_INSTALL = YES; From 1c44ad7f667a99ea318750d188b3ee2c34dc060d Mon Sep 17 00:00:00 2001 From: Morgan Chen Date: Thu, 4 Aug 2016 11:24:24 -0700 Subject: [PATCH 03/28] make database apis more idiomatic --- FirebaseUI/Database/API/FirebaseArray.h | 18 +-- .../Database/API/FirebaseArrayDelegate.h | 12 +- .../API/FirebaseCollectionViewDataSource.h | 105 +++++++++--------- FirebaseUI/Database/API/FirebaseDataSource.h | 7 +- .../Database/Implementation/FirebaseArray.m | 36 ++++-- .../FirebaseCollectionViewDataSource.m | 4 +- .../Implementation/FirebaseDataSource.m | 15 ++- .../FirebaseTableViewDataSource.m | 4 +- 8 files changed, 117 insertions(+), 84 deletions(-) diff --git a/FirebaseUI/Database/API/FirebaseArray.h b/FirebaseUI/Database/API/FirebaseArray.h index c52d03b75be..4ea05da3386 100644 --- a/FirebaseUI/Database/API/FirebaseArray.h +++ b/FirebaseUI/Database/API/FirebaseArray.h @@ -39,7 +39,7 @@ NS_ASSUME_NONNULL_BEGIN * The delegate object that array changes are surfaced to, which conforms to the * [FirebaseArrayDelegate Protocol](FirebaseArrayDelegate). */ -@property(weak, nonatomic) id delegate; +@property(weak, nonatomic, nullable) id delegate; /** * The query on a Firebase reference that provides data to populate the instance of FirebaseArray. @@ -51,6 +51,16 @@ NS_ASSUME_NONNULL_BEGIN */ @property(strong, nonatomic) NSMutableArray * snapshots; +/** + * The number of objects in the FirebaseArray. + */ +@property(nonatomic, readonly) NSUInteger count; + +/** + * The items currently in the FirebaseArray. + */ +@property(nonatomic, readonly, copy) NSArray *items; + #pragma mark - #pragma mark Initializer methods @@ -71,12 +81,6 @@ NS_ASSUME_NONNULL_BEGIN #pragma mark - #pragma mark Public API methods -/** - * Returns the count of objects in the FirebaseArray. - * @return The count of objects in the FirebaseArray - */ -- (NSUInteger)count; - /** * Returns an object at a specific index in the FirebaseArray. * @param index The index of the item to retrieve diff --git a/FirebaseUI/Database/API/FirebaseArrayDelegate.h b/FirebaseUI/Database/API/FirebaseArrayDelegate.h index 731755d193b..785b4f952e5 100644 --- a/FirebaseUI/Database/API/FirebaseArrayDelegate.h +++ b/FirebaseUI/Database/API/FirebaseArrayDelegate.h @@ -18,6 +18,8 @@ // clang-format on +@class FirebaseArray; + /** * A protocol to allow instances of FirebaseArray to raise events through a * delegate. Raises all @@ -36,7 +38,7 @@ * @param object The object added to the FirebaseArray * @param index The index the child was added at */ -- (void)childAdded:(id)object atIndex:(NSUInteger)index; +- (void)array:(FirebaseArray *)array didAddObject:(id)object atIndex:(NSUInteger)index; /** * Delegate method which is called whenever an object is chinged in a @@ -47,7 +49,7 @@ * @param object The object that changed in the FirebaseArray * @param index The index the child was changed at */ -- (void)childChanged:(id)object atIndex:(NSUInteger)index; +- (void)array:(FirebaseArray *)array didChangeObject:(id)object atIndex:(NSUInteger)index; /** * Delegate method which is called whenever an object is removed from a @@ -58,7 +60,7 @@ * @param object The object removed from the FirebaseArray * @param index The index the child was removed at */ -- (void)childRemoved:(id)object atIndex:(NSUInteger)index; +- (void)array:(FirebaseArray *)array didRemoveObject:(id)object atIndex:(NSUInteger)index; /** * Delegate method which is called whenever an object is moved within a @@ -70,12 +72,12 @@ * @param fromIndex The index the child is being moved from * @param toIndex The index the child is being moved to */ -- (void)childMoved:(id)object fromIndex:(NSUInteger)fromIndex toIndex:(NSUInteger)toIndex; +- (void)array:(FirebaseArray *)array didMoveObject:(id)object fromIndex:(NSUInteger)fromIndex toIndex:(NSUInteger)toIndex; /** * Delegate method which is called whenever the backing query is canceled. * @param error the error that was raised */ -- (void)canceledWithError:(NSError *)error; +- (void)array:(FirebaseArray *)array queryCancelledWithError:(NSError *)error; @end diff --git a/FirebaseUI/Database/API/FirebaseCollectionViewDataSource.h b/FirebaseUI/Database/API/FirebaseCollectionViewDataSource.h index 988817192dd..c5859e5fe62 100644 --- a/FirebaseUI/Database/API/FirebaseCollectionViewDataSource.h +++ b/FirebaseUI/Database/API/FirebaseCollectionViewDataSource.h @@ -53,7 +53,7 @@ NS_ASSUME_NONNULL_BEGIN * Message will be * returned instead of type FIRDataSnapshot. */ -@property(strong, nonatomic) Class modelClass; +@property(strong, nonatomic, nullable) Class modelClass; /** * The cell class to coerce UICollectionViewCells to (if desired). For instance, @@ -63,7 +63,7 @@ NS_ASSUME_NONNULL_BEGIN * objects of type CustomCollectionViewCell will be returned instead of type * UICollectionViewCell. */ -@property(strong, nonatomic) Class cellClass; +@property(strong, nonatomic, nullable) Class cellClass; /** * The reuse identifier for cells in the UICollectionView. @@ -104,8 +104,8 @@ NS_ASSUME_NONNULL_BEGIN * FIRDataSnapshots */ - (instancetype)initWithRef:(FIRDatabaseReference *)ref - cellReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView; + cellReuseIdentifier:(NSString *)identifier + view:(UICollectionView *)collectionView; /** * Initialize an instance of FirebaseCollectionViewDataSource that populates @@ -121,8 +121,8 @@ NS_ASSUME_NONNULL_BEGIN * FIRDataSnapshots */ - (instancetype)initWithRef:(FIRDatabaseReference *)ref - prototypeReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView; + prototypeReuseIdentifier:(NSString *)identifier + view:(UICollectionView *)collectionView; /** * Initialize an instance of FirebaseCollectionViewDataSource that populates a @@ -139,9 +139,9 @@ NS_ASSUME_NONNULL_BEGIN * UICollectionViewCell with FIRDataSnapshots */ - (instancetype)initWithRef:(FIRDatabaseReference *)ref - cellClass:(nullable Class)cell - cellReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView; + cellClass:(nullable Class)cell + cellReuseIdentifier:(NSString *)identifier + view:(UICollectionView *)collectionView; /** * Initialize an instance of FirebaseCollectionViewDataSource that populates a @@ -157,9 +157,9 @@ NS_ASSUME_NONNULL_BEGIN * FIRDataSnapshots */ - (instancetype)initWithRef:(FIRDatabaseReference *)ref - nibNamed:(NSString *)nibName - cellReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView; + nibNamed:(NSString *)nibName + cellReuseIdentifier:(NSString *)identifier + view:(UICollectionView *)collectionView; /** * Initialize an instance of FirebaseCollectionViewDataSource that populates @@ -175,9 +175,9 @@ NS_ASSUME_NONNULL_BEGIN * a custom model class */ - (instancetype)initWithRef:(FIRDatabaseReference *)ref - modelClass:(nullable Class)model - cellReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView; + modelClass:(nullable Class)model + cellReuseIdentifier:(NSString *)identifier + view:(UICollectionView *)collectionView; /** * Initialize an instance of FirebaseCollectionViewDataSource that populates @@ -195,9 +195,9 @@ NS_ASSUME_NONNULL_BEGIN * a custom model class */ - (instancetype)initWithRef:(FIRDatabaseReference *)ref - modelClass:(nullable Class)model - prototypeReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView; + modelClass:(nullable Class)model + prototypeReuseIdentifier:(NSString *)identifier + view:(UICollectionView *)collectionView; /** * Initialize an instance of FirebaseCollectionViewDataSource that populates a @@ -216,10 +216,10 @@ NS_ASSUME_NONNULL_BEGIN * UICollectionViewCell with a custom model class */ - (instancetype)initWithRef:(FIRDatabaseReference *)ref - modelClass:(nullable Class)model - cellClass:(nullable Class)cell - cellReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView; + modelClass:(nullable Class)model + cellClass:(nullable Class)cell + cellReuseIdentifier:(NSString *)identifier + view:(UICollectionView *)collectionView; /** * Initialize an instance of FirebaseCollectionViewDataSource that populates a @@ -237,10 +237,10 @@ NS_ASSUME_NONNULL_BEGIN * model class */ - (instancetype)initWithRef:(FIRDatabaseReference *)ref - modelClass:(nullable Class)model - nibNamed:(NSString *)nibName - cellReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView; + modelClass:(nullable Class)model + nibNamed:(NSString *)nibName + cellReuseIdentifier:(NSString *)identifier + view:(UICollectionView *)collectionView; /** * Initialize an instance of FirebaseCollectionViewDataSource that populates @@ -254,8 +254,8 @@ NS_ASSUME_NONNULL_BEGIN * FIRDataSnapshots */ - (instancetype)initWithQuery:(FIRDatabaseQuery *)query - cellReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView; + cellReuseIdentifier:(NSString *)identifier + view:(UICollectionView *)collectionView; /** * Initialize an instance of FirebaseCollectionViewDataSource that populates @@ -271,8 +271,8 @@ NS_ASSUME_NONNULL_BEGIN * FIRDataSnapshots */ - (instancetype)initWithQuery:(FIRDatabaseQuery *)query - prototypeReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView; + prototypeReuseIdentifier:(NSString *)identifier + view:(UICollectionView *)collectionView; /** * Initialize an instance of FirebaseCollectionViewDataSource that populates a @@ -289,9 +289,9 @@ NS_ASSUME_NONNULL_BEGIN * UICollectionViewCell with FIRDataSnapshots */ - (instancetype)initWithQuery:(FIRDatabaseQuery *)query - cellClass:(nullable Class)cell - cellReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView; + cellClass:(nullable Class)cell + cellReuseIdentifier:(NSString *)identifier + view:(UICollectionView *)collectionView; /** * Initialize an instance of FirebaseCollectionViewDataSource that populates a @@ -307,9 +307,9 @@ NS_ASSUME_NONNULL_BEGIN * FIRDataSnapshots */ - (instancetype)initWithQuery:(FIRDatabaseQuery *)query - nibNamed:(NSString *)nibName - cellReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView; + nibNamed:(NSString *)nibName + cellReuseIdentifier:(NSString *)identifier + view:(UICollectionView *)collectionView; /** * Initialize an instance of FirebaseCollectionViewDataSource that populates @@ -325,9 +325,9 @@ NS_ASSUME_NONNULL_BEGIN * a custom model class */ - (instancetype)initWithQuery:(FIRDatabaseQuery *)query - modelClass:(nullable Class)model - cellReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView; + modelClass:(nullable Class)model + cellReuseIdentifier:(NSString *)identifier + view:(UICollectionView *)collectionView; /** * Initialize an instance of FirebaseCollectionViewDataSource that populates @@ -345,9 +345,9 @@ NS_ASSUME_NONNULL_BEGIN * a custom model class */ - (instancetype)initWithQuery:(FIRDatabaseQuery *)query - modelClass:(nullable Class)model - prototypeReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView; + modelClass:(nullable Class)model + prototypeReuseIdentifier:(NSString *)identifier + view:(UICollectionView *)collectionView; /** * Initialize an instance of FirebaseCollectionViewDataSource that populates a @@ -366,10 +366,10 @@ NS_ASSUME_NONNULL_BEGIN * UICollectionViewCell with a custom model class */ - (instancetype)initWithQuery:(FIRDatabaseQuery *)query - modelClass:(nullable Class)model - cellClass:(nullable Class)cell - cellReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView; + modelClass:(nullable Class)model + cellClass:(nullable Class)cell + cellReuseIdentifier:(NSString *)identifier + view:(UICollectionView *)collectionView; /** * Initialize an instance of FirebaseCollectionViewDataSource that populates a @@ -387,10 +387,10 @@ NS_ASSUME_NONNULL_BEGIN * model class */ - (instancetype)initWithQuery:(FIRDatabaseQuery *)query - modelClass:(nullable Class)model - nibNamed:(NSString *)nibName - cellReuseIdentifier:(NSString *)identifier - view:(UICollectionView *)collectionView; + modelClass:(nullable Class)model + nibNamed:(NSString *)nibName + cellReuseIdentifier:(NSString *)identifier + view:(UICollectionView *)collectionView; /** * This method populates the fields of a UICollectionViewCell or subclass given @@ -400,9 +400,8 @@ NS_ASSUME_NONNULL_BEGIN * subclass) and the * corresponding object to populate the cell with. */ -- (void)populateCellWithBlock: - (void (^)(__kindof UICollectionViewCell *cell, - __kindof NSObject *object))callback; +- (void)populateCellWithBlock:(void (^)(__kindof UICollectionViewCell *cell, + __kindof NSObject *object))callback; @end diff --git a/FirebaseUI/Database/API/FirebaseDataSource.h b/FirebaseUI/Database/API/FirebaseDataSource.h index b91a551674a..944ef977ac4 100644 --- a/FirebaseUI/Database/API/FirebaseDataSource.h +++ b/FirebaseUI/Database/API/FirebaseDataSource.h @@ -35,11 +35,12 @@ @interface FirebaseDataSource : NSObject /** - * The FirebaseArray which backs the instance of the datasource. + * The items in the data source. */ -@property(strong, nonatomic) FirebaseArray *array; +@property (nonatomic, readonly, copy) NSArray *items; -- (instancetype)initWithArray:(FirebaseArray *)array; +- (instancetype)initWithArray:(FirebaseArray *)array NS_DESIGNATED_INITIALIZER; +- (instancetype)init NS_UNAVAILABLE; /** * Pass through of [FirebaseArray count]. diff --git a/FirebaseUI/Database/Implementation/FirebaseArray.m b/FirebaseUI/Database/Implementation/FirebaseArray.m index e566d642f2c..a5fac62abae 100755 --- a/FirebaseUI/Database/Implementation/FirebaseArray.m +++ b/FirebaseUI/Database/Implementation/FirebaseArray.m @@ -61,10 +61,14 @@ - (void)initListeners { [self.snapshots insertObject:snapshot atIndex:index]; - [self.delegate childAdded:snapshot atIndex:index]; + if ([self.delegate respondsToSelector:@selector(array:didAddObject:atIndex:)]) { + [self.delegate array:self didAddObject:snapshot atIndex:index]; + } } withCancelBlock:^(NSError *error) { - [self.delegate canceledWithError:error]; + if ([self.delegate respondsToSelector:@selector(array:queryCancelledWithError:)]) { + [self.delegate array:self queryCancelledWithError:error]; + } }]; [self.query observeEventType:FIRDataEventTypeChildChanged @@ -73,10 +77,14 @@ - (void)initListeners { [self.snapshots replaceObjectAtIndex:index withObject:snapshot]; - [self.delegate childChanged:snapshot atIndex:index]; + if ([self.delegate respondsToSelector:@selector(array:didChangeObject:atIndex:)]) { + [self.delegate array:self didChangeObject:snapshot atIndex:index]; + } } withCancelBlock:^(NSError *error) { - [self.delegate canceledWithError:error]; + if ([self.delegate respondsToSelector:@selector(array:queryCancelledWithError:)]) { + [self.delegate array:self queryCancelledWithError:error]; + } }]; [self.query observeEventType:FIRDataEventTypeChildRemoved @@ -85,10 +93,14 @@ - (void)initListeners { [self.snapshots removeObjectAtIndex:index]; - [self.delegate childRemoved:snapshot atIndex:index]; + if ([self.delegate respondsToSelector:@selector(array:didRemoveObject:atIndex:)]) { + [self.delegate array:self didRemoveObject:snapshot atIndex:index]; + } } withCancelBlock:^(NSError *error) { - [self.delegate canceledWithError:error]; + if ([self.delegate respondsToSelector:@selector(array:queryCancelledWithError:)]) { + [self.delegate array:self queryCancelledWithError:error]; + } }]; [self.query observeEventType:FIRDataEventTypeChildMoved @@ -99,10 +111,14 @@ - (void)initListeners { NSUInteger toIndex = [self indexForKey:previousChildKey] + 1; [self.snapshots insertObject:snapshot atIndex:toIndex]; - [self.delegate childMoved:snapshot fromIndex:fromIndex toIndex:toIndex]; + if ([self.delegate respondsToSelector:@selector(array:didMoveObject:fromIndex:toIndex:)]) { + [self.delegate array:self didMoveObject:snapshot fromIndex:fromIndex toIndex:toIndex]; + } } withCancelBlock:^(NSError *error) { - [self.delegate canceledWithError:error]; + if ([self.delegate respondsToSelector:@selector(array:queryCancelledWithError:)]) { + [self.delegate array:self queryCancelledWithError:error]; + } }]; } @@ -128,6 +144,10 @@ - (NSUInteger)indexForKey:(NSString *)key { #pragma mark - #pragma mark Public API methods +- (NSArray *)items { + return [self.snapshots copy]; +} + - (NSUInteger)count { return [self.snapshots count]; } diff --git a/FirebaseUI/Database/Implementation/FirebaseCollectionViewDataSource.m b/FirebaseUI/Database/Implementation/FirebaseCollectionViewDataSource.m index 3b64ab41de9..a61230a56c2 100644 --- a/FirebaseUI/Database/Implementation/FirebaseCollectionViewDataSource.m +++ b/FirebaseUI/Database/Implementation/FirebaseCollectionViewDataSource.m @@ -265,7 +265,7 @@ - (nonnull UICollectionViewCell *)collectionView:(nonnull UICollectionView *)col id cell = [self.collectionView dequeueReusableCellWithReuseIdentifier:self.reuseIdentifier forIndexPath:indexPath]; - FIRDataSnapshot *snap = [self.array objectAtIndex:indexPath.row]; + FIRDataSnapshot *snap = [self.items objectAtIndex:indexPath.row]; if (![self.modelClass isSubclassOfClass:[FIRDataSnapshot class]]) { id model = [[self.modelClass alloc] init]; // TODO: replace setValuesForKeysWithDictionary with client API @@ -285,7 +285,7 @@ - (NSInteger)numberOfSectionsInCollectionView:(nonnull UICollectionView *)collec - (NSInteger)collectionView:(nonnull UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { - return [self.array count]; + return self.items.count; } - (void)populateCellWithBlock: diff --git a/FirebaseUI/Database/Implementation/FirebaseDataSource.m b/FirebaseUI/Database/Implementation/FirebaseDataSource.m index cc3547ee786..5d20a22670f 100644 --- a/FirebaseUI/Database/Implementation/FirebaseDataSource.m +++ b/FirebaseUI/Database/Implementation/FirebaseDataSource.m @@ -21,7 +21,14 @@ #import "FirebaseDataSource.h" @interface FirebaseDataSource () -@property(copy, nonatomic) void (^cancelBlock)(NSError *); + +@property(copy, nonatomic, nonnull) void (^cancelBlock)(NSError *); + +/** + * The FirebaseArray which backs the instance of the datasource. + */ +@property(strong, nonatomic, nonnull) FirebaseArray *array; + @end @implementation FirebaseDataSource @@ -32,8 +39,8 @@ @implementation FirebaseDataSource - (instancetype)initWithArray:(FirebaseArray *)array { self = [super init]; if (self) { - self.array = array; - self.array.delegate = self; + _array = array; + _array.delegate = self; } return self; } @@ -42,7 +49,7 @@ - (instancetype)initWithArray:(FirebaseArray *)array { #pragma mark API methods - (NSUInteger)count { - return [self.array count]; + return self.array.count; } - (id)objectAtIndex:(NSUInteger)index { diff --git a/FirebaseUI/Database/Implementation/FirebaseTableViewDataSource.m b/FirebaseUI/Database/Implementation/FirebaseTableViewDataSource.m index 2dd65cd4c96..65b269817da 100644 --- a/FirebaseUI/Database/Implementation/FirebaseTableViewDataSource.m +++ b/FirebaseUI/Database/Implementation/FirebaseTableViewDataSource.m @@ -274,7 +274,7 @@ - (id)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)in id cell = [self.tableView dequeueReusableCellWithIdentifier:self.reuseIdentifier forIndexPath:indexPath]; - FIRDataSnapshot *snap = [self.array objectAtIndex:indexPath.row]; + FIRDataSnapshot *snap = [self.items objectAtIndex:indexPath.row]; if (![self.modelClass isSubclassOfClass:[FIRDataSnapshot class]]) { id model = [[self.modelClass alloc] init]; // TODO: replace setValuesForKeysWithDictionary with client API @@ -289,7 +289,7 @@ - (id)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)in } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { - return [self.array count]; + return self.items.count; } - (void)populateCellWithBlock:(void (^)(__kindof UITableViewCell *cell, From 0617d4206682d0aec0a87b3b65cd3e877d0d0fab Mon Sep 17 00:00:00 2001 From: Morgan Chen Date: Thu, 4 Aug 2016 12:12:03 -0700 Subject: [PATCH 04/28] deintegrate pods --- FirebaseUI.xcodeproj/project.pbxproj | 58 ---------------------------- 1 file changed, 58 deletions(-) diff --git a/FirebaseUI.xcodeproj/project.pbxproj b/FirebaseUI.xcodeproj/project.pbxproj index 92313fc7150..c7863202171 100644 --- a/FirebaseUI.xcodeproj/project.pbxproj +++ b/FirebaseUI.xcodeproj/project.pbxproj @@ -7,7 +7,6 @@ objects = { /* Begin PBXBuildFile section */ - 062B15392FA061BBBEC6CDC4 /* libPods-Facebook.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FE33CCA3B13AA53771BEC0B4 /* libPods-Facebook.a */; }; 1073FE661CE509EC00E2F73F /* facebook.png in Resources */ = {isa = PBXBuildFile; fileRef = 1073FE1B1CE509EC00E2F73F /* facebook.png */; }; 1073FE671CE509EC00E2F73F /* facebook@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 1073FE1C1CE509EC00E2F73F /* facebook@2x.png */; }; 1073FE681CE509EC00E2F73F /* facebook@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 1073FE1D1CE509EC00E2F73F /* facebook@3x.png */; }; @@ -79,9 +78,6 @@ 1073FEB61CE50A8F00E2F73F /* FirebaseCollectionViewDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 1073FEAD1CE50A8F00E2F73F /* FirebaseCollectionViewDataSource.m */; }; 1073FEB71CE50A8F00E2F73F /* FirebaseDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 1073FEAE1CE50A8F00E2F73F /* FirebaseDataSource.m */; }; 1073FEB81CE50A8F00E2F73F /* FirebaseTableViewDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 1073FEAF1CE50A8F00E2F73F /* FirebaseTableViewDataSource.m */; }; - 79F1B3CFC3F6E157C28C30F5 /* libPods-Auth.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2F28F3BD9C664DEB963595FF /* libPods-Auth.a */; }; - 8D7710365523A745DAA1321E /* libPods-FirebaseUI.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 275B4831F13A9ADD39B47692 /* libPods-FirebaseUI.a */; }; - A3737316F1D0A028E08E9183 /* libPods-Database.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E7EBD66D7AB946A019E62B7F /* libPods-Database.a */; }; D8666CB71CEAFCD5002B7C26 /* FirebaseArray.m in Sources */ = {isa = PBXBuildFile; fileRef = 1073FEAC1CE50A8F00E2F73F /* FirebaseArray.m */; }; D8666CB81CEAFCD5002B7C26 /* FirebaseCollectionViewDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 1073FEAD1CE50A8F00E2F73F /* FirebaseCollectionViewDataSource.m */; }; D8666CB91CEAFCD5002B7C26 /* FirebaseDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 1073FEAE1CE50A8F00E2F73F /* FirebaseDataSource.m */; }; @@ -172,7 +168,6 @@ D8666D601CEBFB5C002B7C26 /* FirebaseDatabaseUI.h in Headers */ = {isa = PBXBuildFile; fileRef = D8666D5E1CEBFB5C002B7C26 /* FirebaseDatabaseUI.h */; }; D8B6ACE51B58383C005CDDB2 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D8C579BB1B5837DF00899F86 /* UIKit.framework */; }; D8B6ACE71B583877005CDDB2 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D8B6ACE61B583877005CDDB2 /* Foundation.framework */; }; - F6761ADEA0F0FE70AC2B8134 /* libPods-Google.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 40CC80AD6E673BED46049F08 /* libPods-Google.a */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -242,7 +237,6 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 0A1917FE3607B78B018B843D /* Pods-Auth.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Auth.release.xcconfig"; path = "Pods/Target Support Files/Pods-Auth/Pods-Auth.release.xcconfig"; sourceTree = ""; }; 1073FE1B1CE509EC00E2F73F /* facebook.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = facebook.png; sourceTree = ""; }; 1073FE1C1CE509EC00E2F73F /* facebook@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "facebook@2x.png"; sourceTree = ""; }; 1073FE1D1CE509EC00E2F73F /* facebook@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "facebook@3x.png"; sourceTree = ""; }; @@ -314,18 +308,6 @@ 1073FEAD1CE50A8F00E2F73F /* FirebaseCollectionViewDataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = FirebaseCollectionViewDataSource.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 1073FEAE1CE50A8F00E2F73F /* FirebaseDataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FirebaseDataSource.m; sourceTree = ""; }; 1073FEAF1CE50A8F00E2F73F /* FirebaseTableViewDataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = FirebaseTableViewDataSource.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; - 275B4831F13A9ADD39B47692 /* libPods-FirebaseUI.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-FirebaseUI.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - 2F28F3BD9C664DEB963595FF /* libPods-Auth.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Auth.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - 38A0F57C03EF230E5A720BD1 /* Pods-FirebaseUI.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FirebaseUI.release.xcconfig"; path = "Pods/Target Support Files/Pods-FirebaseUI/Pods-FirebaseUI.release.xcconfig"; sourceTree = ""; }; - 40CC80AD6E673BED46049F08 /* libPods-Google.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Google.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - 51FE96CCEB38B9896FA8763F /* Pods-Facebook.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Facebook.release.xcconfig"; path = "Pods/Target Support Files/Pods-Facebook/Pods-Facebook.release.xcconfig"; sourceTree = ""; }; - 6A47DCC5F13C82AD936429CD /* Pods-Facebook.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Facebook.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Facebook/Pods-Facebook.debug.xcconfig"; sourceTree = ""; }; - 9DC5493B51C2AA187A0CADC3 /* Pods-Auth.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Auth.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Auth/Pods-Auth.debug.xcconfig"; sourceTree = ""; }; - A19CDD03BA9195E469EC5BAB /* Pods-Google.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Google.release.xcconfig"; path = "Pods/Target Support Files/Pods-Google/Pods-Google.release.xcconfig"; sourceTree = ""; }; - A82808FA5C9B636BDCD554A1 /* Pods-Database.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Database.release.xcconfig"; path = "Pods/Target Support Files/Pods-Database/Pods-Database.release.xcconfig"; sourceTree = ""; }; - B06216F85B72D25E7A394865 /* Pods-Database.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Database.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Database/Pods-Database.debug.xcconfig"; sourceTree = ""; }; - D6A4679357D8650D724CF886 /* Pods-Google.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Google.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Google/Pods-Google.debug.xcconfig"; sourceTree = ""; }; - D8199F2217B396C2D50E9224 /* Pods-FirebaseUI.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FirebaseUI.debug.xcconfig"; path = "Pods/Target Support Files/Pods-FirebaseUI/Pods-FirebaseUI.debug.xcconfig"; sourceTree = ""; }; D8666CAE1CEAFC93002B7C26 /* libDatabase.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libDatabase.a; sourceTree = BUILT_PRODUCTS_DIR; }; D8666CC61CEAFD40002B7C26 /* libAuth.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libAuth.a; sourceTree = BUILT_PRODUCTS_DIR; }; D8666CFE1CEAFDDB002B7C26 /* libPods-FirebaseUI.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libPods-FirebaseUI.a"; path = "../../../Library/Developer/Xcode/DerivedData/FirebaseUI-anhduclyafjbjahglzespojfewme/Build/Products/Debug-iphonesimulator/libPods-FirebaseUI.a"; sourceTree = ""; }; @@ -353,8 +335,6 @@ D8B6ACE61B583877005CDDB2 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; D8C579A61B57349000899F86 /* libFirebaseUI.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libFirebaseUI.a; sourceTree = BUILT_PRODUCTS_DIR; }; D8C579BB1B5837DF00899F86 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; - E7EBD66D7AB946A019E62B7F /* libPods-Database.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Database.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - FE33CCA3B13AA53771BEC0B4 /* libPods-Facebook.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Facebook.a"; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -363,7 +343,6 @@ buildActionMask = 2147483647; files = ( D8666D331CEB0187002B7C26 /* FirebaseDatabase.framework in Frameworks */, - A3737316F1D0A028E08E9183 /* libPods-Database.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -384,7 +363,6 @@ D8666D391CEB0210002B7C26 /* Security.framework in Frameworks */, D8666D371CEB01F0002B7C26 /* FirebaseAnalytics.framework in Frameworks */, D8666D351CEB01E2002B7C26 /* FirebaseAuth.framework in Frameworks */, - 79F1B3CFC3F6E157C28C30F5 /* libPods-Auth.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -392,7 +370,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 062B15392FA061BBBEC6CDC4 /* libPods-Facebook.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -401,7 +378,6 @@ buildActionMask = 2147483647; files = ( D8666D591CEB03BA002B7C26 /* GoogleSignIn.framework in Frameworks */, - F6761ADEA0F0FE70AC2B8134 /* libPods-Google.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -411,30 +387,12 @@ files = ( D8B6ACE51B58383C005CDDB2 /* UIKit.framework in Frameworks */, D8B6ACE71B583877005CDDB2 /* Foundation.framework in Frameworks */, - 8D7710365523A745DAA1321E /* libPods-FirebaseUI.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 0A468E95D1E218FE7DFFCF11 /* Pods */ = { - isa = PBXGroup; - children = ( - D8199F2217B396C2D50E9224 /* Pods-FirebaseUI.debug.xcconfig */, - 38A0F57C03EF230E5A720BD1 /* Pods-FirebaseUI.release.xcconfig */, - 9DC5493B51C2AA187A0CADC3 /* Pods-Auth.debug.xcconfig */, - 0A1917FE3607B78B018B843D /* Pods-Auth.release.xcconfig */, - B06216F85B72D25E7A394865 /* Pods-Database.debug.xcconfig */, - A82808FA5C9B636BDCD554A1 /* Pods-Database.release.xcconfig */, - 6A47DCC5F13C82AD936429CD /* Pods-Facebook.debug.xcconfig */, - 51FE96CCEB38B9896FA8763F /* Pods-Facebook.release.xcconfig */, - D6A4679357D8650D724CF886 /* Pods-Google.debug.xcconfig */, - A19CDD03BA9195E469EC5BAB /* Pods-Google.release.xcconfig */, - ); - name = Pods; - sourceTree = ""; - }; 1073FE171CE509EC00E2F73F /* Auth */ = { isa = PBXGroup; children = ( @@ -665,11 +623,6 @@ D8666CFE1CEAFDDB002B7C26 /* libPods-FirebaseUI.a */, D8B6ACE61B583877005CDDB2 /* Foundation.framework */, D8C579BB1B5837DF00899F86 /* UIKit.framework */, - 275B4831F13A9ADD39B47692 /* libPods-FirebaseUI.a */, - 2F28F3BD9C664DEB963595FF /* libPods-Auth.a */, - E7EBD66D7AB946A019E62B7F /* libPods-Database.a */, - FE33CCA3B13AA53771BEC0B4 /* libPods-Facebook.a */, - 40CC80AD6E673BED46049F08 /* libPods-Google.a */, ); name = Frameworks; sourceTree = ""; @@ -680,7 +633,6 @@ D8B6ACE81B5839A5005CDDB2 /* Frameworks */, D8C579A81B57349000899F86 /* FirebaseUI */, D8C579A71B57349000899F86 /* Products */, - 0A468E95D1E218FE7DFFCF11 /* Pods */, ); sourceTree = ""; }; @@ -1309,7 +1261,6 @@ /* Begin XCBuildConfiguration section */ D8666CB41CEAFC93002B7C26 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = B06216F85B72D25E7A394865 /* Pods-Database.debug.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -1333,7 +1284,6 @@ }; D8666CB51CEAFC93002B7C26 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = A82808FA5C9B636BDCD554A1 /* Pods-Database.release.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -1353,7 +1303,6 @@ }; D8666CCD1CEAFD40002B7C26 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 9DC5493B51C2AA187A0CADC3 /* Pods-Auth.debug.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -1383,7 +1332,6 @@ }; D8666CCE1CEAFD40002B7C26 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 0A1917FE3607B78B018B843D /* Pods-Auth.release.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -1409,7 +1357,6 @@ }; D8666D0D1CEAFF29002B7C26 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 6A47DCC5F13C82AD936429CD /* Pods-Facebook.debug.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -1429,7 +1376,6 @@ }; D8666D0E1CEAFF29002B7C26 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 51FE96CCEB38B9896FA8763F /* Pods-Facebook.release.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -1445,7 +1391,6 @@ }; D8666D1B1CEAFF41002B7C26 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = D6A4679357D8650D724CF886 /* Pods-Google.debug.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -1469,7 +1414,6 @@ }; D8666D1C1CEAFF41002B7C26 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = A19CDD03BA9195E469EC5BAB /* Pods-Google.release.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -1568,7 +1512,6 @@ }; D8C579B01B57349000899F86 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = D8199F2217B396C2D50E9224 /* Pods-FirebaseUI.debug.xcconfig */; buildSettings = { CLANG_MODULES_AUTOLINK = YES; DEAD_CODE_STRIPPING = NO; @@ -1611,7 +1554,6 @@ }; D8C579B11B57349000899F86 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 38A0F57C03EF230E5A720BD1 /* Pods-FirebaseUI.release.xcconfig */; buildSettings = { CLANG_MODULES_AUTOLINK = YES; DEAD_CODE_STRIPPING = NO; From 8a7348585718cbd9b0fde6f2ce68afc9ba704139 Mon Sep 17 00:00:00 2001 From: Morgan Chen Date: Thu, 4 Aug 2016 15:48:38 -0700 Subject: [PATCH 05/28] partially add unit tests --- FirebaseUI.xcodeproj/project.pbxproj | 240 +++++++++++++++++++++++- FirebaseUI/Database/API/FirebaseArray.h | 20 +- FirebaseUITests/FirebaseArrayTest.m | 46 +++++ FirebaseUITests/Info.plist | 24 +++ Podfile | 10 + 5 files changed, 333 insertions(+), 7 deletions(-) create mode 100644 FirebaseUITests/FirebaseArrayTest.m create mode 100644 FirebaseUITests/Info.plist diff --git a/FirebaseUI.xcodeproj/project.pbxproj b/FirebaseUI.xcodeproj/project.pbxproj index c7863202171..f135898fd02 100644 --- a/FirebaseUI.xcodeproj/project.pbxproj +++ b/FirebaseUI.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 47; objects = { /* Begin PBXBuildFile section */ @@ -78,6 +78,13 @@ 1073FEB61CE50A8F00E2F73F /* FirebaseCollectionViewDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 1073FEAD1CE50A8F00E2F73F /* FirebaseCollectionViewDataSource.m */; }; 1073FEB71CE50A8F00E2F73F /* FirebaseDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 1073FEAE1CE50A8F00E2F73F /* FirebaseDataSource.m */; }; 1073FEB81CE50A8F00E2F73F /* FirebaseTableViewDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 1073FEAF1CE50A8F00E2F73F /* FirebaseTableViewDataSource.m */; }; + 44710093677365F50C912171 /* libPods-Database.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 528E8111C0AB5BA29070E357 /* libPods-Database.a */; }; + 811145D773C01673923850F9 /* libPods-Google.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E2AFB1D10DC084378036DA12 /* libPods-Google.a */; }; + 8621C9557B0F42B90A867731 /* libPods-FirebaseUI.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E25E2F8253FA11A3E072D265 /* libPods-FirebaseUI.a */; }; + 8D2CB5E21D53F5AE0097FEEB /* libFirebaseUI.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D8C579A61B57349000899F86 /* libFirebaseUI.a */; }; + 8D2CB5E91D53F5C50097FEEB /* FirebaseArrayTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D2CB5E81D53F5C50097FEEB /* FirebaseArrayTest.m */; }; + 962E1417A825A57ED7034636 /* libPods-Facebook.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 56CCA3CB9295B6E71208403F /* libPods-Facebook.a */; }; + D0A910B983E334AD9CFE58E6 /* libPods-FirebaseUITests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 015DB5FB0D29CB8E1812F81E /* libPods-FirebaseUITests.a */; }; D8666CB71CEAFCD5002B7C26 /* FirebaseArray.m in Sources */ = {isa = PBXBuildFile; fileRef = 1073FEAC1CE50A8F00E2F73F /* FirebaseArray.m */; }; D8666CB81CEAFCD5002B7C26 /* FirebaseCollectionViewDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 1073FEAD1CE50A8F00E2F73F /* FirebaseCollectionViewDataSource.m */; }; D8666CB91CEAFCD5002B7C26 /* FirebaseDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 1073FEAE1CE50A8F00E2F73F /* FirebaseDataSource.m */; }; @@ -168,9 +175,17 @@ D8666D601CEBFB5C002B7C26 /* FirebaseDatabaseUI.h in Headers */ = {isa = PBXBuildFile; fileRef = D8666D5E1CEBFB5C002B7C26 /* FirebaseDatabaseUI.h */; }; D8B6ACE51B58383C005CDDB2 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D8C579BB1B5837DF00899F86 /* UIKit.framework */; }; D8B6ACE71B583877005CDDB2 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D8B6ACE61B583877005CDDB2 /* Foundation.framework */; }; + EF7744239E9F01AC07019DFD /* libPods-Auth.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 21FD6B795A82BA8A66795B8C /* libPods-Auth.a */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ + 8D2CB5E31D53F5AE0097FEEB /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D8C5799E1B57349000899F86 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D8C579A51B57349000899F86; + remoteInfo = FirebaseUI; + }; D8666D541CEB036C002B7C26 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = D8C5799E1B57349000899F86 /* Project object */; @@ -237,6 +252,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 015DB5FB0D29CB8E1812F81E /* libPods-FirebaseUITests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-FirebaseUITests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 1073FE1B1CE509EC00E2F73F /* facebook.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = facebook.png; sourceTree = ""; }; 1073FE1C1CE509EC00E2F73F /* facebook@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "facebook@2x.png"; sourceTree = ""; }; 1073FE1D1CE509EC00E2F73F /* facebook@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "facebook@3x.png"; sourceTree = ""; }; @@ -308,6 +324,24 @@ 1073FEAD1CE50A8F00E2F73F /* FirebaseCollectionViewDataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = FirebaseCollectionViewDataSource.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 1073FEAE1CE50A8F00E2F73F /* FirebaseDataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FirebaseDataSource.m; sourceTree = ""; }; 1073FEAF1CE50A8F00E2F73F /* FirebaseTableViewDataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = FirebaseTableViewDataSource.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; + 21FD6B795A82BA8A66795B8C /* libPods-Auth.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Auth.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 22227132D91A7F5C5A9C32B4 /* Pods-Facebook.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Facebook.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Facebook/Pods-Facebook.debug.xcconfig"; sourceTree = ""; }; + 2725F35BC499F7F0DC1A53EB /* Pods-FirebaseUI.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FirebaseUI.release.xcconfig"; path = "Pods/Target Support Files/Pods-FirebaseUI/Pods-FirebaseUI.release.xcconfig"; sourceTree = ""; }; + 2E4A5F1ED2EEA77B2C3C8B66 /* Pods-Auth.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Auth.release.xcconfig"; path = "Pods/Target Support Files/Pods-Auth/Pods-Auth.release.xcconfig"; sourceTree = ""; }; + 2FF74AE4572A156D0798CCAB /* Pods-FirebaseUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FirebaseUITests.release.xcconfig"; path = "Pods/Target Support Files/Pods-FirebaseUITests/Pods-FirebaseUITests.release.xcconfig"; sourceTree = ""; }; + 41B1C7A71057AC541FDDCF31 /* Pods-Database.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Database.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Database/Pods-Database.debug.xcconfig"; sourceTree = ""; }; + 4559C9C8BF02EE692280B11C /* Pods-Database.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Database.release.xcconfig"; path = "Pods/Target Support Files/Pods-Database/Pods-Database.release.xcconfig"; sourceTree = ""; }; + 528E8111C0AB5BA29070E357 /* libPods-Database.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Database.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 558E0266324D3C1E4901FED8 /* Pods-FirebaseUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FirebaseUITests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-FirebaseUITests/Pods-FirebaseUITests.debug.xcconfig"; sourceTree = ""; }; + 56CCA3CB9295B6E71208403F /* libPods-Facebook.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Facebook.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 5B66352410278E1BAAC6553A /* Pods-FirebaseUI.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FirebaseUI.debug.xcconfig"; path = "Pods/Target Support Files/Pods-FirebaseUI/Pods-FirebaseUI.debug.xcconfig"; sourceTree = ""; }; + 62AA11DC2BCAA83554A5CA5F /* Pods-Auth.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Auth.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Auth/Pods-Auth.debug.xcconfig"; sourceTree = ""; }; + 8D2CB5DD1D53F5AE0097FEEB /* FirebaseUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FirebaseUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 8D2CB5E11D53F5AE0097FEEB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 8D2CB5E81D53F5C50097FEEB /* FirebaseArrayTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FirebaseArrayTest.m; sourceTree = ""; }; + 8D3AA95C1D53F9C7006FC9AF /* libPods-FirebaseUI.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libPods-FirebaseUI.a"; path = "../../Library/Developer/Xcode/DerivedData/FirebaseUI-fwcyvciocjlrhqbyjmmybozelsll/Build/Products/Debug-iphonesimulator/libPods-FirebaseUI.a"; sourceTree = ""; }; + B992B1D4DFBAE9C4E3453B15 /* Pods-Google.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Google.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Google/Pods-Google.debug.xcconfig"; sourceTree = ""; }; + D3D8DBF14682CFE73B51B6A5 /* Pods-Google.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Google.release.xcconfig"; path = "Pods/Target Support Files/Pods-Google/Pods-Google.release.xcconfig"; sourceTree = ""; }; D8666CAE1CEAFC93002B7C26 /* libDatabase.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libDatabase.a; sourceTree = BUILT_PRODUCTS_DIR; }; D8666CC61CEAFD40002B7C26 /* libAuth.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libAuth.a; sourceTree = BUILT_PRODUCTS_DIR; }; D8666CFE1CEAFDDB002B7C26 /* libPods-FirebaseUI.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libPods-FirebaseUI.a"; path = "../../../Library/Developer/Xcode/DerivedData/FirebaseUI-anhduclyafjbjahglzespojfewme/Build/Products/Debug-iphonesimulator/libPods-FirebaseUI.a"; sourceTree = ""; }; @@ -335,14 +369,27 @@ D8B6ACE61B583877005CDDB2 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; D8C579A61B57349000899F86 /* libFirebaseUI.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libFirebaseUI.a; sourceTree = BUILT_PRODUCTS_DIR; }; D8C579BB1B5837DF00899F86 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + DF2E6787E92C161FA17FCC8A /* Pods-Facebook.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Facebook.release.xcconfig"; path = "Pods/Target Support Files/Pods-Facebook/Pods-Facebook.release.xcconfig"; sourceTree = ""; }; + E25E2F8253FA11A3E072D265 /* libPods-FirebaseUI.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-FirebaseUI.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + E2AFB1D10DC084378036DA12 /* libPods-Google.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Google.a"; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 8D2CB5DA1D53F5AE0097FEEB /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8D2CB5E21D53F5AE0097FEEB /* libFirebaseUI.a in Frameworks */, + D0A910B983E334AD9CFE58E6 /* libPods-FirebaseUITests.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; D8666CAB1CEAFC93002B7C26 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( D8666D331CEB0187002B7C26 /* FirebaseDatabase.framework in Frameworks */, + 44710093677365F50C912171 /* libPods-Database.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -363,6 +410,7 @@ D8666D391CEB0210002B7C26 /* Security.framework in Frameworks */, D8666D371CEB01F0002B7C26 /* FirebaseAnalytics.framework in Frameworks */, D8666D351CEB01E2002B7C26 /* FirebaseAuth.framework in Frameworks */, + EF7744239E9F01AC07019DFD /* libPods-Auth.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -370,6 +418,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 962E1417A825A57ED7034636 /* libPods-Facebook.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -378,6 +427,7 @@ buildActionMask = 2147483647; files = ( D8666D591CEB03BA002B7C26 /* GoogleSignIn.framework in Frameworks */, + 811145D773C01673923850F9 /* libPods-Google.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -387,6 +437,7 @@ files = ( D8B6ACE51B58383C005CDDB2 /* UIKit.framework in Frameworks */, D8B6ACE71B583877005CDDB2 /* Foundation.framework in Frameworks */, + 8621C9557B0F42B90A867731 /* libPods-FirebaseUI.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -599,9 +650,38 @@ path = Implementation; sourceTree = ""; }; + 7C1F7BF9D46ABA4D64839CBD /* Pods */ = { + isa = PBXGroup; + children = ( + 62AA11DC2BCAA83554A5CA5F /* Pods-Auth.debug.xcconfig */, + 2E4A5F1ED2EEA77B2C3C8B66 /* Pods-Auth.release.xcconfig */, + 41B1C7A71057AC541FDDCF31 /* Pods-Database.debug.xcconfig */, + 4559C9C8BF02EE692280B11C /* Pods-Database.release.xcconfig */, + 22227132D91A7F5C5A9C32B4 /* Pods-Facebook.debug.xcconfig */, + DF2E6787E92C161FA17FCC8A /* Pods-Facebook.release.xcconfig */, + 5B66352410278E1BAAC6553A /* Pods-FirebaseUI.debug.xcconfig */, + 2725F35BC499F7F0DC1A53EB /* Pods-FirebaseUI.release.xcconfig */, + 558E0266324D3C1E4901FED8 /* Pods-FirebaseUITests.debug.xcconfig */, + 2FF74AE4572A156D0798CCAB /* Pods-FirebaseUITests.release.xcconfig */, + B992B1D4DFBAE9C4E3453B15 /* Pods-Google.debug.xcconfig */, + D3D8DBF14682CFE73B51B6A5 /* Pods-Google.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; + 8D2CB5DE1D53F5AE0097FEEB /* FirebaseUITests */ = { + isa = PBXGroup; + children = ( + 8D2CB5E81D53F5C50097FEEB /* FirebaseArrayTest.m */, + 8D2CB5E11D53F5AE0097FEEB /* Info.plist */, + ); + path = FirebaseUITests; + sourceTree = ""; + }; D8B6ACE81B5839A5005CDDB2 /* Frameworks */ = { isa = PBXGroup; children = ( + 8D3AA95C1D53F9C7006FC9AF /* libPods-FirebaseUI.a */, D8666D581CEB03BA002B7C26 /* GoogleSignIn.framework */, D8666D521CEB02A9002B7C26 /* SystemConfiguration.framework */, D8666D501CEB02A4002B7C26 /* StoreKit.framework */, @@ -623,6 +703,12 @@ D8666CFE1CEAFDDB002B7C26 /* libPods-FirebaseUI.a */, D8B6ACE61B583877005CDDB2 /* Foundation.framework */, D8C579BB1B5837DF00899F86 /* UIKit.framework */, + 21FD6B795A82BA8A66795B8C /* libPods-Auth.a */, + 528E8111C0AB5BA29070E357 /* libPods-Database.a */, + 56CCA3CB9295B6E71208403F /* libPods-Facebook.a */, + E25E2F8253FA11A3E072D265 /* libPods-FirebaseUI.a */, + 015DB5FB0D29CB8E1812F81E /* libPods-FirebaseUITests.a */, + E2AFB1D10DC084378036DA12 /* libPods-Google.a */, ); name = Frameworks; sourceTree = ""; @@ -630,9 +716,11 @@ D8C5799D1B57349000899F86 = { isa = PBXGroup; children = ( - D8B6ACE81B5839A5005CDDB2 /* Frameworks */, D8C579A81B57349000899F86 /* FirebaseUI */, + 8D2CB5DE1D53F5AE0097FEEB /* FirebaseUITests */, D8C579A71B57349000899F86 /* Products */, + D8B6ACE81B5839A5005CDDB2 /* Frameworks */, + 7C1F7BF9D46ABA4D64839CBD /* Pods */, ); sourceTree = ""; }; @@ -644,6 +732,7 @@ D8666CC61CEAFD40002B7C26 /* libAuth.a */, D8666D071CEAFF29002B7C26 /* libFacebook.a */, D8666D141CEAFF41002B7C26 /* libGoogle.a */, + 8D2CB5DD1D53F5AE0097FEEB /* FirebaseUITests.xctest */, ); name = Products; sourceTree = ""; @@ -752,6 +841,27 @@ /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ + 8D2CB5DC1D53F5AE0097FEEB /* FirebaseUITests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 8D2CB5E71D53F5AE0097FEEB /* Build configuration list for PBXNativeTarget "FirebaseUITests" */; + buildPhases = ( + 4A531CC030045B93042803FA /* [CP] Check Pods Manifest.lock */, + 8D2CB5D91D53F5AE0097FEEB /* Sources */, + 8D2CB5DA1D53F5AE0097FEEB /* Frameworks */, + 8D2CB5DB1D53F5AE0097FEEB /* Resources */, + B4BB8A5983D129F23E140373 /* [CP] Embed Pods Frameworks */, + CC1F8BDF974CFA17969663CA /* [CP] Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + 8D2CB5E41D53F5AE0097FEEB /* PBXTargetDependency */, + ); + name = FirebaseUITests; + productName = FirebaseUITests; + productReference = 8D2CB5DD1D53F5AE0097FEEB /* FirebaseUITests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; D8666CAD1CEAFC93002B7C26 /* Database */ = { isa = PBXNativeTarget; buildConfigurationList = D8666CB61CEAFC93002B7C26 /* Build configuration list for PBXNativeTarget "Database" */; @@ -868,6 +978,9 @@ LastUpgradeCheck = 0700; ORGANIZATIONNAME = "Firebase, Inc."; TargetAttributes = { + 8D2CB5DC1D53F5AE0097FEEB = { + CreatedOnToolsVersion = 7.3.1; + }; D8666CAD1CEAFC93002B7C26 = { CreatedOnToolsVersion = 7.3.1; }; @@ -886,7 +999,7 @@ }; }; buildConfigurationList = D8C579A11B57349000899F86 /* Build configuration list for PBXProject "FirebaseUI" */; - compatibilityVersion = "Xcode 3.2"; + compatibilityVersion = "Xcode 6.3"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( @@ -902,11 +1015,19 @@ D8666CC51CEAFD40002B7C26 /* Auth */, D8666D061CEAFF29002B7C26 /* Facebook */, D8666D131CEAFF41002B7C26 /* Google */, + 8D2CB5DC1D53F5AE0097FEEB /* FirebaseUITests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 8D2CB5DB1D53F5AE0097FEEB /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; D809A1321BF7F30C000257AA /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -1033,6 +1154,21 @@ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-FirebaseUI/Pods-FirebaseUI-resources.sh\"\n"; showEnvVarsInLog = 0; }; + 4A531CC030045B93042803FA /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; + showEnvVarsInLog = 0; + }; 4F409FB222EDC7574E52A97F /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -1078,6 +1214,36 @@ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Google/Pods-Google-resources.sh\"\n"; showEnvVarsInLog = 0; }; + B4BB8A5983D129F23E140373 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-FirebaseUITests/Pods-FirebaseUITests-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + CC1F8BDF974CFA17969663CA /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-FirebaseUITests/Pods-FirebaseUITests-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; D17D52CDF1B7F0B80C57DD59 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -1141,6 +1307,14 @@ /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 8D2CB5D91D53F5AE0097FEEB /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8D2CB5E91D53F5C50097FEEB /* FirebaseArrayTest.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; D8666CAA1CEAFC93002B7C26 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -1219,6 +1393,11 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ + 8D2CB5E41D53F5AE0097FEEB /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D8C579A51B57349000899F86 /* FirebaseUI */; + targetProxy = 8D2CB5E31D53F5AE0097FEEB /* PBXContainerItemProxy */; + }; D8666D551CEB036C002B7C26 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = D8666CC51CEAFD40002B7C26 /* Auth */; @@ -1259,8 +1438,41 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ + 8D2CB5E51D53F5AE0097FEEB /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 558E0266324D3C1E4901FED8 /* Pods-FirebaseUITests.debug.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + INFOPLIST_FILE = FirebaseUITests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.3; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.firebase.FirebaseUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 8D2CB5E61D53F5AE0097FEEB /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 2FF74AE4572A156D0798CCAB /* Pods-FirebaseUITests.release.xcconfig */; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + INFOPLIST_FILE = FirebaseUITests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.3; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.firebase.FirebaseUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; D8666CB41CEAFC93002B7C26 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 41B1C7A71057AC541FDDCF31 /* Pods-Database.debug.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -1284,6 +1496,7 @@ }; D8666CB51CEAFC93002B7C26 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 4559C9C8BF02EE692280B11C /* Pods-Database.release.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -1303,6 +1516,7 @@ }; D8666CCD1CEAFD40002B7C26 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 62AA11DC2BCAA83554A5CA5F /* Pods-Auth.debug.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -1332,6 +1546,7 @@ }; D8666CCE1CEAFD40002B7C26 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 2E4A5F1ED2EEA77B2C3C8B66 /* Pods-Auth.release.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -1357,6 +1572,7 @@ }; D8666D0D1CEAFF29002B7C26 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 22227132D91A7F5C5A9C32B4 /* Pods-Facebook.debug.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -1376,6 +1592,7 @@ }; D8666D0E1CEAFF29002B7C26 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = DF2E6787E92C161FA17FCC8A /* Pods-Facebook.release.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -1391,6 +1608,7 @@ }; D8666D1B1CEAFF41002B7C26 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = B992B1D4DFBAE9C4E3453B15 /* Pods-Google.debug.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -1414,6 +1632,7 @@ }; D8666D1C1CEAFF41002B7C26 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = D3D8DBF14682CFE73B51B6A5 /* Pods-Google.release.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -1452,6 +1671,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + FRAMEWORK_SEARCH_PATHS = "$(inherited)"; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -1471,6 +1691,7 @@ MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; + TEST_HOST = ""; }; name = Debug; }; @@ -1495,6 +1716,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + FRAMEWORK_SEARCH_PATHS = "$(inherited)"; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -1506,12 +1728,14 @@ IPHONEOS_DEPLOYMENT_TARGET = 9.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; + TEST_HOST = ""; VALIDATE_PRODUCT = YES; }; name = Release; }; D8C579B01B57349000899F86 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 5B66352410278E1BAAC6553A /* Pods-FirebaseUI.debug.xcconfig */; buildSettings = { CLANG_MODULES_AUTOLINK = YES; DEAD_CODE_STRIPPING = NO; @@ -1554,6 +1778,7 @@ }; D8C579B11B57349000899F86 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 2725F35BC499F7F0DC1A53EB /* Pods-FirebaseUI.release.xcconfig */; buildSettings = { CLANG_MODULES_AUTOLINK = YES; DEAD_CODE_STRIPPING = NO; @@ -1596,6 +1821,15 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 8D2CB5E71D53F5AE0097FEEB /* Build configuration list for PBXNativeTarget "FirebaseUITests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8D2CB5E51D53F5AE0097FEEB /* Debug */, + 8D2CB5E61D53F5AE0097FEEB /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; D8666CB61CEAFC93002B7C26 /* Build configuration list for PBXNativeTarget "Database" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/FirebaseUI/Database/API/FirebaseArray.h b/FirebaseUI/Database/API/FirebaseArray.h index 4ea05da3386..8b3d9ac369f 100644 --- a/FirebaseUI/Database/API/FirebaseArray.h +++ b/FirebaseUI/Database/API/FirebaseArray.h @@ -18,15 +18,27 @@ // clang-format on -#import +@import Firebase; #import "FirebaseArrayDelegate.h" NS_ASSUME_NONNULL_BEGIN -@class FIRDatabaseQuery; -@class FIRDatabaseReference; -@class FIRDataSnapshot; +@protocol FIRDataObservable +@required + +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock:(void (^)(FIRDataSnapshot *snapshot, NSString *__nullable prevKey))block + withCancelBlock:(nullable void (^)(NSError* error))cancelBlock; + +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + withBlock:(void (^)(FIRDataSnapshot *snapshot))block + withCancelBlock:(nullable void (^)(NSError* error))cancelBlock; + +@end + +@interface FIRDatabaseQuery (FIRDataObservable) +@end /** * FirebaseArray provides an array structure that is synchronized with a Firebase reference or diff --git a/FirebaseUITests/FirebaseArrayTest.m b/FirebaseUITests/FirebaseArrayTest.m new file mode 100644 index 00000000000..bcda07bdad9 --- /dev/null +++ b/FirebaseUITests/FirebaseArrayTest.m @@ -0,0 +1,46 @@ +// clang-format off + +// +// Copyright (c) 2016 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// clang-format on + +@import XCTest; + +#import "FirebaseArray.h" + +@interface FirebaseArrayTest : XCTestCase + +@property (nonatomic, nullable) FirebaseArray *fbarray; + +@end + +@implementation FirebaseArrayTest + +- (void)setUp { + [super setUp]; + +} + +- (void)tearDown { + [super tearDown]; +} + +- (void)testExample { + +} + +@end diff --git a/FirebaseUITests/Info.plist b/FirebaseUITests/Info.plist new file mode 100644 index 00000000000..ba72822e872 --- /dev/null +++ b/FirebaseUITests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/Podfile b/Podfile index 7c86cd5b376..3d49c9aa9c2 100644 --- a/Podfile +++ b/Podfile @@ -7,6 +7,15 @@ target 'FirebaseUI' do pod 'Firebase/Auth' pod 'FBSDKLoginKit', '~> 4.0' pod 'GoogleSignIn', '~> 4.0' + + target 'FirebaseUITests' do + inherit! :search_paths + pod 'Firebase' + pod 'Firebase/Database' + pod 'Firebase/Auth' + pod 'FBSDKLoginKit', '~> 4.0' + pod 'GoogleSignIn', '~> 4.0' + end end target 'Database' do @@ -34,3 +43,4 @@ target 'Google' do pod 'Firebase/Auth' pod 'GoogleSignIn', '~> 4.0' end + From 1c39d2efd350a78c153046d1e128cb7a984eff77 Mon Sep 17 00:00:00 2001 From: Morgan Chen Date: Thu, 4 Aug 2016 15:52:30 -0700 Subject: [PATCH 06/28] random file missing from pbxproj --- FirebaseUI.xcodeproj/project.pbxproj | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/FirebaseUI.xcodeproj/project.pbxproj b/FirebaseUI.xcodeproj/project.pbxproj index f135898fd02..c7be7ca256d 100644 --- a/FirebaseUI.xcodeproj/project.pbxproj +++ b/FirebaseUI.xcodeproj/project.pbxproj @@ -83,6 +83,8 @@ 8621C9557B0F42B90A867731 /* libPods-FirebaseUI.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E25E2F8253FA11A3E072D265 /* libPods-FirebaseUI.a */; }; 8D2CB5E21D53F5AE0097FEEB /* libFirebaseUI.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D8C579A61B57349000899F86 /* libFirebaseUI.a */; }; 8D2CB5E91D53F5C50097FEEB /* FirebaseArrayTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D2CB5E81D53F5C50097FEEB /* FirebaseArrayTest.m */; }; + 8DFCD1371D53FE8D00208D7B /* FIRAuthUISignInButton.h in Headers */ = {isa = PBXBuildFile; fileRef = 8DFCD1351D53FE8D00208D7B /* FIRAuthUISignInButton.h */; }; + 8DFCD1381D53FE8D00208D7B /* FIRAuthUISignInButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 8DFCD1361D53FE8D00208D7B /* FIRAuthUISignInButton.m */; }; 962E1417A825A57ED7034636 /* libPods-Facebook.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 56CCA3CB9295B6E71208403F /* libPods-Facebook.a */; }; D0A910B983E334AD9CFE58E6 /* libPods-FirebaseUITests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 015DB5FB0D29CB8E1812F81E /* libPods-FirebaseUITests.a */; }; D8666CB71CEAFCD5002B7C26 /* FirebaseArray.m in Sources */ = {isa = PBXBuildFile; fileRef = 1073FEAC1CE50A8F00E2F73F /* FirebaseArray.m */; }; @@ -340,6 +342,8 @@ 8D2CB5E11D53F5AE0097FEEB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 8D2CB5E81D53F5C50097FEEB /* FirebaseArrayTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FirebaseArrayTest.m; sourceTree = ""; }; 8D3AA95C1D53F9C7006FC9AF /* libPods-FirebaseUI.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libPods-FirebaseUI.a"; path = "../../Library/Developer/Xcode/DerivedData/FirebaseUI-fwcyvciocjlrhqbyjmmybozelsll/Build/Products/Debug-iphonesimulator/libPods-FirebaseUI.a"; sourceTree = ""; }; + 8DFCD1351D53FE8D00208D7B /* FIRAuthUISignInButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FIRAuthUISignInButton.h; sourceTree = ""; }; + 8DFCD1361D53FE8D00208D7B /* FIRAuthUISignInButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRAuthUISignInButton.m; sourceTree = ""; }; B992B1D4DFBAE9C4E3453B15 /* Pods-Google.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Google.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Google/Pods-Google.debug.xcconfig"; sourceTree = ""; }; D3D8DBF14682CFE73B51B6A5 /* Pods-Google.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Google.release.xcconfig"; path = "Pods/Target Support Files/Pods-Google/Pods-Google.release.xcconfig"; sourceTree = ""; }; D8666CAE1CEAFC93002B7C26 /* libDatabase.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libDatabase.a; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -580,6 +584,8 @@ 1073FE471CE509EC00E2F73F /* FIRAuthUIErrors.m */, 1073FE481CE509EC00E2F73F /* FIRAuthUIErrorUtils.h */, 1073FE491CE509EC00E2F73F /* FIRAuthUIErrorUtils.m */, + 8DFCD1351D53FE8D00208D7B /* FIRAuthUISignInButton.h */, + 8DFCD1361D53FE8D00208D7B /* FIRAuthUISignInButton.m */, 1073FE4A1CE509EC00E2F73F /* FIRAuthUIStrings.h */, 1073FE4B1CE509EC00E2F73F /* FIRAuthUIStrings.m */, 1073FE4C1CE509EC00E2F73F /* FIRAuthUITableHeaderView.h */, @@ -822,6 +828,7 @@ 1073FE971CE509EC00E2F73F /* FIRPasswordRecoveryViewController.h in Headers */, 1073FE741CE509EC00E2F73F /* FIRGoogleAuthUI.h in Headers */, 1073FE8E1CE509EC00E2F73F /* FIRAuthUITableViewCell.h in Headers */, + 8DFCD1371D53FE8D00208D7B /* FIRAuthUISignInButton.h in Headers */, 1073FE7D1CE509EC00E2F73F /* FIRAuthPickerViewController.h in Headers */, 1073FEB21CE50A8F00E2F73F /* FirebaseCollectionViewDataSource.h in Headers */, 1073FE881CE509EC00E2F73F /* FIRAuthUIErrorUtils.h in Headers */, @@ -1371,6 +1378,7 @@ 1073FE8F1CE509EC00E2F73F /* FIRAuthUITableViewCell.m in Sources */, 1073FE981CE509EC00E2F73F /* FIRPasswordRecoveryViewController.m in Sources */, 1073FEA11CE509EC00E2F73F /* FIRPasswordVerificationViewController.m in Sources */, + 8DFCD1381D53FE8D00208D7B /* FIRAuthUISignInButton.m in Sources */, 1073FE951CE509EC00E2F73F /* FIREmailEntryViewController.m in Sources */, 1073FEB71CE50A8F00E2F73F /* FirebaseDataSource.m in Sources */, 1073FE6B1CE509EC00E2F73F /* FIRFacebookAuthUI.m in Sources */, From 88709f8c0d594ec049ceec372ffc8c1f3f021619 Mon Sep 17 00:00:00 2001 From: Morgan Chen Date: Thu, 4 Aug 2016 17:22:19 -0700 Subject: [PATCH 07/28] begin writing tests --- FirebaseUI/Database/API/FirebaseArray.h | 27 +--- .../Database/Implementation/FirebaseArray.m | 37 ++--- FirebaseUITests/FirebaseArrayTest.m | 143 +++++++++++++++++- 3 files changed, 167 insertions(+), 40 deletions(-) diff --git a/FirebaseUI/Database/API/FirebaseArray.h b/FirebaseUI/Database/API/FirebaseArray.h index 8b3d9ac369f..d165211f2eb 100644 --- a/FirebaseUI/Database/API/FirebaseArray.h +++ b/FirebaseUI/Database/API/FirebaseArray.h @@ -31,9 +31,7 @@ NS_ASSUME_NONNULL_BEGIN andPreviousSiblingKeyWithBlock:(void (^)(FIRDataSnapshot *snapshot, NSString *__nullable prevKey))block withCancelBlock:(nullable void (^)(NSError* error))cancelBlock; -- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType - withBlock:(void (^)(FIRDataSnapshot *snapshot))block - withCancelBlock:(nullable void (^)(NSError* error))cancelBlock; +- (void)removeAllObservers; // TODO: allow removing observers by handle @end @@ -56,12 +54,7 @@ NS_ASSUME_NONNULL_BEGIN /** * The query on a Firebase reference that provides data to populate the instance of FirebaseArray. */ -@property(strong, nonatomic) FIRDatabaseQuery *query; - -/** - * The delegate object that array changes are surfaced to. - */ -@property(strong, nonatomic) NSMutableArray * snapshots; +@property(strong, nonatomic) id query; /** * The number of objects in the FirebaseArray. @@ -77,18 +70,14 @@ NS_ASSUME_NONNULL_BEGIN #pragma mark Initializer methods /** - * Intitalizes FirebaseArray with a standard Firebase reference. - * @param ref The Firebase reference which provides data to FirebaseArray - * @return The instance of FirebaseArray + * Initalizes FirebaseArray with a Firebase query (FIRDatabaseQuery) or database reference + * (FIRDatabaseReference). + * @param query A query or Firebase database reference + * @return A FirebaseArray instance */ -- (instancetype)initWithRef:(FIRDatabaseReference *)ref; +- (instancetype)initWithQuery:(id)query NS_DESIGNATED_INITIALIZER; -/** - * Intitalizes FirebaseArray with a Firebase query (FIRDatabaseQuery). - * @param query A query on a Firebase reference which provides filtered data to FirebaseArray - * @return The instance of FirebaseArray - */ -- (instancetype)initWithQuery:(FIRDatabaseQuery *)query; +- (instancetype)init NS_UNAVAILABLE; #pragma mark - #pragma mark Public API methods diff --git a/FirebaseUI/Database/Implementation/FirebaseArray.m b/FirebaseUI/Database/Implementation/FirebaseArray.m index a5fac62abae..65004f79174 100755 --- a/FirebaseUI/Database/Implementation/FirebaseArray.m +++ b/FirebaseUI/Database/Implementation/FirebaseArray.m @@ -20,6 +20,15 @@ #import "FirebaseArray.h" +@interface FirebaseArray () + +/** + * The delegate object that array changes are surfaced to. + */ +@property(strong, nonatomic) NSMutableArray * snapshots; + +@end + @import FirebaseDatabase; @implementation FirebaseArray @@ -27,15 +36,12 @@ @implementation FirebaseArray #pragma mark - #pragma mark Initializer methods -- (instancetype)initWithRef:(FIRDatabaseReference *)ref { - return [self initWithQuery:ref]; -} - - (instancetype)initWithQuery:(FIRDatabaseQuery *)query { + NSParameterAssert(query != nil); self = [super init]; if (self) { - self.snapshots = [NSMutableArray array]; - self.query = query; + _snapshots = [NSMutableArray array]; + _query = query; [self initListeners]; } @@ -57,7 +63,10 @@ - (void)dealloc { - (void)initListeners { [self.query observeEventType:FIRDataEventTypeChildAdded andPreviousSiblingKeyWithBlock:^(FIRDataSnapshot *snapshot, NSString *previousChildKey) { - NSUInteger index = [self indexForKey:previousChildKey] + 1; + NSUInteger index = 0; + if (previousChildKey != nil) { + index = [self indexForKey:previousChildKey] + 1; + } [self.snapshots insertObject:snapshot atIndex:index]; @@ -88,7 +97,7 @@ - (void)initListeners { }]; [self.query observeEventType:FIRDataEventTypeChildRemoved - withBlock:^(FIRDataSnapshot *snapshot) { + andPreviousSiblingKeyWithBlock:^(FIRDataSnapshot *snapshot, NSString *previousSiblingKey) { NSUInteger index = [self indexForKey:snapshot.key]; [self.snapshots removeObjectAtIndex:index]; @@ -123,22 +132,14 @@ - (void)initListeners { } - (NSUInteger)indexForKey:(NSString *)key { - if (!key) return -1; + NSParameterAssert(key != nil); for (NSUInteger index = 0; index < [self.snapshots count]; index++) { if ([key isEqualToString:[(FIRDataSnapshot *)[self.snapshots objectAtIndex:index] key]]) { return index; } } - - NSString *errorReason = - [NSString stringWithFormat:@"Key \"%@\" not found in FirebaseArray %@", key, self.snapshots]; - @throw [NSException exceptionWithName:@"FirebaseArrayKeyNotFoundException" - reason:errorReason - userInfo:@{ - @"Key" : key, - @"Array" : self.snapshots - }]; + return NSNotFound; } #pragma mark - diff --git a/FirebaseUITests/FirebaseArrayTest.m b/FirebaseUITests/FirebaseArrayTest.m index bcda07bdad9..d2598267df6 100644 --- a/FirebaseUITests/FirebaseArrayTest.m +++ b/FirebaseUITests/FirebaseArrayTest.m @@ -22,9 +22,95 @@ #import "FirebaseArray.h" +// Dumb object holding a pair of blocks and a data event type. +@interface FUIDataEventHandler: NSObject +@property (nonatomic, assign) FIRDataEventType event; +@property (nonatomic, copy, nonnull) void (^success)(FIRDataSnapshot * _Nonnull, NSString *_Nullable); +@property (nonatomic, copy, nonnull) void (^cancelled)(NSError *_Nonnull); +@end +@implementation FUIDataEventHandler +@end + +// A dummy observable so we can test this without relying on an internet connection. +@interface FUITestObservable: NSObject + +// Map of handles to observers. +@property (nonatomic, readonly) NSMutableDictionary *observers; + +// Incremented to generate unique handles. +@property (nonatomic, readonly, assign) FIRDatabaseHandle current; + +@end + +// Horrible abuse of ObjC type system, since FirebaseArray is unfortunately coupled to +// FIRDataSnapshot +@interface FUIFakeSnapshot: NSObject +@property (nonatomic, assign) NSString *key; +@end +@implementation FUIFakeSnapshot +@end + +@implementation FUITestObservable + +- (instancetype)init { + self = [super init]; + if (self != nil) { + _observers = [NSMutableDictionary dictionary]; + } + return self; +} + +- (void)removeAllObservers { + _observers = [NSMutableDictionary dictionary]; +} + +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock:(void (^)(FIRDataSnapshot * _Nonnull, NSString * _Nullable))block + withCancelBlock:(void (^)(NSError * _Nonnull))cancelBlock { + FUIDataEventHandler *handler = [[FUIDataEventHandler alloc] init]; + handler.event = eventType; + handler.success = block; + handler.cancelled = cancelBlock; + + NSNumber *key = @(self.current); + _current++; + self.observers[key] = handler; + return key.unsignedIntegerValue; +} + +// Sends an event in jankiest possible way +- (void)sendEvent:(FIRDataEventType)event + withObject:(FUIFakeSnapshot *)object + previousKey:(NSString *)string + error:(NSError *)error { + NSArray *allKeys = self.observers.allKeys; + for (NSNumber *key in allKeys) { + FUIDataEventHandler *handler = self.observers[key]; + if (handler.event == event) { + if (error != nil) { handler.cancelled(error); } + else { handler.success((FIRDataSnapshot *)object, string); } + } + } +} + +// Sends a bunch of insertion events with snapshot keys as integer strings (i.e. @"0") of increasing +// order, starting from 0. +- (void)populateWithCount:(NSUInteger)count { + NSString *previous = nil; + for (NSUInteger i = 0; i < count; i++) { + FUIFakeSnapshot *snap = [[FUIFakeSnapshot alloc] init]; + snap.key = @(i).stringValue; + [self sendEvent:FIRDataEventTypeChildAdded withObject:snap previousKey:previous error:nil]; + previous = snap.key; + } +} + +@end + @interface FirebaseArrayTest : XCTestCase -@property (nonatomic, nullable) FirebaseArray *fbarray; +@property (nonatomic, nullable) FUITestObservable *observable; +@property (nonatomic, nullable) FirebaseArray *firebaseArray; @end @@ -32,15 +118,66 @@ @implementation FirebaseArrayTest - (void)setUp { [super setUp]; - + self.observable = [[FUITestObservable alloc] init]; + self.firebaseArray = [[FirebaseArray alloc] initWithQuery:self.observable]; } - (void)tearDown { [super tearDown]; + [self.observable removeAllObservers]; +} + +- (void)testFirebaseArrayCanBeInitialized { + XCTAssertNotNil(self.observable, @"expected FirebaseArray to not be nil when initialized"); +} + +- (void)testEmptyFirebaseArrayUpdatesCountOnInsert { + FUIFakeSnapshot *snap = [[FUIFakeSnapshot alloc] init]; + snap.key = @"snapshot"; + [self.observable sendEvent:FIRDataEventTypeChildAdded + withObject:snap + previousKey:nil + error:nil]; + NSAssert(self.firebaseArray.count == 1, @"expected empty array to contain one item after insert"); } -- (void)testExample { +- (void)testFirebaseArrayCanDeleteOneElementArray { + // Insert a key + FUIFakeSnapshot *snap = [[FUIFakeSnapshot alloc] init]; + snap.key = @"snapshot"; + [self.observable sendEvent:FIRDataEventTypeChildAdded + withObject:snap + previousKey:nil + error:nil]; + + // Delete + [self.observable sendEvent:FIRDataEventTypeChildRemoved + withObject:snap + previousKey:nil + error:nil]; + + XCTAssert(self.firebaseArray.count == 0, + @"expected empty array to still be empty after one insertion and one deletion"); +} + +- (void)testFirebaseArrayCanInsertInMiddle { + // Setup boilerplate + [self.observable populateWithCount:10]; + FUIFakeSnapshot *snap = [[FUIFakeSnapshot alloc] init]; + snap.key = @"5"; + + // This is the actual change being tested + [self.observable sendEvent:FIRDataEventTypeChildAdded withObject:snap previousKey:@"4" error:nil]; + + // Expectation boilerplate + NSArray *items = self.firebaseArray.items; + NSArray *expected = @[@"0", @"1", @"2", @"3", @"4", @"5", @"5", @"6", @"7", @"8", @"9"]; + NSMutableArray *result = [NSMutableArray array]; + for (FUIFakeSnapshot *snapshot in items) { + [result addObject:snapshot.key]; + } + XCTAssert([result isEqual:expected], @"expected firebaseArray contents to equal %@, got %@", expected, [result copy]); } @end From 2efcf35a6f195d2ea1d8b910b8da138f058dc265 Mon Sep 17 00:00:00 2001 From: Morgan Chen Date: Fri, 5 Aug 2016 11:15:28 -0700 Subject: [PATCH 08/28] finish FirebaseArray tests, kind of --- FirebaseUITests/FirebaseArrayTest.m | 234 +++++++++++++++++++++++++--- 1 file changed, 213 insertions(+), 21 deletions(-) diff --git a/FirebaseUITests/FirebaseArrayTest.m b/FirebaseUITests/FirebaseArrayTest.m index d2598267df6..0a04d142c94 100644 --- a/FirebaseUITests/FirebaseArrayTest.m +++ b/FirebaseUITests/FirebaseArrayTest.m @@ -25,7 +25,7 @@ // Dumb object holding a pair of blocks and a data event type. @interface FUIDataEventHandler: NSObject @property (nonatomic, assign) FIRDataEventType event; -@property (nonatomic, copy, nonnull) void (^success)(FIRDataSnapshot * _Nonnull, NSString *_Nullable); +@property (nonatomic, copy, nonnull) void (^success)(FIRDataSnapshot *_Nonnull, NSString *_Nullable); @property (nonatomic, copy, nonnull) void (^cancelled)(NSError *_Nonnull); @end @implementation FUIDataEventHandler @@ -93,24 +93,33 @@ - (void)sendEvent:(FIRDataEventType)event } } -// Sends a bunch of insertion events with snapshot keys as integer strings (i.e. @"0") of increasing -// order, starting from 0. -- (void)populateWithCount:(NSUInteger)count { +// Inserts sequentially with data provided by the `generator` block. +- (void)populateWithCount:(NSUInteger)count generator:(FUIFakeSnapshot *(^)(NSUInteger))generator { NSString *previous = nil; for (NSUInteger i = 0; i < count; i++) { - FUIFakeSnapshot *snap = [[FUIFakeSnapshot alloc] init]; - snap.key = @(i).stringValue; + FUIFakeSnapshot *snap = generator(i); [self sendEvent:FIRDataEventTypeChildAdded withObject:snap previousKey:previous error:nil]; previous = snap.key; } } +// Sends a bunch of insertion events with snapshot keys as integer strings (i.e. @"0") of increasing +// order, starting from 0. +- (void)populateWithCount:(NSUInteger)count { + [self populateWithCount:count generator:^FUIFakeSnapshot *(NSUInteger index) { + FUIFakeSnapshot *snap = [[FUIFakeSnapshot alloc] init]; + snap.key = @(index).stringValue; + return snap; + }]; +} + @end @interface FirebaseArrayTest : XCTestCase @property (nonatomic, nullable) FUITestObservable *observable; @property (nonatomic, nullable) FirebaseArray *firebaseArray; +@property (nonatomic, nullable) FUIFakeSnapshot *snap; @end @@ -118,6 +127,7 @@ @implementation FirebaseArrayTest - (void)setUp { [super setUp]; + self.snap = [[FUIFakeSnapshot alloc] init]; self.observable = [[FUITestObservable alloc] init]; self.firebaseArray = [[FirebaseArray alloc] initWithQuery:self.observable]; } @@ -127,32 +137,144 @@ - (void)tearDown { [self.observable removeAllObservers]; } +#pragma mark - Insertion + - (void)testFirebaseArrayCanBeInitialized { - XCTAssertNotNil(self.observable, @"expected FirebaseArray to not be nil when initialized"); + XCTAssertNotNil(self.firebaseArray, @"expected FirebaseArray to not be nil when initialized"); } - (void)testEmptyFirebaseArrayUpdatesCountOnInsert { - FUIFakeSnapshot *snap = [[FUIFakeSnapshot alloc] init]; - snap.key = @"snapshot"; + self.snap.key = @"snapshot"; [self.observable sendEvent:FIRDataEventTypeChildAdded - withObject:snap + withObject:self.snap previousKey:nil error:nil]; NSAssert(self.firebaseArray.count == 1, @"expected empty array to contain one item after insert"); } +- (void)testFirebaseArrayCanInsertInMiddle { + // Setup boilerplate + [self.observable populateWithCount:10]; + self.snap.key = @"5"; + + // Insert in middle + [self.observable sendEvent:FIRDataEventTypeChildAdded withObject:self.snap previousKey:@"4" error:nil]; + + // Expectation boilerplate + NSArray *items = self.firebaseArray.items; + NSArray *expected = @[@"0", @"1", @"2", @"3", @"4", @"5", @"5", @"6", @"7", @"8", @"9"]; + NSMutableArray *result = [NSMutableArray array]; + for (FUIFakeSnapshot *snapshot in items) { + [result addObject:snapshot.key]; + } + + XCTAssert([result isEqual:expected], @"expected firebaseArray contents to equal %@, got %@", expected, [result copy]); +} + +- (void)testFirebaseArrayCanInsertAtBeginning { + // Setup boilerplate + [self.observable populateWithCount:10]; + self.snap.key = @"0"; + + // Insert at beginning + [self.observable sendEvent:FIRDataEventTypeChildAdded withObject:self.snap previousKey:nil error:nil]; + + // Expectation boilerplate + NSArray *items = self.firebaseArray.items; + NSArray *expected = @[@"0", @"0", @"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9"]; + NSMutableArray *result = [NSMutableArray array]; + for (FUIFakeSnapshot *snapshot in items) { + [result addObject:snapshot.key]; + } + + XCTAssert([result isEqual:expected], @"expected firebaseArray contents to equal %@, got %@", expected, [result copy]); +} + +- (void)testFirebaseArrayCanInsertAtEnd { + // Setup boilerplate + [self.observable populateWithCount:10]; + self.snap.key = @"10"; + + // Insert at end + [self.observable sendEvent:FIRDataEventTypeChildAdded withObject:self.snap previousKey:@"9" error:nil]; + + // Expectation boilerplate + NSArray *items = self.firebaseArray.items; + NSArray *expected = @[@"0", @"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9", @"10"]; + NSMutableArray *result = [NSMutableArray array]; + for (FUIFakeSnapshot *snapshot in items) { + [result addObject:snapshot.key]; + } + + XCTAssert([result isEqual:expected], @"expected firebaseArray contents to equal %@, got %@", expected, [result copy]); +} + +- (void)testFirebaseArrayCanInsertIntoUniformArray { + // Setup boilerplate + [self.observable populateWithCount:10 generator:^FUIFakeSnapshot *(NSUInteger i) { + FUIFakeSnapshot *snap = [[FUIFakeSnapshot alloc] init]; + snap.key = @"1"; + return snap; + }]; + self.snap.key = @"1"; + + // Insert after @"1", which is ambiguous + [self.observable sendEvent:FIRDataEventTypeChildAdded withObject:self.snap previousKey:@"1" error:nil]; + + // Expectation boilerplate + NSArray *items = self.firebaseArray.items; + NSArray *expected = @[@"1", @"1", @"1", @"1", @"1", @"1", @"1", @"1", @"1", @"1", @"1"]; + NSMutableArray *result = [NSMutableArray array]; + for (FUIFakeSnapshot *snapshot in items) { + [result addObject:snapshot.key]; + } + + XCTAssert([result isEqual:expected], @"expected firebaseArray contents to equal %@, got %@", expected, [result copy]); +} + +- (void)testFirebaseCanInsertIntoArrayWithDuplicates { + // Setup boilerplate + [self.observable populateWithCount:10 generator:^FUIFakeSnapshot *(NSUInteger i) { + FUIFakeSnapshot *snap = [[FUIFakeSnapshot alloc] init]; + // Since insertion with duplicates is ambiguous and is resolved by + // always inserting at the first element identical to the + // previous sibling, this series of insertions will produce + // unexpected results. + snap.key = ((i % 3 == 0) ? @"1" : @"0"); + NSLog(@"index: %lu, key: %@", i, snap.key); + return snap; + }]; + self.snap.key = @"1"; + + // Insert after @"1", which is ambiguous again + [self.observable sendEvent:FIRDataEventTypeChildAdded withObject:self.snap previousKey:@"1" error:nil]; + + // Expectation boilerplate + NSArray *items = self.firebaseArray.items; + // The insertion point (after the first 1) of this ambiguous insert + // is a leaky implementation detail and could be considered a bug. + NSArray *expected = @[@"1", @"1", @"0", @"1", @"0", @"0", @"1", @"0", @"0", @"1", @"0"]; + NSMutableArray *result = [NSMutableArray array]; + for (FUIFakeSnapshot *snapshot in items) { + [result addObject:snapshot.key]; + } + + XCTAssert([result isEqual:expected], @"expected firebaseArray contents to equal %@, got %@", expected, [result copy]); +} + +#pragma mark - Deletion + - (void)testFirebaseArrayCanDeleteOneElementArray { // Insert a key - FUIFakeSnapshot *snap = [[FUIFakeSnapshot alloc] init]; - snap.key = @"snapshot"; + self.snap.key = @"snapshot"; [self.observable sendEvent:FIRDataEventTypeChildAdded - withObject:snap + withObject:self.snap previousKey:nil error:nil]; // Delete [self.observable sendEvent:FIRDataEventTypeChildRemoved - withObject:snap + withObject:self.snap previousKey:nil error:nil]; @@ -160,18 +282,49 @@ - (void)testFirebaseArrayCanDeleteOneElementArray { @"expected empty array to still be empty after one insertion and one deletion"); } -- (void)testFirebaseArrayCanInsertInMiddle { - // Setup boilerplate +- (void)testFirebaseArrayCanDeleteFirstElement { [self.observable populateWithCount:10]; - FUIFakeSnapshot *snap = [[FUIFakeSnapshot alloc] init]; - snap.key = @"5"; + self.snap.key = @"0"; - // This is the actual change being tested - [self.observable sendEvent:FIRDataEventTypeChildAdded withObject:snap previousKey:@"4" error:nil]; + [self.observable sendEvent:FIRDataEventTypeChildRemoved withObject:self.snap previousKey:nil error:nil]; // Expectation boilerplate NSArray *items = self.firebaseArray.items; - NSArray *expected = @[@"0", @"1", @"2", @"3", @"4", @"5", @"5", @"6", @"7", @"8", @"9"]; + NSArray *expected = @[@"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9"]; + NSMutableArray *result = [NSMutableArray array]; + for (FUIFakeSnapshot *snapshot in items) { + [result addObject:snapshot.key]; + } + + XCTAssert([result isEqual:expected], @"expected firebaseArray contents to equal %@, got %@", expected, [result copy]); +} + +- (void)testFirebaseArrayCanDeleteLastElement { + [self.observable populateWithCount:10]; + self.snap.key = @"9"; + + [self.observable sendEvent:FIRDataEventTypeChildRemoved withObject:self.snap previousKey:@"8" error:nil]; + + // Expectation boilerplate + NSArray *items = self.firebaseArray.items; + NSArray *expected = @[@"0", @"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8"]; + NSMutableArray *result = [NSMutableArray array]; + for (FUIFakeSnapshot *snapshot in items) { + [result addObject:snapshot.key]; + } + + XCTAssert([result isEqual:expected], @"expected firebaseArray contents to equal %@, got %@", expected, [result copy]); +} + +- (void)testFirebaseArrayCanDeleteMiddleElement { + [self.observable populateWithCount:10]; + self.snap.key = @"5"; + + [self.observable sendEvent:FIRDataEventTypeChildRemoved withObject:self.snap previousKey:@"4" error:nil]; + + // Expectation boilerplate + NSArray *items = self.firebaseArray.items; + NSArray *expected = @[@"0", @"1", @"2", @"3", @"4", @"6", @"7", @"8", @"9"]; NSMutableArray *result = [NSMutableArray array]; for (FUIFakeSnapshot *snapshot in items) { [result addObject:snapshot.key]; @@ -180,4 +333,43 @@ - (void)testFirebaseArrayCanInsertInMiddle { XCTAssert([result isEqual:expected], @"expected firebaseArray contents to equal %@, got %@", expected, [result copy]); } +- (void)testFirebaseArrayCanModifyElement { + // TODO: Make this test less bad + [self.observable populateWithCount:10]; + self.snap.key = @"5"; + + [self.observable sendEvent:FIRDataEventTypeChildChanged withObject:self.snap previousKey:@"4" error:nil]; + + // Expectation boilerplate + NSArray *items = self.firebaseArray.items; + // Current implementation doesn't change the key of the snap on child change. + NSArray *expected = @[@"0", @"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9"]; + NSMutableArray *result = [NSMutableArray array]; + for (FUIFakeSnapshot *snapshot in items) { + [result addObject:snapshot.key]; + } + + XCTAssert([result isEqual:expected], @"expected firebaseArray contents to equal %@, got %@", expected, [result copy]); +} + +- (void)testirebaseArrayCanMoveElement { + [self.observable populateWithCount:10]; + self.snap.key = @"8"; + + // Move 8 to after 2 + [self.observable sendEvent:FIRDataEventTypeChildMoved withObject:self.snap previousKey:@"2" error:nil]; + + // Expectation boilerplate + NSArray *items = self.firebaseArray.items; + NSArray *expected = @[@"0", @"1", @"2", @"8", @"3", @"4", @"5", @"6", @"7", @"9"]; + NSMutableArray *result = [NSMutableArray array]; + for (FUIFakeSnapshot *snapshot in items) { + [result addObject:snapshot.key]; + } + + XCTAssert([result isEqual:expected], @"expected firebaseArray contents to equal %@, got %@", expected, [result copy]); +} + +// TODO: add tests for arrays with uniques after we figure out what we want the desired behavior to be + @end From bfd3b63a516614ef4496475b1f12b85d435c32cf Mon Sep 17 00:00:00 2001 From: Morgan Chen Date: Fri, 5 Aug 2016 12:02:36 -0700 Subject: [PATCH 09/28] add firebase array delegate tests --- .../Database/Implementation/FirebaseArray.m | 12 +- FirebaseUITests/FirebaseArrayTest.m | 255 ++++++++++++++++-- 2 files changed, 237 insertions(+), 30 deletions(-) diff --git a/FirebaseUI/Database/Implementation/FirebaseArray.m b/FirebaseUI/Database/Implementation/FirebaseArray.m index 65004f79174..d9205cab0a5 100755 --- a/FirebaseUI/Database/Implementation/FirebaseArray.m +++ b/FirebaseUI/Database/Implementation/FirebaseArray.m @@ -33,8 +33,7 @@ @interface FirebaseArray () @implementation FirebaseArray -#pragma mark - -#pragma mark Initializer methods +#pragma mark - Initializer methods - (instancetype)initWithQuery:(FIRDatabaseQuery *)query { NSParameterAssert(query != nil); @@ -48,8 +47,7 @@ - (instancetype)initWithQuery:(FIRDatabaseQuery *)query { return self; } -#pragma mark - -#pragma mark Memory management methods +#pragma mark - Memory management methods - (void)dealloc { // TODO: Consider keeping track of these and only removing them if they are @@ -57,8 +55,7 @@ - (void)dealloc { [self.query removeAllObservers]; } -#pragma mark - -#pragma mark Private API methods +#pragma mark - Private API methods - (void)initListeners { [self.query observeEventType:FIRDataEventTypeChildAdded @@ -142,8 +139,7 @@ - (NSUInteger)indexForKey:(NSString *)key { return NSNotFound; } -#pragma mark - -#pragma mark Public API methods +#pragma mark - Public API methods - (NSArray *)items { return [self.snapshots copy]; diff --git a/FirebaseUITests/FirebaseArrayTest.m b/FirebaseUITests/FirebaseArrayTest.m index 0a04d142c94..156a74d3530 100644 --- a/FirebaseUITests/FirebaseArrayTest.m +++ b/FirebaseUITests/FirebaseArrayTest.m @@ -115,8 +115,52 @@ - (void)populateWithCount:(NSUInteger)count { @end +@interface FUIFirebaseArrayTestDelegate : NSObject +@property (nonatomic, copy) void (^queryCancelled)(FirebaseArray *array, NSError *error); +@property (nonatomic, copy) void (^didAddObject)(FirebaseArray *array, id object, NSUInteger index); +@property (nonatomic, copy) void (^didChangeObject)(FirebaseArray *array, id object, NSUInteger index); +@property (nonatomic, copy) void (^didRemoveObject)(FirebaseArray *array, id object, NSUInteger index); +@property (nonatomic, copy) void (^didMoveObject)(FirebaseArray *array, id object, NSUInteger fromIndex, NSUInteger toIndex); +@end + +@implementation FUIFirebaseArrayTestDelegate + +- (void)array:(FirebaseArray *)array didAddObject:(id)object atIndex:(NSUInteger)index { + if (self.didAddObject != NULL) { + self.didAddObject(array, object, index); + } +} + +- (void)array:(FirebaseArray *)array didChangeObject:(id)object atIndex:(NSUInteger)index { + if (self.didChangeObject != NULL) { + self.didChangeObject(array, object, index); + } +} + +- (void)array:(FirebaseArray *)array didRemoveObject:(id)object atIndex:(NSUInteger)index { + if (self.didRemoveObject != NULL) { + self.didRemoveObject(array, object, index); + } +} + +- (void)array:(FirebaseArray *)array didMoveObject:(id)object + fromIndex:(NSUInteger)fromIndex toIndex:(NSUInteger)toIndex { + if (self.didMoveObject != NULL) { + self.didMoveObject(array, object, fromIndex, toIndex); + } +} + +- (void)array:(FirebaseArray *)array queryCancelledWithError:(NSError *)error { + if (self.queryCancelled != NULL) { + self.queryCancelled(array, error); + } +} + +@end + @interface FirebaseArrayTest : XCTestCase +@property (nonatomic, nullable) FUIFirebaseArrayTestDelegate *arrayDelegate; @property (nonatomic, nullable) FUITestObservable *observable; @property (nonatomic, nullable) FirebaseArray *firebaseArray; @property (nonatomic, nullable) FUIFakeSnapshot *snap; @@ -127,9 +171,11 @@ @implementation FirebaseArrayTest - (void)setUp { [super setUp]; + self.arrayDelegate = [[FUIFirebaseArrayTestDelegate alloc] init]; self.snap = [[FUIFakeSnapshot alloc] init]; self.observable = [[FUITestObservable alloc] init]; self.firebaseArray = [[FirebaseArray alloc] initWithQuery:self.observable]; + self.firebaseArray.delegate = self.arrayDelegate; } - (void)tearDown { @@ -144,12 +190,29 @@ - (void)testFirebaseArrayCanBeInitialized { } - (void)testEmptyFirebaseArrayUpdatesCountOnInsert { + // Test delegate + __block BOOL delegateWasCalled = NO; + __block BOOL expectedParametersWereCorrect = NO; + self.arrayDelegate.didAddObject = ^(FirebaseArray *array, id object, NSUInteger index) { + // Xcode complains about retain cycles if an XCTAssert is placed in here. + delegateWasCalled = YES; + expectedParametersWereCorrect = (array == self.firebaseArray && + object == self.snap && + index == 0); + }; + + // Test insert self.snap.key = @"snapshot"; [self.observable sendEvent:FIRDataEventTypeChildAdded withObject:self.snap previousKey:nil error:nil]; - NSAssert(self.firebaseArray.count == 1, @"expected empty array to contain one item after insert"); + // Array expectations + XCTAssert(self.firebaseArray.count == 1, @"expected empty array to contain one item after insert"); + + // Delegate expectations + XCTAssert(delegateWasCalled, @"expected delegate to receive callback for insertion"); + XCTAssert(expectedParametersWereCorrect, @"unexpected parameter in delegate callback"); } - (void)testFirebaseArrayCanInsertInMiddle { @@ -157,18 +220,32 @@ - (void)testFirebaseArrayCanInsertInMiddle { [self.observable populateWithCount:10]; self.snap.key = @"5"; + // Test delegate + __block BOOL delegateWasCalled = NO; + __block BOOL expectedParametersWereCorrect = NO; + self.arrayDelegate.didAddObject = ^(FirebaseArray *array, id object, NSUInteger index) { + // Xcode complains about retain cycles if an XCTAssert is placed in here. + delegateWasCalled = YES; + expectedParametersWereCorrect = (array == self.firebaseArray && + object == self.snap && + index == 5); + }; + // Insert in middle [self.observable sendEvent:FIRDataEventTypeChildAdded withObject:self.snap previousKey:@"4" error:nil]; - // Expectation boilerplate + // Array expectations NSArray *items = self.firebaseArray.items; NSArray *expected = @[@"0", @"1", @"2", @"3", @"4", @"5", @"5", @"6", @"7", @"8", @"9"]; NSMutableArray *result = [NSMutableArray array]; for (FUIFakeSnapshot *snapshot in items) { [result addObject:snapshot.key]; } - XCTAssert([result isEqual:expected], @"expected firebaseArray contents to equal %@, got %@", expected, [result copy]); + + // Delegate expectations + XCTAssert(delegateWasCalled, @"expected delegate to receive callback for insertion"); + XCTAssert(expectedParametersWereCorrect, @"unexpected parameter in delegate callback"); } - (void)testFirebaseArrayCanInsertAtBeginning { @@ -176,18 +253,32 @@ - (void)testFirebaseArrayCanInsertAtBeginning { [self.observable populateWithCount:10]; self.snap.key = @"0"; + // Test delegate + __block BOOL delegateWasCalled = NO; + __block BOOL expectedParametersWereCorrect = NO; + self.arrayDelegate.didAddObject = ^(FirebaseArray *array, id object, NSUInteger index) { + // Xcode complains about retain cycles if an XCTAssert is placed in here. + delegateWasCalled = YES; + expectedParametersWereCorrect = (array == self.firebaseArray && + object == self.snap && + index == 0); + }; + // Insert at beginning [self.observable sendEvent:FIRDataEventTypeChildAdded withObject:self.snap previousKey:nil error:nil]; - // Expectation boilerplate + // Array expectations NSArray *items = self.firebaseArray.items; NSArray *expected = @[@"0", @"0", @"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9"]; NSMutableArray *result = [NSMutableArray array]; for (FUIFakeSnapshot *snapshot in items) { [result addObject:snapshot.key]; } - XCTAssert([result isEqual:expected], @"expected firebaseArray contents to equal %@, got %@", expected, [result copy]); + + // Delegate expectations + XCTAssert(delegateWasCalled, @"expected delegate to receive callback for insertion"); + XCTAssert(expectedParametersWereCorrect, @"unexpected parameter in delegate callback"); } - (void)testFirebaseArrayCanInsertAtEnd { @@ -195,18 +286,32 @@ - (void)testFirebaseArrayCanInsertAtEnd { [self.observable populateWithCount:10]; self.snap.key = @"10"; + // Test delegate + __block BOOL delegateWasCalled = NO; + __block BOOL expectedParametersWereCorrect = NO; + self.arrayDelegate.didAddObject = ^(FirebaseArray *array, id object, NSUInteger index) { + // Xcode complains about retain cycles if an XCTAssert is placed in here. + delegateWasCalled = YES; + expectedParametersWereCorrect = (array == self.firebaseArray && + object == self.snap && + index == 10); + }; + // Insert at end [self.observable sendEvent:FIRDataEventTypeChildAdded withObject:self.snap previousKey:@"9" error:nil]; - // Expectation boilerplate + // Array expectations NSArray *items = self.firebaseArray.items; NSArray *expected = @[@"0", @"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9", @"10"]; NSMutableArray *result = [NSMutableArray array]; for (FUIFakeSnapshot *snapshot in items) { [result addObject:snapshot.key]; } - XCTAssert([result isEqual:expected], @"expected firebaseArray contents to equal %@, got %@", expected, [result copy]); + + // Delegate expectations + XCTAssert(delegateWasCalled, @"expected delegate to receive callback for insertion"); + XCTAssert(expectedParametersWereCorrect, @"unexpected parameter in delegate callback"); } - (void)testFirebaseArrayCanInsertIntoUniformArray { @@ -218,18 +323,32 @@ - (void)testFirebaseArrayCanInsertIntoUniformArray { }]; self.snap.key = @"1"; + // Test delegate + __block BOOL delegateWasCalled = NO; + __block BOOL expectedParametersWereCorrect = NO; + self.arrayDelegate.didAddObject = ^(FirebaseArray *array, id object, NSUInteger index) { + // Xcode complains about retain cycles if an XCTAssert is placed in here. + delegateWasCalled = YES; + expectedParametersWereCorrect = (array == self.firebaseArray && + object == self.snap && + index == 1); + }; + // Insert after @"1", which is ambiguous [self.observable sendEvent:FIRDataEventTypeChildAdded withObject:self.snap previousKey:@"1" error:nil]; - // Expectation boilerplate + // Array expectations NSArray *items = self.firebaseArray.items; NSArray *expected = @[@"1", @"1", @"1", @"1", @"1", @"1", @"1", @"1", @"1", @"1", @"1"]; NSMutableArray *result = [NSMutableArray array]; for (FUIFakeSnapshot *snapshot in items) { [result addObject:snapshot.key]; } - XCTAssert([result isEqual:expected], @"expected firebaseArray contents to equal %@, got %@", expected, [result copy]); + + // Delegate expectations + XCTAssert(delegateWasCalled, @"expected delegate to receive callback for insertion"); + XCTAssert(expectedParametersWereCorrect, @"unexpected parameter in delegate callback"); } - (void)testFirebaseCanInsertIntoArrayWithDuplicates { @@ -249,7 +368,7 @@ - (void)testFirebaseCanInsertIntoArrayWithDuplicates { // Insert after @"1", which is ambiguous again [self.observable sendEvent:FIRDataEventTypeChildAdded withObject:self.snap previousKey:@"1" error:nil]; - // Expectation boilerplate + // Array expectations NSArray *items = self.firebaseArray.items; // The insertion point (after the first 1) of this ambiguous insert // is a leaky implementation detail and could be considered a bug. @@ -272,75 +391,148 @@ - (void)testFirebaseArrayCanDeleteOneElementArray { previousKey:nil error:nil]; + // Test delegate + __block BOOL delegateWasCalled = NO; + __block BOOL expectedParametersWereCorrect = NO; + self.arrayDelegate.didRemoveObject = ^(FirebaseArray *array, id object, NSUInteger index) { + // Xcode complains about retain cycles if an XCTAssert is placed in here. + delegateWasCalled = YES; + expectedParametersWereCorrect = (array == self.firebaseArray && + object == self.snap && + index == 0); + }; + // Delete [self.observable sendEvent:FIRDataEventTypeChildRemoved withObject:self.snap previousKey:nil error:nil]; - + // Array expectation XCTAssert(self.firebaseArray.count == 0, @"expected empty array to still be empty after one insertion and one deletion"); + + // Delegate expectations + XCTAssert(delegateWasCalled, @"expected delegate to receive callback for deletion"); + XCTAssert(expectedParametersWereCorrect, @"unexpected parameter in delegate callback"); } - (void)testFirebaseArrayCanDeleteFirstElement { [self.observable populateWithCount:10]; self.snap.key = @"0"; + // Test delegate + __block BOOL delegateWasCalled = NO; + __block BOOL expectedParametersWereCorrect = NO; + self.arrayDelegate.didRemoveObject = ^(FirebaseArray *array, id object, NSUInteger index) { + // Xcode complains about retain cycles if an XCTAssert is placed in here. + delegateWasCalled = YES; + expectedParametersWereCorrect = (array == self.firebaseArray && + object == self.snap && + index == 0); + }; + [self.observable sendEvent:FIRDataEventTypeChildRemoved withObject:self.snap previousKey:nil error:nil]; - // Expectation boilerplate + // Array expectations NSArray *items = self.firebaseArray.items; NSArray *expected = @[@"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9"]; NSMutableArray *result = [NSMutableArray array]; for (FUIFakeSnapshot *snapshot in items) { [result addObject:snapshot.key]; } - XCTAssert([result isEqual:expected], @"expected firebaseArray contents to equal %@, got %@", expected, [result copy]); + + // Delegate expectations + XCTAssert(delegateWasCalled, @"expected delegate to receive callback for deletion"); + XCTAssert(expectedParametersWereCorrect, @"unexpected parameter in delegate callback"); } - (void)testFirebaseArrayCanDeleteLastElement { [self.observable populateWithCount:10]; self.snap.key = @"9"; + // Test delegate + __block BOOL delegateWasCalled = NO; + __block BOOL expectedParametersWereCorrect = NO; + self.arrayDelegate.didRemoveObject = ^(FirebaseArray *array, id object, NSUInteger index) { + // Xcode complains about retain cycles if an XCTAssert is placed in here. + delegateWasCalled = YES; + expectedParametersWereCorrect = (array == self.firebaseArray && + object == self.snap && + index == 9); + }; + + // Delete last element [self.observable sendEvent:FIRDataEventTypeChildRemoved withObject:self.snap previousKey:@"8" error:nil]; - // Expectation boilerplate + // Array expectations NSArray *items = self.firebaseArray.items; NSArray *expected = @[@"0", @"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8"]; NSMutableArray *result = [NSMutableArray array]; for (FUIFakeSnapshot *snapshot in items) { [result addObject:snapshot.key]; } - XCTAssert([result isEqual:expected], @"expected firebaseArray contents to equal %@, got %@", expected, [result copy]); + + // Delegate expectations + XCTAssert(delegateWasCalled, @"expected delegate to receive callback for deletion"); + XCTAssert(expectedParametersWereCorrect, @"unexpected parameter in delegate callback"); } - (void)testFirebaseArrayCanDeleteMiddleElement { [self.observable populateWithCount:10]; self.snap.key = @"5"; + // Test delegate + __block BOOL delegateWasCalled = NO; + __block BOOL expectedParametersWereCorrect = NO; + self.arrayDelegate.didRemoveObject = ^(FirebaseArray *array, id object, NSUInteger index) { + // Xcode complains about retain cycles if an XCTAssert is placed in here. + delegateWasCalled = YES; + expectedParametersWereCorrect = (array == self.firebaseArray && + object == self.snap && + index == 5); + }; + + // Delete element [self.observable sendEvent:FIRDataEventTypeChildRemoved withObject:self.snap previousKey:@"4" error:nil]; - // Expectation boilerplate + // Array expectation NSArray *items = self.firebaseArray.items; NSArray *expected = @[@"0", @"1", @"2", @"3", @"4", @"6", @"7", @"8", @"9"]; NSMutableArray *result = [NSMutableArray array]; for (FUIFakeSnapshot *snapshot in items) { [result addObject:snapshot.key]; } - XCTAssert([result isEqual:expected], @"expected firebaseArray contents to equal %@, got %@", expected, [result copy]); + + // Delegate expectations + XCTAssert(delegateWasCalled, @"expected delegate to receive callback for deletion"); + XCTAssert(expectedParametersWereCorrect, @"unexpected parameter in delegate callback"); } +#pragma mark - Modifying elements + - (void)testFirebaseArrayCanModifyElement { // TODO: Make this test less bad [self.observable populateWithCount:10]; self.snap.key = @"5"; + // Test delegate + __block BOOL delegateWasCalled = NO; + __block BOOL expectedParametersWereCorrect = NO; + self.arrayDelegate.didChangeObject = ^(FirebaseArray *array, id object, NSUInteger index) { + // Xcode complains about retain cycles if an XCTAssert is placed in here. + delegateWasCalled = YES; + expectedParametersWereCorrect = (array == self.firebaseArray && + object == self.snap && + index == 5); + }; + + // Replace element with identical copy of itself lol [self.observable sendEvent:FIRDataEventTypeChildChanged withObject:self.snap previousKey:@"4" error:nil]; - // Expectation boilerplate + // Array expectation NSArray *items = self.firebaseArray.items; // Current implementation doesn't change the key of the snap on child change. NSArray *expected = @[@"0", @"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9"]; @@ -348,26 +540,45 @@ - (void)testFirebaseArrayCanModifyElement { for (FUIFakeSnapshot *snapshot in items) { [result addObject:snapshot.key]; } - XCTAssert([result isEqual:expected], @"expected firebaseArray contents to equal %@, got %@", expected, [result copy]); + + // Delegate expectations + XCTAssert(delegateWasCalled, @"expected delegate to receive callback for deletion"); + XCTAssert(expectedParametersWereCorrect, @"unexpected parameter in delegate callback"); } -- (void)testirebaseArrayCanMoveElement { +#pragma mark - Moving elements + +- (void)testFirebaseArrayCanMoveElement { [self.observable populateWithCount:10]; self.snap.key = @"8"; + // Test delegate + __block BOOL delegateWasCalled = NO; + __block BOOL expectedParametersWereCorrect = NO; + self.arrayDelegate.didMoveObject = ^(FirebaseArray *array, id object, NSUInteger from, NSUInteger to) { + // Xcode complains about retain cycles if an XCTAssert is placed in here. + delegateWasCalled = YES; + expectedParametersWereCorrect = (array == self.firebaseArray && + object == self.snap && + from == 8 && to == 3); + }; + // Move 8 to after 2 [self.observable sendEvent:FIRDataEventTypeChildMoved withObject:self.snap previousKey:@"2" error:nil]; - // Expectation boilerplate + // Array expectation NSArray *items = self.firebaseArray.items; NSArray *expected = @[@"0", @"1", @"2", @"8", @"3", @"4", @"5", @"6", @"7", @"9"]; NSMutableArray *result = [NSMutableArray array]; for (FUIFakeSnapshot *snapshot in items) { [result addObject:snapshot.key]; } - XCTAssert([result isEqual:expected], @"expected firebaseArray contents to equal %@, got %@", expected, [result copy]); + + // Delegate expectations + XCTAssert(delegateWasCalled, @"expected delegate to receive callback for deletion"); + XCTAssert(expectedParametersWereCorrect, @"unexpected parameter in delegate callback"); } // TODO: add tests for arrays with uniques after we figure out what we want the desired behavior to be From a455819097838c4ccef3ecdfe1ba8e522a0bffa8 Mon Sep 17 00:00:00 2001 From: Morgan Chen Date: Mon, 8 Aug 2016 12:06:29 -0700 Subject: [PATCH 10/28] make FirebaseArray remove only its own observers --- FirebaseUI/Database/API/FirebaseArray.h | 2 +- .../Database/Implementation/FirebaseArray.m | 28 +++++++++++++------ FirebaseUITests/FirebaseArrayTest.m | 4 +++ 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/FirebaseUI/Database/API/FirebaseArray.h b/FirebaseUI/Database/API/FirebaseArray.h index d165211f2eb..42ac138ac1c 100644 --- a/FirebaseUI/Database/API/FirebaseArray.h +++ b/FirebaseUI/Database/API/FirebaseArray.h @@ -31,7 +31,7 @@ NS_ASSUME_NONNULL_BEGIN andPreviousSiblingKeyWithBlock:(void (^)(FIRDataSnapshot *snapshot, NSString *__nullable prevKey))block withCancelBlock:(nullable void (^)(NSError* error))cancelBlock; -- (void)removeAllObservers; // TODO: allow removing observers by handle +- (void)removeObserverWithHandle:(FIRDatabaseHandle)handle; @end diff --git a/FirebaseUI/Database/Implementation/FirebaseArray.m b/FirebaseUI/Database/Implementation/FirebaseArray.m index d9205cab0a5..e0937445330 100755 --- a/FirebaseUI/Database/Implementation/FirebaseArray.m +++ b/FirebaseUI/Database/Implementation/FirebaseArray.m @@ -27,6 +27,12 @@ @interface FirebaseArray () */ @property(strong, nonatomic) NSMutableArray * snapshots; +/** + * A set containing the query observer handles that should be released when + * this array is freed. + */ +@property(strong, nonatomic) NSMutableSet *handles; + @end @import FirebaseDatabase; @@ -41,6 +47,7 @@ - (instancetype)initWithQuery:(FIRDatabaseQuery *)query { if (self) { _snapshots = [NSMutableArray array]; _query = query; + _handles = [NSMutableSet setWithCapacity:4]; [self initListeners]; } @@ -50,15 +57,16 @@ - (instancetype)initWithQuery:(FIRDatabaseQuery *)query { #pragma mark - Memory management methods - (void)dealloc { - // TODO: Consider keeping track of these and only removing them if they are - // explicitly added here - [self.query removeAllObservers]; + for (NSNumber *handle in _handles) { + [_query removeObserverWithHandle:handle.unsignedIntegerValue]; + } } #pragma mark - Private API methods - (void)initListeners { - [self.query observeEventType:FIRDataEventTypeChildAdded + FIRDatabaseHandle handle; + handle = [self.query observeEventType:FIRDataEventTypeChildAdded andPreviousSiblingKeyWithBlock:^(FIRDataSnapshot *snapshot, NSString *previousChildKey) { NSUInteger index = 0; if (previousChildKey != nil) { @@ -76,8 +84,9 @@ - (void)initListeners { [self.delegate array:self queryCancelledWithError:error]; } }]; + [_handles addObject:@(handle)]; - [self.query observeEventType:FIRDataEventTypeChildChanged + handle = [self.query observeEventType:FIRDataEventTypeChildChanged andPreviousSiblingKeyWithBlock:^(FIRDataSnapshot *snapshot, NSString *previousChildKey) { NSUInteger index = [self indexForKey:snapshot.key]; @@ -92,8 +101,9 @@ - (void)initListeners { [self.delegate array:self queryCancelledWithError:error]; } }]; + [_handles addObject:@(handle)]; - [self.query observeEventType:FIRDataEventTypeChildRemoved + handle = [self.query observeEventType:FIRDataEventTypeChildRemoved andPreviousSiblingKeyWithBlock:^(FIRDataSnapshot *snapshot, NSString *previousSiblingKey) { NSUInteger index = [self indexForKey:snapshot.key]; @@ -108,8 +118,9 @@ - (void)initListeners { [self.delegate array:self queryCancelledWithError:error]; } }]; + [_handles addObject:@(handle)]; - [self.query observeEventType:FIRDataEventTypeChildMoved + handle = [self.query observeEventType:FIRDataEventTypeChildMoved andPreviousSiblingKeyWithBlock:^(FIRDataSnapshot *snapshot, NSString *previousChildKey) { NSUInteger fromIndex = [self indexForKey:snapshot.key]; [self.snapshots removeObjectAtIndex:fromIndex]; @@ -126,6 +137,7 @@ - (void)initListeners { [self.delegate array:self queryCancelledWithError:error]; } }]; + [_handles addObject:@(handle)]; } - (NSUInteger)indexForKey:(NSString *)key { @@ -158,7 +170,7 @@ - (FIRDatabaseReference *)refForIndex:(NSUInteger)index { } - (id)objectAtIndexedSubscript:(NSUInteger)index{ - return [self objectAtIndex:index]; + return [self objectAtIndex:index]; } - (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)index{ diff --git a/FirebaseUITests/FirebaseArrayTest.m b/FirebaseUITests/FirebaseArrayTest.m index 156a74d3530..099ec240a11 100644 --- a/FirebaseUITests/FirebaseArrayTest.m +++ b/FirebaseUITests/FirebaseArrayTest.m @@ -60,6 +60,10 @@ - (instancetype)init { return self; } +- (void)removeObserverWithHandle:(FIRDatabaseHandle)handle { + [self.observers removeObjectForKey:@(handle)]; +} + - (void)removeAllObservers { _observers = [NSMutableDictionary dictionary]; } From 6348024da631da6b7ba0d6b3f42323051425c3ab Mon Sep 17 00:00:00 2001 From: Morgan Chen Date: Mon, 8 Aug 2016 13:29:11 -0700 Subject: [PATCH 11/28] use correct delegate methods --- .../Database/Implementation/FirebaseArray.m | 2 +- .../FirebaseCollectionViewDataSource.m | 16 +++++++--------- .../Implementation/FirebaseTableViewDataSource.m | 14 +++++++------- 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/FirebaseUI/Database/Implementation/FirebaseArray.m b/FirebaseUI/Database/Implementation/FirebaseArray.m index e0937445330..be02a2af300 100755 --- a/FirebaseUI/Database/Implementation/FirebaseArray.m +++ b/FirebaseUI/Database/Implementation/FirebaseArray.m @@ -169,7 +169,7 @@ - (FIRDatabaseReference *)refForIndex:(NSUInteger)index { return [(FIRDataSnapshot *)[self.snapshots objectAtIndex:index] ref]; } -- (id)objectAtIndexedSubscript:(NSUInteger)index{ +- (id)objectAtIndexedSubscript:(NSUInteger)index { return [self objectAtIndex:index]; } diff --git a/FirebaseUI/Database/Implementation/FirebaseCollectionViewDataSource.m b/FirebaseUI/Database/Implementation/FirebaseCollectionViewDataSource.m index a61230a56c2..3682294e0ef 100644 --- a/FirebaseUI/Database/Implementation/FirebaseCollectionViewDataSource.m +++ b/FirebaseUI/Database/Implementation/FirebaseCollectionViewDataSource.m @@ -234,31 +234,29 @@ - (instancetype)initWithQuery:(FIRDatabaseQuery *)query return self; } -#pragma mark - -#pragma mark FirebaseCollectionDelegate methods +#pragma mark - FirebaseArrayDelegate methods -- (void)childAdded:(id)obj atIndex:(NSUInteger)index { +- (void)array:(FirebaseArray *)array didAddObject:(id)object atIndex:(NSUInteger)index { [self.collectionView insertItemsAtIndexPaths:@[ [NSIndexPath indexPathForItem:index inSection:0] ]]; } -- (void)childChanged:(id)obj atIndex:(NSUInteger)index { +- (void)array:(FirebaseArray *)array didChangeObject:(id)object atIndex:(NSUInteger)index { [self.collectionView reloadItemsAtIndexPaths:@[ [NSIndexPath indexPathForRow:index inSection:0] ]]; } -- (void)childRemoved:(id)obj atIndex:(NSUInteger)index { +- (void)array:(FirebaseArray *)array didRemoveObject:(id)object atIndex:(NSUInteger)index { [self.collectionView deleteItemsAtIndexPaths:@[ [NSIndexPath indexPathForRow:index inSection:0] ]]; } -- (void)childMoved:(id)obj fromIndex:(NSUInteger)fromIndex toIndex:(NSUInteger)toIndex { +- (void)array:(FirebaseArray *)array didMoveObject:(id)object fromIndex:(NSUInteger)fromIndex toIndex:(NSUInteger)toIndex { [self.collectionView moveItemAtIndexPath:[NSIndexPath indexPathForRow:fromIndex inSection:0] toIndexPath:[NSIndexPath indexPathForRow:toIndex inSection:0]]; } -#pragma mark - -#pragma mark UICollectionViewDataSource methods +#pragma mark - UICollectionViewDataSource methods - (nonnull UICollectionViewCell *)collectionView:(nonnull UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath { @@ -285,7 +283,7 @@ - (NSInteger)numberOfSectionsInCollectionView:(nonnull UICollectionView *)collec - (NSInteger)collectionView:(nonnull UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { - return self.items.count; + return self.count; } - (void)populateCellWithBlock: diff --git a/FirebaseUI/Database/Implementation/FirebaseTableViewDataSource.m b/FirebaseUI/Database/Implementation/FirebaseTableViewDataSource.m index 65b269817da..15d8c5c09d7 100644 --- a/FirebaseUI/Database/Implementation/FirebaseTableViewDataSource.m +++ b/FirebaseUI/Database/Implementation/FirebaseTableViewDataSource.m @@ -237,30 +237,30 @@ - (instancetype)initWithQuery:(FIRDatabaseQuery *)query } #pragma mark - -#pragma mark FirebaseCollectionDelegate methods +#pragma mark FirebaseArrayDelegate methods -- (void)childAdded:(id)obj atIndex:(NSUInteger)index { +- (void)array:(FirebaseArray *)array didAddObject:(id)object atIndex:(NSUInteger)index { [self.tableView beginUpdates]; [self.tableView insertRowsAtIndexPaths:@[ [NSIndexPath indexPathForRow:index inSection:0] ] withRowAnimation:UITableViewRowAnimationAutomatic]; [self.tableView endUpdates]; } -- (void)childChanged:(id)obj atIndex:(NSUInteger)index { +- (void)array:(FirebaseArray *)array didChangeObject:(id)object atIndex:(NSUInteger)index { [self.tableView beginUpdates]; [self.tableView reloadRowsAtIndexPaths:@[ [NSIndexPath indexPathForRow:index inSection:0] ] withRowAnimation:UITableViewRowAnimationAutomatic]; [self.tableView endUpdates]; } -- (void)childRemoved:(id)obj atIndex:(NSUInteger)index { +- (void)array:(FirebaseArray *)array didRemoveObject:(id)object atIndex:(NSUInteger)index { [self.tableView beginUpdates]; [self.tableView deleteRowsAtIndexPaths:@[ [NSIndexPath indexPathForRow:index inSection:0] ] withRowAnimation:UITableViewRowAnimationAutomatic]; [self.tableView endUpdates]; } -- (void)childMoved:(id)obj fromIndex:(NSUInteger)fromIndex toIndex:(NSUInteger)toIndex { +- (void)array:(FirebaseArray *)array didMoveObject:(id)object fromIndex:(NSUInteger)fromIndex toIndex:(NSUInteger)toIndex { [self.tableView beginUpdates]; [self.tableView moveRowAtIndexPath:[NSIndexPath indexPathForRow:fromIndex inSection:0] toIndexPath:[NSIndexPath indexPathForRow:toIndex inSection:0]]; @@ -289,11 +289,11 @@ - (id)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)in } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { - return self.items.count; + return self.count; } - (void)populateCellWithBlock:(void (^)(__kindof UITableViewCell *cell, - __kindof NSObject *object))callback { + __kindof NSObject *object))callback { self.populateCell = callback; } From f29ce42cc5cc51cdb0fd5a1022957bc553a2dbad Mon Sep 17 00:00:00 2001 From: Morgan Chen Date: Mon, 8 Aug 2016 13:54:38 -0700 Subject: [PATCH 12/28] update comments --- FirebaseUI/Database/API/FirebaseArray.h | 19 ++++++------------- .../API/FirebaseTableViewDataSource.h | 5 ++--- .../FirebaseCollectionViewDataSource.m | 3 +-- .../Implementation/FirebaseDataSource.m | 9 +++------ .../FirebaseTableViewDataSource.m | 9 +++------ 5 files changed, 15 insertions(+), 30 deletions(-) diff --git a/FirebaseUI/Database/API/FirebaseArray.h b/FirebaseUI/Database/API/FirebaseArray.h index 42ac138ac1c..1787ec2c311 100644 --- a/FirebaseUI/Database/API/FirebaseArray.h +++ b/FirebaseUI/Database/API/FirebaseArray.h @@ -66,8 +66,7 @@ NS_ASSUME_NONNULL_BEGIN */ @property(nonatomic, readonly, copy) NSArray *items; -#pragma mark - -#pragma mark Initializer methods +#pragma mark - Initializer methods /** * Initalizes FirebaseArray with a Firebase query (FIRDatabaseQuery) or database reference @@ -79,8 +78,7 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)init NS_UNAVAILABLE; -#pragma mark - -#pragma mark Public API methods +#pragma mark - Public API methods /** * Returns an object at a specific index in the FirebaseArray. @@ -105,21 +103,16 @@ NS_ASSUME_NONNULL_BEGIN /** * Support for subscripting. This method is unused and trying to write directly to the - * array using subscripting will cause an assertion. + * array using subscripting will cause an assertion failure. */ -- (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx; - -#pragma mark - -#pragma mark Private API methods +- (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx NS_UNAVAILABLE; /** * Returns an index for a given object's key (that matches the object's key in the corresponding * Firebase reference). * @param key The key of the desired object - * @return The index of the object for which the key matches or -1 if the key is null - * @exception FirebaseArrayKeyNotFoundException Thrown when the desired key is not in the - * FirebaseArray, likely indicating that the FirebaseArray is no longer being properly synchronized - * with the Firebase database. + * @return The index of the object for which the key matches or NSNotFound if the key is not found + * @exception NSInvalidArgumentException Thrown when the `key` parameter is `nil`. */ - (NSUInteger)indexForKey:(NSString *)key; diff --git a/FirebaseUI/Database/API/FirebaseTableViewDataSource.h b/FirebaseUI/Database/API/FirebaseTableViewDataSource.h index d6968ff8955..204240ee4b3 100644 --- a/FirebaseUI/Database/API/FirebaseTableViewDataSource.h +++ b/FirebaseUI/Database/API/FirebaseTableViewDataSource.h @@ -383,9 +383,8 @@ NS_ASSUME_NONNULL_BEGIN * This method populates the fields of a UITableViewCell or subclass given a * model object (or * FIRDataSnapshot). - * @param callback A block which returns an initialized UITableViewCell (or - * subclass) and the - * corresponding object to populate the cell with. + * @param callback A block which returns an initialized UITableViewCell + * (or subclass) and the corresponding object to populate the cell with. */ - (void)populateCellWithBlock:(void (^)(__kindof UITableViewCell *cell, __kindof NSObject *object))callback; diff --git a/FirebaseUI/Database/Implementation/FirebaseCollectionViewDataSource.m b/FirebaseUI/Database/Implementation/FirebaseCollectionViewDataSource.m index 3682294e0ef..2c64cf10116 100644 --- a/FirebaseUI/Database/Implementation/FirebaseCollectionViewDataSource.m +++ b/FirebaseUI/Database/Implementation/FirebaseCollectionViewDataSource.m @@ -24,8 +24,7 @@ @implementation FirebaseCollectionViewDataSource -#pragma mark - -#pragma mark FirebaseDataSource initializer methods +#pragma mark - FirebaseDataSource initializer methods - (instancetype)initWithRef:(FIRDatabaseReference *)ref cellReuseIdentifier:(NSString *)identifier diff --git a/FirebaseUI/Database/Implementation/FirebaseDataSource.m b/FirebaseUI/Database/Implementation/FirebaseDataSource.m index 5d20a22670f..14af53cb585 100644 --- a/FirebaseUI/Database/Implementation/FirebaseDataSource.m +++ b/FirebaseUI/Database/Implementation/FirebaseDataSource.m @@ -33,8 +33,7 @@ @interface FirebaseDataSource () @implementation FirebaseDataSource -#pragma mark - -#pragma mark Initializer methods +#pragma mark - Initializer methods - (instancetype)initWithArray:(FirebaseArray *)array { self = [super init]; @@ -45,8 +44,7 @@ - (instancetype)initWithArray:(FirebaseArray *)array { return self; } -#pragma mark - -#pragma mark API methods +#pragma mark - API methods - (NSUInteger)count { return self.array.count; @@ -64,8 +62,7 @@ - (void)cancelWithBlock:(void (^)(NSError *))block { self.cancelBlock = block; } -#pragma mark - -#pragma mark FirebaseArrayDelegate methods +#pragma mark - FirebaseArrayDelegate methods - (void)canceledWithError:(NSError *)error { if (self.cancelBlock != nil) { diff --git a/FirebaseUI/Database/Implementation/FirebaseTableViewDataSource.m b/FirebaseUI/Database/Implementation/FirebaseTableViewDataSource.m index 15d8c5c09d7..7ad21c7e8dc 100644 --- a/FirebaseUI/Database/Implementation/FirebaseTableViewDataSource.m +++ b/FirebaseUI/Database/Implementation/FirebaseTableViewDataSource.m @@ -24,8 +24,7 @@ @implementation FirebaseTableViewDataSource -#pragma mark - -#pragma mark FirebaseDataSource initializer methods +#pragma mark - FirebaseDataSource initializer methods - (instancetype)initWithRef:(FIRDatabaseReference *)ref cellReuseIdentifier:(NSString *)identifier @@ -236,8 +235,7 @@ - (instancetype)initWithQuery:(FIRDatabaseQuery *)query return self; } -#pragma mark - -#pragma mark FirebaseArrayDelegate methods +#pragma mark - FirebaseArrayDelegate methods - (void)array:(FirebaseArray *)array didAddObject:(id)object atIndex:(NSUInteger)index { [self.tableView beginUpdates]; @@ -267,8 +265,7 @@ - (void)array:(FirebaseArray *)array didMoveObject:(id)object fromIndex:(NSUInte [self.tableView endUpdates]; } -#pragma mark - -#pragma mark UITableViewDataSource methods +#pragma mark - UITableViewDataSource methods - (id)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { id cell = [self.tableView dequeueReusableCellWithIdentifier:self.reuseIdentifier From 696d31b04506137ab41bef5d4bd377aeada29991 Mon Sep 17 00:00:00 2001 From: Morgan Chen Date: Mon, 8 Aug 2016 14:36:32 -0700 Subject: [PATCH 13/28] make initializers for auth providers non-optional --- .../Facebook/Source/FIRFacebookAuthUI.h | 8 ++++---- .../Facebook/Source/FIRFacebookAuthUI.m | 6 +++--- .../Google/Source/FIRGoogleAuthUI.h | 16 ++++++++++++---- .../Google/Source/FIRGoogleAuthUI.m | 10 +++++++--- FirebaseUITests/FirebaseArrayTest.m | 16 ++++++++-------- 5 files changed, 34 insertions(+), 22 deletions(-) diff --git a/FirebaseUI/Auth/AuthProviderUI/Facebook/Source/FIRFacebookAuthUI.h b/FirebaseUI/Auth/AuthProviderUI/Facebook/Source/FIRFacebookAuthUI.h index 2eed3c50118..fd0b4cd7606 100644 --- a/FirebaseUI/Auth/AuthProviderUI/Facebook/Source/FIRFacebookAuthUI.h +++ b/FirebaseUI/Auth/AuthProviderUI/Facebook/Source/FIRFacebookAuthUI.h @@ -34,18 +34,18 @@ NS_ASSUME_NONNULL_BEGIN @brief The scopes to use with Facebook Login. @remarks Defaults to using "email" scopes. */ -@property(nonatomic, copy) NSArray *scopes; +@property(nonatomic, copy, readonly) NSArray *scopes; /** @fn init @brief Please use initWithAppId: */ -- (nullable instancetype)init NS_UNAVAILABLE; +- (instancetype)init NS_UNAVAILABLE; /** @fn initWithAppID: @brief Conevenience initializer. Uses a default permission of `@[ "email" ]`. @param appID The Facebook App ID. */ -- (nullable instancetype)initWithAppID:(NSString *)appID; +- (instancetype)initWithAppID:(NSString *)appID; /** @fn initWithAppID:permissions: @brief Designated initializer. @@ -53,7 +53,7 @@ NS_ASSUME_NONNULL_BEGIN @param permissions The permissions of the app. This array must be an array of specific string values as defined in https://developers.facebook.com/docs/facebook-login/permissions/ */ -- (nullable instancetype)initWithAppID:(NSString *)appID permissions:(NSArray *)permissions NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithAppID:(NSString *)appID permissions:(NSArray *)permissions NS_DESIGNATED_INITIALIZER; @end diff --git a/FirebaseUI/Auth/AuthProviderUI/Facebook/Source/FIRFacebookAuthUI.m b/FirebaseUI/Auth/AuthProviderUI/Facebook/Source/FIRFacebookAuthUI.m index 2193e0b6b50..f79a4622c18 100644 --- a/FirebaseUI/Auth/AuthProviderUI/Facebook/Source/FIRFacebookAuthUI.m +++ b/FirebaseUI/Auth/AuthProviderUI/Facebook/Source/FIRFacebookAuthUI.m @@ -49,13 +49,13 @@ @implementation FIRFacebookAuthUI { FIRAuthProviderSignInCompletionBlock _pendingSignInCallback; } -- (nullable instancetype)init { +- (instancetype)init { @throw [NSException exceptionWithName:@"Attempt to call unavailable initializer." reason:@"Please call the designated initializer." userInfo:nil]; } -- (nullable instancetype)initWithAppID:(NSString *)appID permissions:(NSArray *)permissions { +- (instancetype)initWithAppID:(NSString *)appID permissions:(NSArray *)permissions { self = [super init]; if (self != nil) { _scopes = permissions; @@ -65,7 +65,7 @@ - (nullable instancetype)initWithAppID:(NSString *)appID permissions:(NSArray *) return self; } -- (nullable instancetype)initWithAppID:(NSString *)appID { +- (instancetype)initWithAppID:(NSString *)appID { return [self initWithAppID:appID permissions:@[ @"email" ]]; } diff --git a/FirebaseUI/Auth/AuthProviderUI/Google/Source/FIRGoogleAuthUI.h b/FirebaseUI/Auth/AuthProviderUI/Google/Source/FIRGoogleAuthUI.h index 35aed7ca956..4097379dd48 100644 --- a/FirebaseUI/Auth/AuthProviderUI/Google/Source/FIRGoogleAuthUI.h +++ b/FirebaseUI/Auth/AuthProviderUI/Google/Source/FIRGoogleAuthUI.h @@ -34,18 +34,26 @@ NS_ASSUME_NONNULL_BEGIN @brief The scopes to use with Google Sign In. @remarks Defaults to using "email" and "profile" scopes. */ -@property(nonatomic, copy) NSArray *scopes; +@property(nonatomic, copy, readonly) NSArray *scopes; /** @fn init @brief Please use initWithClientId: */ -- (nullable instancetype)init NS_UNAVAILABLE; +- (instancetype)init NS_UNAVAILABLE; /** @fn initWithClientID: - @brief Designated initializer. + @brief Convenience initializer. Calls designated init with default + scopes of "email" and "profile". @param clientId The Google Sign In client ID. */ -- (nullable instancetype)initWithClientID:(NSString *)clientID NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithClientID:(NSString *)clientID; + +/** @fn initWithClientID:scopes: + @brief Designated initializer. + @param clientId The Google Sign In client ID. + @param scopes The user account scopes required by the app. + */ +- (instancetype)initWithClientID:(NSString *)clientID scopes:(NSArray *)scopes NS_DESIGNATED_INITIALIZER; @end diff --git a/FirebaseUI/Auth/AuthProviderUI/Google/Source/FIRGoogleAuthUI.m b/FirebaseUI/Auth/AuthProviderUI/Google/Source/FIRGoogleAuthUI.m index 5bc73adc637..79c3c34c896 100644 --- a/FirebaseUI/Auth/AuthProviderUI/Google/Source/FIRGoogleAuthUI.m +++ b/FirebaseUI/Auth/AuthProviderUI/Google/Source/FIRGoogleAuthUI.m @@ -60,17 +60,21 @@ @implementation FIRGoogleAuthUI { FIRAuthProviderSignInCompletionBlock _pendingSignInCallback; } -- (nullable instancetype)init { +- (instancetype)init { @throw [NSException exceptionWithName:@"Attempt to call unavailable initializer." reason:@"Please call the designated initializer." userInfo:nil]; } -- (nullable instancetype)initWithClientID:(NSString *)clientID { +- (instancetype)initWithClientID:(NSString *)clientID { + return [self initWithClientID:clientID scopes:@[@"email", @"profile"]]; +} + +- (instancetype)initWithClientID:(NSString *)clientID scopes:(NSArray *)scopes { self = [super init]; if (self) { _clientID = [clientID copy]; - _scopes = @[ @"email", @"profile" ]; + _scopes = scopes; } return self; } diff --git a/FirebaseUITests/FirebaseArrayTest.m b/FirebaseUITests/FirebaseArrayTest.m index 099ec240a11..0d187d6c8d6 100644 --- a/FirebaseUITests/FirebaseArrayTest.m +++ b/FirebaseUITests/FirebaseArrayTest.m @@ -31,6 +31,14 @@ @interface FUIDataEventHandler: NSObject @implementation FUIDataEventHandler @end +// Horrible abuse of ObjC type system, since FirebaseArray is unfortunately coupled to +// FIRDataSnapshot +@interface FUIFakeSnapshot: NSObject +@property (nonatomic, assign) NSString *key; +@end +@implementation FUIFakeSnapshot +@end + // A dummy observable so we can test this without relying on an internet connection. @interface FUITestObservable: NSObject @@ -42,14 +50,6 @@ @interface FUITestObservable: NSObject @end -// Horrible abuse of ObjC type system, since FirebaseArray is unfortunately coupled to -// FIRDataSnapshot -@interface FUIFakeSnapshot: NSObject -@property (nonatomic, assign) NSString *key; -@end -@implementation FUIFakeSnapshot -@end - @implementation FUITestObservable - (instancetype)init { From 0d01485cae18a5a78007c579fc5fd24225d6a8b1 Mon Sep 17 00:00:00 2001 From: Morgan Chen Date: Mon, 8 Aug 2016 14:55:08 -0700 Subject: [PATCH 14/28] xcode writes to xibs when they're opened aaa --- FirebaseUI/Auth/AuthUI/Source/FIRAuthPickerViewController.xib | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/FirebaseUI/Auth/AuthUI/Source/FIRAuthPickerViewController.xib b/FirebaseUI/Auth/AuthUI/Source/FIRAuthPickerViewController.xib index c69f57db814..e4cb689120c 100644 --- a/FirebaseUI/Auth/AuthUI/Source/FIRAuthPickerViewController.xib +++ b/FirebaseUI/Auth/AuthUI/Source/FIRAuthPickerViewController.xib @@ -1,7 +1,6 @@ - + - From 9d962c1e61e76fe56aa17d8019cf480a025b4bc5 Mon Sep 17 00:00:00 2001 From: Morgan Chen Date: Mon, 8 Aug 2016 15:07:32 -0700 Subject: [PATCH 15/28] rename authUI to defaultAuthUI --- FirebaseUI/Auth/AuthUI/Source/FIRAuthUI.h | 2 +- FirebaseUI/Auth/AuthUI/Source/FIRAuthUI.m | 5 +++-- FirebaseUI/Auth/AuthUI/Source/FIRAuthUIStrings.m | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/FirebaseUI/Auth/AuthUI/Source/FIRAuthUI.h b/FirebaseUI/Auth/AuthUI/Source/FIRAuthUI.h index 52d5660ddca..883db50ad83 100644 --- a/FirebaseUI/Auth/AuthUI/Source/FIRAuthUI.h +++ b/FirebaseUI/Auth/AuthUI/Source/FIRAuthUI.h @@ -67,7 +67,7 @@ typedef void (^FIRAuthUIResultCallback)(FIRUser *_Nullable user, NSError *_Nulla @brief Gets the @c FIRAuthUI object for the default FirebaseApp. @remarks Thread safe. */ -+ (nullable FIRAuthUI *)authUI NS_SWIFT_NAME(authUI()); ++ (nullable FIRAuthUI *)defaultAuthUI NS_SWIFT_NAME(authUI()); /** @fn authUIWithAuth: @brief Gets the @c FIRAuthUI instance for a @c FIRAuth. diff --git a/FirebaseUI/Auth/AuthUI/Source/FIRAuthUI.m b/FirebaseUI/Auth/AuthUI/Source/FIRAuthUI.m index c230fade4fd..c2df3ce66b8 100644 --- a/FirebaseUI/Auth/AuthUI/Source/FIRAuthUI.m +++ b/FirebaseUI/Auth/AuthUI/Source/FIRAuthUI.m @@ -45,7 +45,7 @@ - (nullable instancetype)initWithAuth:(FIRAuth *)auth NS_DESIGNATED_INITIALIZER; @implementation FIRAuthUI -+ (nullable FIRAuthUI *)authUI { ++ (nullable FIRAuthUI *)defaultAuthUI { FIRAuth *defaultAuth = [FIRAuth auth]; if (!defaultAuth) { return nil; @@ -54,6 +54,7 @@ + (nullable FIRAuthUI *)authUI { } + (nullable FIRAuthUI *)authUIWithAuth:(FIRAuth *)auth { + NSParameterAssert(auth != nil); @synchronized (self) { // Let the FIRAuth instance retain the FIRAuthUI instance. FIRAuthUI *authUI = objc_getAssociatedObject(auth, &kAuthAssociationKey); @@ -66,7 +67,7 @@ + (nullable FIRAuthUI *)authUIWithAuth:(FIRAuth *)auth { } } -- (nullable instancetype)initWithAuth:(FIRAuth *)auth { +- (instancetype)initWithAuth:(FIRAuth *)auth { self = [super init]; if (self) { _auth = auth; diff --git a/FirebaseUI/Auth/AuthUI/Source/FIRAuthUIStrings.m b/FirebaseUI/Auth/AuthUI/Source/FIRAuthUIStrings.m index 3268b63adf3..609c73a8d29 100644 --- a/FirebaseUI/Auth/AuthUI/Source/FIRAuthUIStrings.m +++ b/FirebaseUI/Auth/AuthUI/Source/FIRAuthUIStrings.m @@ -75,7 +75,7 @@ @implementation FIRAuthUIStrings @return Localized value of the string identified by the key. */ + (NSString *)localizedStringForKey:(nonnull NSString *)key { - NSBundle *customStringsBundle = [FIRAuthUI authUI].customStringsBundle; + NSBundle *customStringsBundle = [FIRAuthUI defaultAuthUI].customStringsBundle; if (customStringsBundle) { NSString *localizedString = [customStringsBundle localizedStringForKey:key value:kKeyNotFound From c7da9aef2b00a08bb1accf3fbda3a842ff5b27aa Mon Sep 17 00:00:00 2001 From: Morgan Chen Date: Mon, 8 Aug 2016 15:11:51 -0700 Subject: [PATCH 16/28] use correct google api scopes --- .../AuthProviderUI/Google/Source/FIRGoogleAuthUI.h | 6 ++++-- .../AuthProviderUI/Google/Source/FIRGoogleAuthUI.m | 14 ++++++++++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/FirebaseUI/Auth/AuthProviderUI/Google/Source/FIRGoogleAuthUI.h b/FirebaseUI/Auth/AuthProviderUI/Google/Source/FIRGoogleAuthUI.h index 4097379dd48..21e2b821660 100644 --- a/FirebaseUI/Auth/AuthProviderUI/Google/Source/FIRGoogleAuthUI.h +++ b/FirebaseUI/Auth/AuthProviderUI/Google/Source/FIRGoogleAuthUI.h @@ -32,7 +32,8 @@ NS_ASSUME_NONNULL_BEGIN /** @property scopes @brief The scopes to use with Google Sign In. - @remarks Defaults to using "email" and "profile" scopes. + @remarks Defaults to using email and profile scopes. For a list of all scopes + see https://developers.google.com/identity/protocols/googlescopes */ @property(nonatomic, copy, readonly) NSArray *scopes; @@ -51,7 +52,8 @@ NS_ASSUME_NONNULL_BEGIN /** @fn initWithClientID:scopes: @brief Designated initializer. @param clientId The Google Sign In client ID. - @param scopes The user account scopes required by the app. + @param scopes The user account scopes required by the app. A list of possible scopes can be + found at https://developers.google.com/identity/protocols/googlescopes */ - (instancetype)initWithClientID:(NSString *)clientID scopes:(NSArray *)scopes NS_DESIGNATED_INITIALIZER; diff --git a/FirebaseUI/Auth/AuthProviderUI/Google/Source/FIRGoogleAuthUI.m b/FirebaseUI/Auth/AuthProviderUI/Google/Source/FIRGoogleAuthUI.m index 79c3c34c896..2637f6d6ba7 100644 --- a/FirebaseUI/Auth/AuthProviderUI/Google/Source/FIRGoogleAuthUI.m +++ b/FirebaseUI/Auth/AuthProviderUI/Google/Source/FIRGoogleAuthUI.m @@ -31,10 +31,15 @@ */ static NSString *const kGooglePlusMeScope = @"https://www.googleapis.com/auth/plus.me"; -/** @var kGooglePlusScopesPrefix - @brief The OAuth scope string prefix for all scopes starting with "plus.". +/** @var kGooglePlusMeScope + @brief The OAuth scope string for the user's email scope. + */ +static NSString *const kGoogleUserInfoEmailScope = @"https://www.googleapis.com/auth/userinfo.email"; + +/** @var kGooglePlusMeScope + @brief The OAuth scope string for the basic G+ profile information scope. */ -static NSString *const kGooglePlusScopesPrefix = @"https://www.googleapis.com/auth/plus."; +static NSString *const kGoogleUserInfoProfileScope = @"https://www.googleapis.com/auth/userinfo.profile"; /** @var kTableName @brief The name of the strings table to search for localized strings. @@ -67,7 +72,8 @@ - (instancetype)init { } - (instancetype)initWithClientID:(NSString *)clientID { - return [self initWithClientID:clientID scopes:@[@"email", @"profile"]]; + return [self initWithClientID:clientID + scopes:@[kGoogleUserInfoEmailScope, kGoogleUserInfoProfileScope]]; } - (instancetype)initWithClientID:(NSString *)clientID scopes:(NSArray *)scopes { From e57e70b15a9c66ead895723fd4a597458f5f7aff Mon Sep 17 00:00:00 2001 From: Morgan Chen Date: Mon, 8 Aug 2016 17:48:14 -0700 Subject: [PATCH 17/28] make collection view data source test --- FirebaseUI.xcodeproj/project.pbxproj | 18 +++ .../API/FirebaseCollectionViewDataSource.h | 2 +- .../FirebaseCollectionViewDataSource.m | 14 +- FirebaseUITests/FirebaseArrayTest.m | 141 +----------------- FirebaseUITests/FirebaseArrayTestUtils.h | 60 ++++++++ FirebaseUITests/FirebaseArrayTestUtils.m | 115 ++++++++++++++ .../FirebaseCollectionViewDataSourceTest.m | 59 ++++++++ 7 files changed, 263 insertions(+), 146 deletions(-) create mode 100644 FirebaseUITests/FirebaseArrayTestUtils.h create mode 100644 FirebaseUITests/FirebaseArrayTestUtils.m create mode 100644 FirebaseUITests/FirebaseCollectionViewDataSourceTest.m diff --git a/FirebaseUI.xcodeproj/project.pbxproj b/FirebaseUI.xcodeproj/project.pbxproj index c7be7ca256d..2f38aa96381 100644 --- a/FirebaseUI.xcodeproj/project.pbxproj +++ b/FirebaseUI.xcodeproj/project.pbxproj @@ -83,6 +83,8 @@ 8621C9557B0F42B90A867731 /* libPods-FirebaseUI.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E25E2F8253FA11A3E072D265 /* libPods-FirebaseUI.a */; }; 8D2CB5E21D53F5AE0097FEEB /* libFirebaseUI.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D8C579A61B57349000899F86 /* libFirebaseUI.a */; }; 8D2CB5E91D53F5C50097FEEB /* FirebaseArrayTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D2CB5E81D53F5C50097FEEB /* FirebaseArrayTest.m */; }; + 8DD3AACA1D5940E000E6B1F9 /* FirebaseCollectionViewDataSourceTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8DD3AAC91D5940E000E6B1F9 /* FirebaseCollectionViewDataSourceTest.m */; }; + 8DD3AACD1D5942C900E6B1F9 /* FirebaseArrayTestUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 8DD3AACC1D5942C900E6B1F9 /* FirebaseArrayTestUtils.m */; }; 8DFCD1371D53FE8D00208D7B /* FIRAuthUISignInButton.h in Headers */ = {isa = PBXBuildFile; fileRef = 8DFCD1351D53FE8D00208D7B /* FIRAuthUISignInButton.h */; }; 8DFCD1381D53FE8D00208D7B /* FIRAuthUISignInButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 8DFCD1361D53FE8D00208D7B /* FIRAuthUISignInButton.m */; }; 962E1417A825A57ED7034636 /* libPods-Facebook.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 56CCA3CB9295B6E71208403F /* libPods-Facebook.a */; }; @@ -342,6 +344,9 @@ 8D2CB5E11D53F5AE0097FEEB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 8D2CB5E81D53F5C50097FEEB /* FirebaseArrayTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FirebaseArrayTest.m; sourceTree = ""; }; 8D3AA95C1D53F9C7006FC9AF /* libPods-FirebaseUI.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libPods-FirebaseUI.a"; path = "../../Library/Developer/Xcode/DerivedData/FirebaseUI-fwcyvciocjlrhqbyjmmybozelsll/Build/Products/Debug-iphonesimulator/libPods-FirebaseUI.a"; sourceTree = ""; }; + 8DD3AAC91D5940E000E6B1F9 /* FirebaseCollectionViewDataSourceTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FirebaseCollectionViewDataSourceTest.m; sourceTree = ""; }; + 8DD3AACB1D5942C900E6B1F9 /* FirebaseArrayTestUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FirebaseArrayTestUtils.h; sourceTree = ""; }; + 8DD3AACC1D5942C900E6B1F9 /* FirebaseArrayTestUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FirebaseArrayTestUtils.m; sourceTree = ""; }; 8DFCD1351D53FE8D00208D7B /* FIRAuthUISignInButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FIRAuthUISignInButton.h; sourceTree = ""; }; 8DFCD1361D53FE8D00208D7B /* FIRAuthUISignInButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRAuthUISignInButton.m; sourceTree = ""; }; B992B1D4DFBAE9C4E3453B15 /* Pods-Google.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Google.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Google/Pods-Google.debug.xcconfig"; sourceTree = ""; }; @@ -678,12 +683,23 @@ 8D2CB5DE1D53F5AE0097FEEB /* FirebaseUITests */ = { isa = PBXGroup; children = ( + 8DD3AACE1D5942D000E6B1F9 /* Helpers */, 8D2CB5E81D53F5C50097FEEB /* FirebaseArrayTest.m */, + 8DD3AAC91D5940E000E6B1F9 /* FirebaseCollectionViewDataSourceTest.m */, 8D2CB5E11D53F5AE0097FEEB /* Info.plist */, ); path = FirebaseUITests; sourceTree = ""; }; + 8DD3AACE1D5942D000E6B1F9 /* Helpers */ = { + isa = PBXGroup; + children = ( + 8DD3AACB1D5942C900E6B1F9 /* FirebaseArrayTestUtils.h */, + 8DD3AACC1D5942C900E6B1F9 /* FirebaseArrayTestUtils.m */, + ); + name = Helpers; + sourceTree = ""; + }; D8B6ACE81B5839A5005CDDB2 /* Frameworks */ = { isa = PBXGroup; children = ( @@ -1318,6 +1334,8 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 8DD3AACD1D5942C900E6B1F9 /* FirebaseArrayTestUtils.m in Sources */, + 8DD3AACA1D5940E000E6B1F9 /* FirebaseCollectionViewDataSourceTest.m in Sources */, 8D2CB5E91D53F5C50097FEEB /* FirebaseArrayTest.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/FirebaseUI/Database/API/FirebaseCollectionViewDataSource.h b/FirebaseUI/Database/API/FirebaseCollectionViewDataSource.h index c5859e5fe62..bb3941b7530 100644 --- a/FirebaseUI/Database/API/FirebaseCollectionViewDataSource.h +++ b/FirebaseUI/Database/API/FirebaseCollectionViewDataSource.h @@ -89,7 +89,7 @@ NS_ASSUME_NONNULL_BEGIN * provided by the * datasource. */ -@property(strong, nonatomic) void (^populateCell) +@property(strong, nonatomic, readonly) void (^populateCell) (__kindof UICollectionViewCell *cell, __kindof NSObject *object); /** diff --git a/FirebaseUI/Database/Implementation/FirebaseCollectionViewDataSource.m b/FirebaseUI/Database/Implementation/FirebaseCollectionViewDataSource.m index 2c64cf10116..0093f54784c 100644 --- a/FirebaseUI/Database/Implementation/FirebaseCollectionViewDataSource.m +++ b/FirebaseUI/Database/Implementation/FirebaseCollectionViewDataSource.m @@ -22,6 +22,11 @@ @import FirebaseDatabase; +@interface FirebaseCollectionViewDataSource () +@property(strong, nonatomic, readwrite) void (^populateCell) +(__kindof UICollectionViewCell *cell, __kindof NSObject *object); +@end + @implementation FirebaseCollectionViewDataSource #pragma mark - FirebaseDataSource initializer methods @@ -83,9 +88,9 @@ - (instancetype)initWithRef:(FIRDatabaseReference *)ref prototypeReuseIdentifier:(NSString *)identifier view:(UICollectionView *)collectionView { return [self initWithQuery:ref - modelClass:model - prototypeReuseIdentifier:identifier - view:collectionView]; + modelClass:model + prototypeReuseIdentifier:identifier + view:collectionView]; } - (instancetype)initWithRef:(FIRDatabaseReference *)ref @@ -198,8 +203,7 @@ - (instancetype)initWithQuery:(FIRDatabaseQuery *)query self.modelClass = model; self.cellClass = cell; self.reuseIdentifier = identifier; - self.populateCell = ^(id cell, id object) { - }; + self.populateCell = ^(id cell, id object) {}; if (!self.hasPrototypeCell) { [self.collectionView registerClass:self.cellClass diff --git a/FirebaseUITests/FirebaseArrayTest.m b/FirebaseUITests/FirebaseArrayTest.m index 0d187d6c8d6..616b358052e 100644 --- a/FirebaseUITests/FirebaseArrayTest.m +++ b/FirebaseUITests/FirebaseArrayTest.m @@ -21,146 +21,7 @@ @import XCTest; #import "FirebaseArray.h" - -// Dumb object holding a pair of blocks and a data event type. -@interface FUIDataEventHandler: NSObject -@property (nonatomic, assign) FIRDataEventType event; -@property (nonatomic, copy, nonnull) void (^success)(FIRDataSnapshot *_Nonnull, NSString *_Nullable); -@property (nonatomic, copy, nonnull) void (^cancelled)(NSError *_Nonnull); -@end -@implementation FUIDataEventHandler -@end - -// Horrible abuse of ObjC type system, since FirebaseArray is unfortunately coupled to -// FIRDataSnapshot -@interface FUIFakeSnapshot: NSObject -@property (nonatomic, assign) NSString *key; -@end -@implementation FUIFakeSnapshot -@end - -// A dummy observable so we can test this without relying on an internet connection. -@interface FUITestObservable: NSObject - -// Map of handles to observers. -@property (nonatomic, readonly) NSMutableDictionary *observers; - -// Incremented to generate unique handles. -@property (nonatomic, readonly, assign) FIRDatabaseHandle current; - -@end - -@implementation FUITestObservable - -- (instancetype)init { - self = [super init]; - if (self != nil) { - _observers = [NSMutableDictionary dictionary]; - } - return self; -} - -- (void)removeObserverWithHandle:(FIRDatabaseHandle)handle { - [self.observers removeObjectForKey:@(handle)]; -} - -- (void)removeAllObservers { - _observers = [NSMutableDictionary dictionary]; -} - -- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType - andPreviousSiblingKeyWithBlock:(void (^)(FIRDataSnapshot * _Nonnull, NSString * _Nullable))block - withCancelBlock:(void (^)(NSError * _Nonnull))cancelBlock { - FUIDataEventHandler *handler = [[FUIDataEventHandler alloc] init]; - handler.event = eventType; - handler.success = block; - handler.cancelled = cancelBlock; - - NSNumber *key = @(self.current); - _current++; - self.observers[key] = handler; - return key.unsignedIntegerValue; -} - -// Sends an event in jankiest possible way -- (void)sendEvent:(FIRDataEventType)event - withObject:(FUIFakeSnapshot *)object - previousKey:(NSString *)string - error:(NSError *)error { - NSArray *allKeys = self.observers.allKeys; - for (NSNumber *key in allKeys) { - FUIDataEventHandler *handler = self.observers[key]; - if (handler.event == event) { - if (error != nil) { handler.cancelled(error); } - else { handler.success((FIRDataSnapshot *)object, string); } - } - } -} - -// Inserts sequentially with data provided by the `generator` block. -- (void)populateWithCount:(NSUInteger)count generator:(FUIFakeSnapshot *(^)(NSUInteger))generator { - NSString *previous = nil; - for (NSUInteger i = 0; i < count; i++) { - FUIFakeSnapshot *snap = generator(i); - [self sendEvent:FIRDataEventTypeChildAdded withObject:snap previousKey:previous error:nil]; - previous = snap.key; - } -} - -// Sends a bunch of insertion events with snapshot keys as integer strings (i.e. @"0") of increasing -// order, starting from 0. -- (void)populateWithCount:(NSUInteger)count { - [self populateWithCount:count generator:^FUIFakeSnapshot *(NSUInteger index) { - FUIFakeSnapshot *snap = [[FUIFakeSnapshot alloc] init]; - snap.key = @(index).stringValue; - return snap; - }]; -} - -@end - -@interface FUIFirebaseArrayTestDelegate : NSObject -@property (nonatomic, copy) void (^queryCancelled)(FirebaseArray *array, NSError *error); -@property (nonatomic, copy) void (^didAddObject)(FirebaseArray *array, id object, NSUInteger index); -@property (nonatomic, copy) void (^didChangeObject)(FirebaseArray *array, id object, NSUInteger index); -@property (nonatomic, copy) void (^didRemoveObject)(FirebaseArray *array, id object, NSUInteger index); -@property (nonatomic, copy) void (^didMoveObject)(FirebaseArray *array, id object, NSUInteger fromIndex, NSUInteger toIndex); -@end - -@implementation FUIFirebaseArrayTestDelegate - -- (void)array:(FirebaseArray *)array didAddObject:(id)object atIndex:(NSUInteger)index { - if (self.didAddObject != NULL) { - self.didAddObject(array, object, index); - } -} - -- (void)array:(FirebaseArray *)array didChangeObject:(id)object atIndex:(NSUInteger)index { - if (self.didChangeObject != NULL) { - self.didChangeObject(array, object, index); - } -} - -- (void)array:(FirebaseArray *)array didRemoveObject:(id)object atIndex:(NSUInteger)index { - if (self.didRemoveObject != NULL) { - self.didRemoveObject(array, object, index); - } -} - -- (void)array:(FirebaseArray *)array didMoveObject:(id)object - fromIndex:(NSUInteger)fromIndex toIndex:(NSUInteger)toIndex { - if (self.didMoveObject != NULL) { - self.didMoveObject(array, object, fromIndex, toIndex); - } -} - -- (void)array:(FirebaseArray *)array queryCancelledWithError:(NSError *)error { - if (self.queryCancelled != NULL) { - self.queryCancelled(array, error); - } -} - -@end +#import "FirebaseArrayTestUtils.h" @interface FirebaseArrayTest : XCTestCase diff --git a/FirebaseUITests/FirebaseArrayTestUtils.h b/FirebaseUITests/FirebaseArrayTestUtils.h new file mode 100644 index 00000000000..292e615feba --- /dev/null +++ b/FirebaseUITests/FirebaseArrayTestUtils.h @@ -0,0 +1,60 @@ +// +// FirebaseArrayTestUtils.h +// FirebaseUI +// +// Created by Morgan Chen on 8/8/16. +// Copyright © 2016 Firebase, Inc. All rights reserved. +// + +#import "FirebaseArray.h" + +NS_ASSUME_NONNULL_BEGIN + +// Dumb object holding a pair of blocks and a data event type. +@interface FUIDataEventHandler: NSObject +@property (nonatomic, assign) FIRDataEventType event; +@property (nonatomic, copy) void (^success)(FIRDataSnapshot *_Nonnull, NSString *_Nullable); +@property (nonatomic, copy) void (^cancelled)(NSError *_Nonnull); +@end + +// Horrible abuse of ObjC type system, since FirebaseArray is unfortunately coupled to +// FIRDataSnapshot +@interface FUIFakeSnapshot: NSObject +@property (nonatomic, copy) NSString *key; +@end + +// A dummy observable so we can test this without relying on an internet connection. +@interface FUITestObservable: NSObject + +// Map of handles to observers. +@property (nonatomic, readonly) NSMutableDictionary *observers; + +// Incremented to generate unique handles. +@property (nonatomic, readonly, assign) FIRDatabaseHandle current; + +- (void)removeAllObservers; + +// Sends an event to the observable's observers. +- (void)sendEvent:(FIRDataEventType)event + withObject:(nullable FUIFakeSnapshot *)object + previousKey:(nullable NSString *)string + error:(nullable NSError *)error; + +// Inserts sequentially with data provided by the `generator` block. +- (void)populateWithCount:(NSUInteger)count generator:(FUIFakeSnapshot *(^)(NSUInteger))generator; + +// Sends a bunch of insertion events with snapshot keys as integer strings (i.e. @"0") of increasing +// order, starting from 0. +- (void)populateWithCount:(NSUInteger)count; + +@end + +@interface FUIFirebaseArrayTestDelegate : NSObject +@property (nonatomic, copy) void (^queryCancelled)(FirebaseArray *array, NSError *error); +@property (nonatomic, copy) void (^didAddObject)(FirebaseArray *array, id object, NSUInteger index); +@property (nonatomic, copy) void (^didChangeObject)(FirebaseArray *array, id object, NSUInteger index); +@property (nonatomic, copy) void (^didRemoveObject)(FirebaseArray *array, id object, NSUInteger index); +@property (nonatomic, copy) void (^didMoveObject)(FirebaseArray *array, id object, NSUInteger fromIndex, NSUInteger toIndex); +@end + +NS_ASSUME_NONNULL_END diff --git a/FirebaseUITests/FirebaseArrayTestUtils.m b/FirebaseUITests/FirebaseArrayTestUtils.m new file mode 100644 index 00000000000..d8b3bf54de5 --- /dev/null +++ b/FirebaseUITests/FirebaseArrayTestUtils.m @@ -0,0 +1,115 @@ +// +// FirebaseArrayTestUtils.m +// FirebaseUI +// +// Created by Morgan Chen on 8/8/16. +// Copyright © 2016 Firebase, Inc. All rights reserved. +// + +#import "FirebaseArrayTestUtils.h" + +@implementation FUIDataEventHandler +@end + +@implementation FUIFakeSnapshot +@end + +@implementation FUITestObservable + +- (instancetype)init { + self = [super init]; + if (self != nil) { + _observers = [NSMutableDictionary dictionary]; + } + return self; +} + +- (void)removeObserverWithHandle:(FIRDatabaseHandle)handle { + [self.observers removeObjectForKey:@(handle)]; +} + +- (void)removeAllObservers { + _observers = [NSMutableDictionary dictionary]; +} + +- (FIRDatabaseHandle)observeEventType:(FIRDataEventType)eventType + andPreviousSiblingKeyWithBlock:(void (^)(FIRDataSnapshot * _Nonnull, NSString * _Nullable))block + withCancelBlock:(void (^)(NSError * _Nonnull))cancelBlock { + FUIDataEventHandler *handler = [[FUIDataEventHandler alloc] init]; + handler.event = eventType; + handler.success = block; + handler.cancelled = cancelBlock; + + NSNumber *key = @(self.current); + _current++; + self.observers[key] = handler; + return key.unsignedIntegerValue; +} + +- (void)sendEvent:(FIRDataEventType)event + withObject:(FUIFakeSnapshot *)object + previousKey:(NSString *)string + error:(NSError *)error { + NSArray *allKeys = self.observers.allKeys; + for (NSNumber *key in allKeys) { + FUIDataEventHandler *handler = self.observers[key]; + if (handler.event == event) { + if (error != nil) { handler.cancelled(error); } + else { handler.success((FIRDataSnapshot *)object, string); } + } + } +} + +- (void)populateWithCount:(NSUInteger)count generator:(FUIFakeSnapshot *(^)(NSUInteger))generator { + NSString *previous = nil; + for (NSUInteger i = 0; i < count; i++) { + FUIFakeSnapshot *snap = generator(i); + [self sendEvent:FIRDataEventTypeChildAdded withObject:snap previousKey:previous error:nil]; + previous = snap.key; + } +} + +- (void)populateWithCount:(NSUInteger)count { + [self populateWithCount:count generator:^FUIFakeSnapshot *(NSUInteger index) { + FUIFakeSnapshot *snap = [[FUIFakeSnapshot alloc] init]; + snap.key = @(index).stringValue; + return snap; + }]; +} + +@end + +@implementation FUIFirebaseArrayTestDelegate + +- (void)array:(FirebaseArray *)array didAddObject:(id)object atIndex:(NSUInteger)index { + if (self.didAddObject != NULL) { + self.didAddObject(array, object, index); + } +} + +- (void)array:(FirebaseArray *)array didChangeObject:(id)object atIndex:(NSUInteger)index { + if (self.didChangeObject != NULL) { + self.didChangeObject(array, object, index); + } +} + +- (void)array:(FirebaseArray *)array didRemoveObject:(id)object atIndex:(NSUInteger)index { + if (self.didRemoveObject != NULL) { + self.didRemoveObject(array, object, index); + } +} + +- (void)array:(FirebaseArray *)array didMoveObject:(id)object + fromIndex:(NSUInteger)fromIndex toIndex:(NSUInteger)toIndex { + if (self.didMoveObject != NULL) { + self.didMoveObject(array, object, fromIndex, toIndex); + } +} + +- (void)array:(FirebaseArray *)array queryCancelledWithError:(NSError *)error { + if (self.queryCancelled != NULL) { + self.queryCancelled(array, error); + } +} + +@end diff --git a/FirebaseUITests/FirebaseCollectionViewDataSourceTest.m b/FirebaseUITests/FirebaseCollectionViewDataSourceTest.m new file mode 100644 index 00000000000..27621807368 --- /dev/null +++ b/FirebaseUITests/FirebaseCollectionViewDataSourceTest.m @@ -0,0 +1,59 @@ +// clang-format off + +// +// Copyright (c) 2016 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// clang-format on + +@import XCTest; + +#import "FirebaseCollectionViewDataSource.h" +#import "FirebaseArrayTestUtils.h" + +static NSString *const kTestReuseIdentifier = @"FirebaseCollectionViewDataSourceTest"; + +@interface FirebaseCollectionViewDataSourceTest : XCTestCase +@property (nonatomic) UICollectionView *collectionView; +@property (nonatomic) FUITestObservable *observable; +@property (nonatomic) FirebaseCollectionViewDataSource *dataSource; +@end + +@implementation FirebaseCollectionViewDataSourceTest + +- (void)setUp { + [super setUp]; + self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero + collectionViewLayout:[[UICollectionViewFlowLayout alloc] init]]; + [self.collectionView registerClass:[UICollectionViewCell class] + forCellWithReuseIdentifier:kTestReuseIdentifier]; + self.observable = [[FUITestObservable alloc] init]; + self.dataSource = [[FirebaseCollectionViewDataSource alloc] initWithRef:(FIRDatabaseReference *)self.observable + cellReuseIdentifier:kTestReuseIdentifier + // no really nil is ok + view:(UICollectionView *_Nonnull)nil]; + [self.observable populateWithCount:10]; +} + +- (void)tearDown { + [super tearDown]; +} + +- (void)testItHasACount { + NSUInteger count = self.dataSource.count; + XCTAssert(count == 10, @"expected data source to have 10 elements after 10 insertions, but got %lu", count); +} + +@end From bca666a60925838906051ff4a3b42da7532c2c5c Mon Sep 17 00:00:00 2001 From: Morgan Chen Date: Tue, 9 Aug 2016 10:50:17 -0700 Subject: [PATCH 18/28] clean up comments and whitespace; get rid of bad swift name --- FirebaseUI/Auth/AuthUI/Source/FIRAuthUI.h | 2 +- .../Database/Implementation/FirebaseArray.m | 4 ++-- .../FirebaseCollectionViewDataSource.m | 8 ++++---- .../FirebaseTableViewDataSource.m | 3 ++- FirebaseUITests/FirebaseArrayTestUtils.h | 20 +++++++++++++++---- FirebaseUITests/FirebaseArrayTestUtils.m | 20 +++++++++++++++---- .../FirebaseCollectionViewDataSourceTest.m | 6 +++++- 7 files changed, 46 insertions(+), 17 deletions(-) diff --git a/FirebaseUI/Auth/AuthUI/Source/FIRAuthUI.h b/FirebaseUI/Auth/AuthUI/Source/FIRAuthUI.h index 883db50ad83..5e2c774c527 100644 --- a/FirebaseUI/Auth/AuthUI/Source/FIRAuthUI.h +++ b/FirebaseUI/Auth/AuthUI/Source/FIRAuthUI.h @@ -67,7 +67,7 @@ typedef void (^FIRAuthUIResultCallback)(FIRUser *_Nullable user, NSError *_Nulla @brief Gets the @c FIRAuthUI object for the default FirebaseApp. @remarks Thread safe. */ -+ (nullable FIRAuthUI *)defaultAuthUI NS_SWIFT_NAME(authUI()); ++ (nullable FIRAuthUI *)defaultAuthUI; /** @fn authUIWithAuth: @brief Gets the @c FIRAuthUI instance for a @c FIRAuth. diff --git a/FirebaseUI/Database/Implementation/FirebaseArray.m b/FirebaseUI/Database/Implementation/FirebaseArray.m index be02a2af300..a56ff4ed53d 100755 --- a/FirebaseUI/Database/Implementation/FirebaseArray.m +++ b/FirebaseUI/Database/Implementation/FirebaseArray.m @@ -23,9 +23,9 @@ @interface FirebaseArray () /** - * The delegate object that array changes are surfaced to. + * The backing collection that holds all of the FirebaseArray's data. */ -@property(strong, nonatomic) NSMutableArray * snapshots; +@property(strong, nonatomic) NSMutableArray *snapshots; /** * A set containing the query observer handles that should be released when diff --git a/FirebaseUI/Database/Implementation/FirebaseCollectionViewDataSource.m b/FirebaseUI/Database/Implementation/FirebaseCollectionViewDataSource.m index 0093f54784c..66ffb5fe2df 100644 --- a/FirebaseUI/Database/Implementation/FirebaseCollectionViewDataSource.m +++ b/FirebaseUI/Database/Implementation/FirebaseCollectionViewDataSource.m @@ -254,7 +254,8 @@ - (void)array:(FirebaseArray *)array didRemoveObject:(id)object atIndex:(NSUInte deleteItemsAtIndexPaths:@[ [NSIndexPath indexPathForRow:index inSection:0] ]]; } -- (void)array:(FirebaseArray *)array didMoveObject:(id)object fromIndex:(NSUInteger)fromIndex toIndex:(NSUInteger)toIndex { +- (void)array:(FirebaseArray *)array didMoveObject:(id)object + fromIndex:(NSUInteger)fromIndex toIndex:(NSUInteger)toIndex { [self.collectionView moveItemAtIndexPath:[NSIndexPath indexPathForRow:fromIndex inSection:0] toIndexPath:[NSIndexPath indexPathForRow:toIndex inSection:0]]; } @@ -289,9 +290,8 @@ - (NSInteger)collectionView:(nonnull UICollectionView *)collectionView return self.count; } -- (void)populateCellWithBlock: - (void (^)(__kindof UICollectionViewCell *cell, - __kindof NSObject *object))callback { +- (void)populateCellWithBlock:(void (^)(__kindof UICollectionViewCell *cell, + __kindof NSObject *object))callback { self.populateCell = callback; } diff --git a/FirebaseUI/Database/Implementation/FirebaseTableViewDataSource.m b/FirebaseUI/Database/Implementation/FirebaseTableViewDataSource.m index 7ad21c7e8dc..c37c5e0f367 100644 --- a/FirebaseUI/Database/Implementation/FirebaseTableViewDataSource.m +++ b/FirebaseUI/Database/Implementation/FirebaseTableViewDataSource.m @@ -258,7 +258,8 @@ - (void)array:(FirebaseArray *)array didRemoveObject:(id)object atIndex:(NSUInte [self.tableView endUpdates]; } -- (void)array:(FirebaseArray *)array didMoveObject:(id)object fromIndex:(NSUInteger)fromIndex toIndex:(NSUInteger)toIndex { +- (void)array:(FirebaseArray *)array didMoveObject:(id)object + fromIndex:(NSUInteger)fromIndex toIndex:(NSUInteger)toIndex { [self.tableView beginUpdates]; [self.tableView moveRowAtIndexPath:[NSIndexPath indexPathForRow:fromIndex inSection:0] toIndexPath:[NSIndexPath indexPathForRow:toIndex inSection:0]]; diff --git a/FirebaseUITests/FirebaseArrayTestUtils.h b/FirebaseUITests/FirebaseArrayTestUtils.h index 292e615feba..dab91f5b60f 100644 --- a/FirebaseUITests/FirebaseArrayTestUtils.h +++ b/FirebaseUITests/FirebaseArrayTestUtils.h @@ -1,10 +1,22 @@ +// clang-format off + +// +// Copyright (c) 2016 Google Inc. // -// FirebaseArrayTestUtils.h -// FirebaseUI +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // -// Created by Morgan Chen on 8/8/16. -// Copyright © 2016 Firebase, Inc. All rights reserved. +// http://www.apache.org/licenses/LICENSE-2.0 // +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// clang-format on #import "FirebaseArray.h" diff --git a/FirebaseUITests/FirebaseArrayTestUtils.m b/FirebaseUITests/FirebaseArrayTestUtils.m index d8b3bf54de5..9ce2a95c276 100644 --- a/FirebaseUITests/FirebaseArrayTestUtils.m +++ b/FirebaseUITests/FirebaseArrayTestUtils.m @@ -1,10 +1,22 @@ +// clang-format off + +// +// Copyright (c) 2016 Google Inc. // -// FirebaseArrayTestUtils.m -// FirebaseUI +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at // -// Created by Morgan Chen on 8/8/16. -// Copyright © 2016 Firebase, Inc. All rights reserved. +// http://www.apache.org/licenses/LICENSE-2.0 // +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// clang-format on #import "FirebaseArrayTestUtils.h" diff --git a/FirebaseUITests/FirebaseCollectionViewDataSourceTest.m b/FirebaseUITests/FirebaseCollectionViewDataSourceTest.m index 27621807368..2768a15ae3c 100644 --- a/FirebaseUITests/FirebaseCollectionViewDataSourceTest.m +++ b/FirebaseUITests/FirebaseCollectionViewDataSourceTest.m @@ -40,9 +40,13 @@ - (void)setUp { [self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:kTestReuseIdentifier]; self.observable = [[FUITestObservable alloc] init]; + // Horrible abuse of type system, knowing that the initializer passes the observable straight to + // FirebaseArray anyway. self.dataSource = [[FirebaseCollectionViewDataSource alloc] initWithRef:(FIRDatabaseReference *)self.observable cellReuseIdentifier:kTestReuseIdentifier - // no really nil is ok + // no really nil is ok. + // using nil here because UICollectionView + // gets unhappy sometimes view:(UICollectionView *_Nonnull)nil]; [self.observable populateWithCount:10]; } From 82383bff73cbb8666b62da5f91cf264d15048627 Mon Sep 17 00:00:00 2001 From: Morgan Chen Date: Tue, 9 Aug 2016 14:44:28 -0700 Subject: [PATCH 19/28] try to use actual collection view in tests, breaking everything --- FirebaseUI/Database/API/FirebaseDataSource.h | 8 +-- .../FirebaseCollectionViewDataSource.m | 17 +++--- .../Implementation/FirebaseDataSource.m | 4 ++ FirebaseUITests/FirebaseArrayTest.m | 1 - .../FirebaseCollectionViewDataSourceTest.m | 61 +++++++++++++++++-- 5 files changed, 72 insertions(+), 19 deletions(-) diff --git a/FirebaseUI/Database/API/FirebaseDataSource.h b/FirebaseUI/Database/API/FirebaseDataSource.h index 944ef977ac4..4bc5d19cb34 100644 --- a/FirebaseUI/Database/API/FirebaseDataSource.h +++ b/FirebaseUI/Database/API/FirebaseDataSource.h @@ -39,13 +39,13 @@ */ @property (nonatomic, readonly, copy) NSArray *items; -- (instancetype)initWithArray:(FirebaseArray *)array NS_DESIGNATED_INITIALIZER; -- (instancetype)init NS_UNAVAILABLE; - /** * Pass through of [FirebaseArray count]. */ -- (NSUInteger)count; +@property (nonatomic, readonly) NSUInteger count; + +- (instancetype)initWithArray:(FirebaseArray *)array NS_DESIGNATED_INITIALIZER; +- (instancetype)init NS_UNAVAILABLE; /** * Pass through of [FirebaseArray objectAtIndex:]. diff --git a/FirebaseUI/Database/Implementation/FirebaseCollectionViewDataSource.m b/FirebaseUI/Database/Implementation/FirebaseCollectionViewDataSource.m index 66ffb5fe2df..802fa0c5bc1 100644 --- a/FirebaseUI/Database/Implementation/FirebaseCollectionViewDataSource.m +++ b/FirebaseUI/Database/Implementation/FirebaseCollectionViewDataSource.m @@ -228,8 +228,7 @@ - (instancetype)initWithQuery:(FIRDatabaseQuery *)query self.collectionView = collectionView; self.modelClass = model; self.reuseIdentifier = identifier; - self.populateCell = ^(id cell, id object) { - }; + self.populateCell = ^(id cell, id object) {}; UINib *nib = [UINib nibWithNibName:nibName bundle:nil]; [self.collectionView registerNib:nib forCellWithReuseIdentifier:self.reuseIdentifier]; @@ -240,24 +239,24 @@ - (instancetype)initWithQuery:(FIRDatabaseQuery *)query #pragma mark - FirebaseArrayDelegate methods - (void)array:(FirebaseArray *)array didAddObject:(id)object atIndex:(NSUInteger)index { - [self.collectionView - insertItemsAtIndexPaths:@[ [NSIndexPath indexPathForItem:index inSection:0] ]]; +// [self.collectionView +// insertItemsAtIndexPaths:@[ [NSIndexPath indexPathForItem:index inSection:0] ]]; } - (void)array:(FirebaseArray *)array didChangeObject:(id)object atIndex:(NSUInteger)index { [self.collectionView - reloadItemsAtIndexPaths:@[ [NSIndexPath indexPathForRow:index inSection:0] ]]; + reloadItemsAtIndexPaths:@[ [NSIndexPath indexPathForItem:index inSection:0] ]]; } - (void)array:(FirebaseArray *)array didRemoveObject:(id)object atIndex:(NSUInteger)index { - [self.collectionView - deleteItemsAtIndexPaths:@[ [NSIndexPath indexPathForRow:index inSection:0] ]]; +// [self.collectionView +// deleteItemsAtIndexPaths:@[ [NSIndexPath indexPathForItem:index inSection:0] ]]; } - (void)array:(FirebaseArray *)array didMoveObject:(id)object fromIndex:(NSUInteger)fromIndex toIndex:(NSUInteger)toIndex { - [self.collectionView moveItemAtIndexPath:[NSIndexPath indexPathForRow:fromIndex inSection:0] - toIndexPath:[NSIndexPath indexPathForRow:toIndex inSection:0]]; + [self.collectionView moveItemAtIndexPath:[NSIndexPath indexPathForItem:fromIndex inSection:0] + toIndexPath:[NSIndexPath indexPathForItem:toIndex inSection:0]]; } #pragma mark - UICollectionViewDataSource methods diff --git a/FirebaseUI/Database/Implementation/FirebaseDataSource.m b/FirebaseUI/Database/Implementation/FirebaseDataSource.m index 14af53cb585..6feb466041e 100644 --- a/FirebaseUI/Database/Implementation/FirebaseDataSource.m +++ b/FirebaseUI/Database/Implementation/FirebaseDataSource.m @@ -46,6 +46,10 @@ - (instancetype)initWithArray:(FirebaseArray *)array { #pragma mark - API methods +- (NSArray *)items { + return [self.array.items copy]; +} + - (NSUInteger)count { return self.array.count; } diff --git a/FirebaseUITests/FirebaseArrayTest.m b/FirebaseUITests/FirebaseArrayTest.m index 616b358052e..b8274ee1501 100644 --- a/FirebaseUITests/FirebaseArrayTest.m +++ b/FirebaseUITests/FirebaseArrayTest.m @@ -225,7 +225,6 @@ - (void)testFirebaseCanInsertIntoArrayWithDuplicates { // previous sibling, this series of insertions will produce // unexpected results. snap.key = ((i % 3 == 0) ? @"1" : @"0"); - NSLog(@"index: %lu, key: %@", i, snap.key); return snap; }]; self.snap.key = @"1"; diff --git a/FirebaseUITests/FirebaseCollectionViewDataSourceTest.m b/FirebaseUITests/FirebaseCollectionViewDataSourceTest.m index 2768a15ae3c..4957e447994 100644 --- a/FirebaseUITests/FirebaseCollectionViewDataSourceTest.m +++ b/FirebaseUITests/FirebaseCollectionViewDataSourceTest.m @@ -35,29 +35,80 @@ @implementation FirebaseCollectionViewDataSourceTest - (void)setUp { [super setUp]; - self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero + [UIView setAnimationsEnabled:NO]; + self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, 100, 100) collectionViewLayout:[[UICollectionViewFlowLayout alloc] init]]; [self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:kTestReuseIdentifier]; + self.observable = [[FUITestObservable alloc] init]; // Horrible abuse of type system, knowing that the initializer passes the observable straight to // FirebaseArray anyway. self.dataSource = [[FirebaseCollectionViewDataSource alloc] initWithRef:(FIRDatabaseReference *)self.observable cellReuseIdentifier:kTestReuseIdentifier - // no really nil is ok. - // using nil here because UICollectionView - // gets unhappy sometimes - view:(UICollectionView *_Nonnull)nil]; + view:self.collectionView]; + [self.dataSource populateCellWithBlock:^(__kindof UICollectionViewCell *_Nonnull cell, + FUIFakeSnapshot * _Nonnull object) { + cell.accessibilityValue = object.key; + }]; + [self.observable populateWithCount:10]; + self.collectionView.dataSource = self.dataSource; } - (void)tearDown { [super tearDown]; + [self.observable removeAllObservers]; + [UIView setAnimationsEnabled:YES]; } - (void)testItHasACount { NSUInteger count = self.dataSource.count; + NSUInteger collectionViewCount = [self.collectionView numberOfItemsInSection:0]; + XCTAssert(collectionViewCount == 10, + @"expected collection view to have 10 elements after 10 insertions, but got %lu", collectionViewCount); XCTAssert(count == 10, @"expected data source to have 10 elements after 10 insertions, but got %lu", count); } +- (void)testItPopulatesCells { + UICollectionViewCell *cell = [self.dataSource collectionView:self.collectionView + cellForItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]]; + XCTAssert([cell.accessibilityValue isEqualToString:@"0"], + @"expected cellForItemAtIndexPath to populate accessibility label with value '0', \ + but instead got %@", cell.accessibilityValue); + + cell = [self.dataSource collectionView:self.collectionView + cellForItemAtIndexPath:[NSIndexPath indexPathForItem:5 inSection:0]]; + XCTAssert([cell.accessibilityValue isEqualToString:@"5"], + @"expected cellForItemAtIndexPath to populate accessibility label with value '5', \ + but instead got %@", cell.accessibilityValue); + + cell = [self.dataSource collectionView:self.collectionView + cellForItemAtIndexPath:[NSIndexPath indexPathForItem:9 inSection:0]]; + XCTAssert([cell.accessibilityValue isEqualToString:@"9"], + @"expected cellForItemAtIndexPath to populate accessibility label with value '9', \ + but instead got %@", cell.accessibilityValue); +} + +- (void)testItDeletesCells { + FUIFakeSnapshot *snap = [[FUIFakeSnapshot alloc] init]; + snap.key = @"0"; + [self.observable sendEvent:FIRDataEventTypeChildRemoved withObject:snap previousKey:nil error:nil]; + UICollectionViewCell *cell = [self.dataSource collectionView:self.collectionView + cellForItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]]; + XCTAssert([cell.accessibilityValue isEqualToString:@"1"], @"expected element with previous index 1 \ + to be zeroth after deletion of zeroth element, but got %@", cell.accessibilityValue); +} + +- (void)testItMovesCells { + FUIFakeSnapshot *snap = [[FUIFakeSnapshot alloc] init]; + snap.key = @"5"; + [self.observable sendEvent:FIRDataEventTypeChildMoved withObject:snap previousKey:@"3" error:nil]; + UICollectionViewCell *cell = [self.dataSource collectionView:self.collectionView + cellForItemAtIndexPath:[NSIndexPath indexPathForItem:4 inSection:0]]; + + XCTAssert([cell.accessibilityValue isEqualToString:@"5"], @"expected element with index 5 to move to index 4, \ + found %@ at index 4 instead", cell.accessibilityValue); +} + @end From b7488f98ccf1b8d7b7f554939cd7d270ba96dcad Mon Sep 17 00:00:00 2001 From: Morgan Chen Date: Wed, 10 Aug 2016 11:30:53 -0700 Subject: [PATCH 20/28] fix crash bug in tests --- .../Implementation/FirebaseCollectionViewDataSource.m | 8 ++++---- FirebaseUITests/FirebaseCollectionViewDataSourceTest.m | 9 +++++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/FirebaseUI/Database/Implementation/FirebaseCollectionViewDataSource.m b/FirebaseUI/Database/Implementation/FirebaseCollectionViewDataSource.m index 802fa0c5bc1..2b43e3969b1 100644 --- a/FirebaseUI/Database/Implementation/FirebaseCollectionViewDataSource.m +++ b/FirebaseUI/Database/Implementation/FirebaseCollectionViewDataSource.m @@ -239,8 +239,8 @@ - (instancetype)initWithQuery:(FIRDatabaseQuery *)query #pragma mark - FirebaseArrayDelegate methods - (void)array:(FirebaseArray *)array didAddObject:(id)object atIndex:(NSUInteger)index { -// [self.collectionView -// insertItemsAtIndexPaths:@[ [NSIndexPath indexPathForItem:index inSection:0] ]]; + [self.collectionView + insertItemsAtIndexPaths:@[ [NSIndexPath indexPathForItem:index inSection:0] ]]; } - (void)array:(FirebaseArray *)array didChangeObject:(id)object atIndex:(NSUInteger)index { @@ -249,8 +249,8 @@ - (void)array:(FirebaseArray *)array didChangeObject:(id)object atIndex:(NSUInte } - (void)array:(FirebaseArray *)array didRemoveObject:(id)object atIndex:(NSUInteger)index { -// [self.collectionView -// deleteItemsAtIndexPaths:@[ [NSIndexPath indexPathForItem:index inSection:0] ]]; + [self.collectionView + deleteItemsAtIndexPaths:@[ [NSIndexPath indexPathForItem:index inSection:0] ]]; } - (void)array:(FirebaseArray *)array didMoveObject:(id)object diff --git a/FirebaseUITests/FirebaseCollectionViewDataSourceTest.m b/FirebaseUITests/FirebaseCollectionViewDataSourceTest.m index 4957e447994..0763f410716 100644 --- a/FirebaseUITests/FirebaseCollectionViewDataSourceTest.m +++ b/FirebaseUITests/FirebaseCollectionViewDataSourceTest.m @@ -51,9 +51,13 @@ - (void)setUp { FUIFakeSnapshot * _Nonnull object) { cell.accessibilityValue = object.key; }]; + self.collectionView.dataSource = self.dataSource; + + // Removing this NSLog causes the tests to crash since `numberOfItemsInSection` + // actually pulls updates from the data source or something + NSLog(@"count: %lu", [self.collectionView numberOfItemsInSection:0]); [self.observable populateWithCount:10]; - self.collectionView.dataSource = self.dataSource; } - (void)tearDown { @@ -64,9 +68,6 @@ - (void)tearDown { - (void)testItHasACount { NSUInteger count = self.dataSource.count; - NSUInteger collectionViewCount = [self.collectionView numberOfItemsInSection:0]; - XCTAssert(collectionViewCount == 10, - @"expected collection view to have 10 elements after 10 insertions, but got %lu", collectionViewCount); XCTAssert(count == 10, @"expected data source to have 10 elements after 10 insertions, but got %lu", count); } From 577a3d7b287d7dd91f1f349836a2094d23dbd57e Mon Sep 17 00:00:00 2001 From: Morgan Chen Date: Wed, 10 Aug 2016 11:47:24 -0700 Subject: [PATCH 21/28] add table view data source tests --- FirebaseUI.xcodeproj/project.pbxproj | 4 + .../FirebaseTableViewDataSourceTest.m | 104 ++++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 FirebaseUITests/FirebaseTableViewDataSourceTest.m diff --git a/FirebaseUI.xcodeproj/project.pbxproj b/FirebaseUI.xcodeproj/project.pbxproj index 2f38aa96381..f6c7802276c 100644 --- a/FirebaseUI.xcodeproj/project.pbxproj +++ b/FirebaseUI.xcodeproj/project.pbxproj @@ -85,6 +85,7 @@ 8D2CB5E91D53F5C50097FEEB /* FirebaseArrayTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D2CB5E81D53F5C50097FEEB /* FirebaseArrayTest.m */; }; 8DD3AACA1D5940E000E6B1F9 /* FirebaseCollectionViewDataSourceTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8DD3AAC91D5940E000E6B1F9 /* FirebaseCollectionViewDataSourceTest.m */; }; 8DD3AACD1D5942C900E6B1F9 /* FirebaseArrayTestUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 8DD3AACC1D5942C900E6B1F9 /* FirebaseArrayTestUtils.m */; }; + 8DD498F41D5BAAA30022D37E /* FirebaseTableViewDataSourceTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8DD498F31D5BAAA30022D37E /* FirebaseTableViewDataSourceTest.m */; }; 8DFCD1371D53FE8D00208D7B /* FIRAuthUISignInButton.h in Headers */ = {isa = PBXBuildFile; fileRef = 8DFCD1351D53FE8D00208D7B /* FIRAuthUISignInButton.h */; }; 8DFCD1381D53FE8D00208D7B /* FIRAuthUISignInButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 8DFCD1361D53FE8D00208D7B /* FIRAuthUISignInButton.m */; }; 962E1417A825A57ED7034636 /* libPods-Facebook.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 56CCA3CB9295B6E71208403F /* libPods-Facebook.a */; }; @@ -347,6 +348,7 @@ 8DD3AAC91D5940E000E6B1F9 /* FirebaseCollectionViewDataSourceTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FirebaseCollectionViewDataSourceTest.m; sourceTree = ""; }; 8DD3AACB1D5942C900E6B1F9 /* FirebaseArrayTestUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FirebaseArrayTestUtils.h; sourceTree = ""; }; 8DD3AACC1D5942C900E6B1F9 /* FirebaseArrayTestUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FirebaseArrayTestUtils.m; sourceTree = ""; }; + 8DD498F31D5BAAA30022D37E /* FirebaseTableViewDataSourceTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FirebaseTableViewDataSourceTest.m; sourceTree = ""; }; 8DFCD1351D53FE8D00208D7B /* FIRAuthUISignInButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FIRAuthUISignInButton.h; sourceTree = ""; }; 8DFCD1361D53FE8D00208D7B /* FIRAuthUISignInButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRAuthUISignInButton.m; sourceTree = ""; }; B992B1D4DFBAE9C4E3453B15 /* Pods-Google.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Google.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Google/Pods-Google.debug.xcconfig"; sourceTree = ""; }; @@ -686,6 +688,7 @@ 8DD3AACE1D5942D000E6B1F9 /* Helpers */, 8D2CB5E81D53F5C50097FEEB /* FirebaseArrayTest.m */, 8DD3AAC91D5940E000E6B1F9 /* FirebaseCollectionViewDataSourceTest.m */, + 8DD498F31D5BAAA30022D37E /* FirebaseTableViewDataSourceTest.m */, 8D2CB5E11D53F5AE0097FEEB /* Info.plist */, ); path = FirebaseUITests; @@ -1335,6 +1338,7 @@ buildActionMask = 2147483647; files = ( 8DD3AACD1D5942C900E6B1F9 /* FirebaseArrayTestUtils.m in Sources */, + 8DD498F41D5BAAA30022D37E /* FirebaseTableViewDataSourceTest.m in Sources */, 8DD3AACA1D5940E000E6B1F9 /* FirebaseCollectionViewDataSourceTest.m in Sources */, 8D2CB5E91D53F5C50097FEEB /* FirebaseArrayTest.m in Sources */, ); diff --git a/FirebaseUITests/FirebaseTableViewDataSourceTest.m b/FirebaseUITests/FirebaseTableViewDataSourceTest.m new file mode 100644 index 00000000000..aa9e73966b8 --- /dev/null +++ b/FirebaseUITests/FirebaseTableViewDataSourceTest.m @@ -0,0 +1,104 @@ +// clang-format off + +// +// Copyright (c) 2016 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// clang-format on + +@import XCTest; + +#import "FirebaseTableViewDataSource.h" +#import "FirebaseArrayTestUtils.h" + +static NSString *const kTestReuseIdentifier = @"FirebaseTableViewDataSourceTest"; + +@interface FirebaseTableViewDataSourceTest : XCTestCase +@property (nonatomic) UITableView *tableView; +@property (nonatomic) FUITestObservable *observable; +@property (nonatomic) FirebaseTableViewDataSource *dataSource; +@end + +@implementation FirebaseTableViewDataSourceTest + +- (void)setUp { + [super setUp]; + [UIView setAnimationsEnabled:NO]; + self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 100, 100) + style:UITableViewStylePlain]; + [self.tableView registerClass:[UITableViewCell class] + forCellReuseIdentifier:kTestReuseIdentifier]; + + self.observable = [[FUITestObservable alloc] init]; + // Horrible abuse of type system, knowing that the initializer passes the observable straight to + // FirebaseArray anyway. + self.dataSource = [[FirebaseTableViewDataSource alloc] initWithRef:(FIRDatabaseReference *)self.observable + cellReuseIdentifier:kTestReuseIdentifier + view:self.tableView]; + [self.dataSource populateCellWithBlock:^(__kindof UITableViewCell *_Nonnull cell, + FUIFakeSnapshot * _Nonnull object) { + cell.accessibilityValue = object.key; + }]; + self.tableView.dataSource = self.dataSource; + + [self.observable populateWithCount:10]; +} + +- (void)tearDown { + [super tearDown]; + [self.observable removeAllObservers]; + [UIView setAnimationsEnabled:YES]; +} + +- (void)testItHasACount { + NSUInteger count = self.dataSource.count; + XCTAssert(count == 10, @"expected data source to have 10 elements after 10 insertions, but got %lu", count); +} + +- (void)testItPopulatesCells { + UITableViewCell *cell = [self.dataSource tableView:self.tableView + cellForRowAtIndexPath:[NSIndexPath indexPathForRow:5 inSection:0]]; + + XCTAssert([cell.accessibilityValue isEqualToString:@"5"], @"expected cell to have accessibility label \ + equal to its indexpath row (5), but instead got %@", cell.accessibilityValue); +} + +- (void)testItInsertsCells { + FUIFakeSnapshot *snap = [[FUIFakeSnapshot alloc] init]; + snap.key = @"inserted"; + [self.observable sendEvent:FIRDataEventTypeChildAdded withObject:snap previousKey:@"9" error:nil]; + + UITableViewCell *cell = [self.dataSource tableView:self.tableView + cellForRowAtIndexPath:[NSIndexPath indexPathForRow:10 inSection:0]]; + XCTAssert([cell.accessibilityValue isEqualToString:snap.key], @"expected inserted element to be last \ + cell in table view, instead got %@", cell.accessibilityValue); +} + +- (void)testItDeletesCells { + FUIFakeSnapshot *snap = [[FUIFakeSnapshot alloc] init]; + snap.key = @"9"; + [self.observable sendEvent:FIRDataEventTypeChildRemoved withObject:snap previousKey:@"8" error:nil]; + + UITableViewCell *cell = [self.dataSource tableView:self.tableView + cellForRowAtIndexPath:[NSIndexPath indexPathForRow:8 inSection:0]]; + XCTAssert([cell.accessibilityValue isEqualToString:@"8"], @"expected second-to-last element to be last \ + after deletion of last element, instead got %@", cell.accessibilityValue); + XCTAssert(self.dataSource.count == 9, @"expected 10-element data source to have 9 elements after deletion, \ + instead got %lu", self.dataSource.count); +} + +// TODO: add tests for moving and modifying elements + +@end From 89efa98cdfa8e15856fb699cc2d9498ffeef4be3 Mon Sep 17 00:00:00 2001 From: Morgan Chen Date: Wed, 10 Aug 2016 15:19:26 -0700 Subject: [PATCH 22/28] use accessors in init --- FirebaseUI/Database/Implementation/FirebaseArray.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/FirebaseUI/Database/Implementation/FirebaseArray.m b/FirebaseUI/Database/Implementation/FirebaseArray.m index a56ff4ed53d..c63bb51f461 100755 --- a/FirebaseUI/Database/Implementation/FirebaseArray.m +++ b/FirebaseUI/Database/Implementation/FirebaseArray.m @@ -45,9 +45,9 @@ - (instancetype)initWithQuery:(FIRDatabaseQuery *)query { NSParameterAssert(query != nil); self = [super init]; if (self) { - _snapshots = [NSMutableArray array]; - _query = query; - _handles = [NSMutableSet setWithCapacity:4]; + self.snapshots = [NSMutableArray array]; + self.query = query; + self.handles = [NSMutableSet setWithCapacity:4]; [self initListeners]; } From 1be8364fceb2b74f36a4e82db8d1892f1d612efc Mon Sep 17 00:00:00 2001 From: Morgan Chen Date: Thu, 11 Aug 2016 11:03:52 -0700 Subject: [PATCH 23/28] don't test duplicate keys, use snapshot values in tests --- FirebaseUITests/FirebaseArrayTest.m | 77 ++---------------------- FirebaseUITests/FirebaseArrayTestUtils.h | 8 ++- FirebaseUITests/FirebaseArrayTestUtils.m | 20 ++++-- 3 files changed, 24 insertions(+), 81 deletions(-) diff --git a/FirebaseUITests/FirebaseArrayTest.m b/FirebaseUITests/FirebaseArrayTest.m index b8274ee1501..191d82c9f1d 100644 --- a/FirebaseUITests/FirebaseArrayTest.m +++ b/FirebaseUITests/FirebaseArrayTest.m @@ -46,6 +46,7 @@ - (void)setUp { - (void)tearDown { [super tearDown]; [self.observable removeAllObservers]; + self.arrayDelegate = nil; } #pragma mark - Insertion @@ -179,72 +180,6 @@ - (void)testFirebaseArrayCanInsertAtEnd { XCTAssert(expectedParametersWereCorrect, @"unexpected parameter in delegate callback"); } -- (void)testFirebaseArrayCanInsertIntoUniformArray { - // Setup boilerplate - [self.observable populateWithCount:10 generator:^FUIFakeSnapshot *(NSUInteger i) { - FUIFakeSnapshot *snap = [[FUIFakeSnapshot alloc] init]; - snap.key = @"1"; - return snap; - }]; - self.snap.key = @"1"; - - // Test delegate - __block BOOL delegateWasCalled = NO; - __block BOOL expectedParametersWereCorrect = NO; - self.arrayDelegate.didAddObject = ^(FirebaseArray *array, id object, NSUInteger index) { - // Xcode complains about retain cycles if an XCTAssert is placed in here. - delegateWasCalled = YES; - expectedParametersWereCorrect = (array == self.firebaseArray && - object == self.snap && - index == 1); - }; - - // Insert after @"1", which is ambiguous - [self.observable sendEvent:FIRDataEventTypeChildAdded withObject:self.snap previousKey:@"1" error:nil]; - - // Array expectations - NSArray *items = self.firebaseArray.items; - NSArray *expected = @[@"1", @"1", @"1", @"1", @"1", @"1", @"1", @"1", @"1", @"1", @"1"]; - NSMutableArray *result = [NSMutableArray array]; - for (FUIFakeSnapshot *snapshot in items) { - [result addObject:snapshot.key]; - } - XCTAssert([result isEqual:expected], @"expected firebaseArray contents to equal %@, got %@", expected, [result copy]); - - // Delegate expectations - XCTAssert(delegateWasCalled, @"expected delegate to receive callback for insertion"); - XCTAssert(expectedParametersWereCorrect, @"unexpected parameter in delegate callback"); -} - -- (void)testFirebaseCanInsertIntoArrayWithDuplicates { - // Setup boilerplate - [self.observable populateWithCount:10 generator:^FUIFakeSnapshot *(NSUInteger i) { - FUIFakeSnapshot *snap = [[FUIFakeSnapshot alloc] init]; - // Since insertion with duplicates is ambiguous and is resolved by - // always inserting at the first element identical to the - // previous sibling, this series of insertions will produce - // unexpected results. - snap.key = ((i % 3 == 0) ? @"1" : @"0"); - return snap; - }]; - self.snap.key = @"1"; - - // Insert after @"1", which is ambiguous again - [self.observable sendEvent:FIRDataEventTypeChildAdded withObject:self.snap previousKey:@"1" error:nil]; - - // Array expectations - NSArray *items = self.firebaseArray.items; - // The insertion point (after the first 1) of this ambiguous insert - // is a leaky implementation detail and could be considered a bug. - NSArray *expected = @[@"1", @"1", @"0", @"1", @"0", @"0", @"1", @"0", @"0", @"1", @"0"]; - NSMutableArray *result = [NSMutableArray array]; - for (FUIFakeSnapshot *snapshot in items) { - [result addObject:snapshot.key]; - } - - XCTAssert([result isEqual:expected], @"expected firebaseArray contents to equal %@, got %@", expected, [result copy]); -} - #pragma mark - Deletion - (void)testFirebaseArrayCanDeleteOneElementArray { @@ -378,9 +313,9 @@ - (void)testFirebaseArrayCanDeleteMiddleElement { #pragma mark - Modifying elements - (void)testFirebaseArrayCanModifyElement { - // TODO: Make this test less bad [self.observable populateWithCount:10]; self.snap.key = @"5"; + self.snap.value = @"a value"; // Test delegate __block BOOL delegateWasCalled = NO; @@ -393,16 +328,14 @@ - (void)testFirebaseArrayCanModifyElement { index == 5); }; - // Replace element with identical copy of itself lol [self.observable sendEvent:FIRDataEventTypeChildChanged withObject:self.snap previousKey:@"4" error:nil]; // Array expectation NSArray *items = self.firebaseArray.items; - // Current implementation doesn't change the key of the snap on child change. - NSArray *expected = @[@"0", @"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9"]; + NSArray *expected = @[@"0", @"1", @"2", @"3", @"4", @"a value", @"6", @"7", @"8", @"9"]; NSMutableArray *result = [NSMutableArray array]; for (FUIFakeSnapshot *snapshot in items) { - [result addObject:snapshot.key]; + [result addObject:snapshot.value]; } XCTAssert([result isEqual:expected], @"expected firebaseArray contents to equal %@, got %@", expected, [result copy]); @@ -445,6 +378,4 @@ - (void)testFirebaseArrayCanMoveElement { XCTAssert(expectedParametersWereCorrect, @"unexpected parameter in delegate callback"); } -// TODO: add tests for arrays with uniques after we figure out what we want the desired behavior to be - @end diff --git a/FirebaseUITests/FirebaseArrayTestUtils.h b/FirebaseUITests/FirebaseArrayTestUtils.h index dab91f5b60f..f746a0380eb 100644 --- a/FirebaseUITests/FirebaseArrayTestUtils.h +++ b/FirebaseUITests/FirebaseArrayTestUtils.h @@ -32,7 +32,9 @@ NS_ASSUME_NONNULL_BEGIN // Horrible abuse of ObjC type system, since FirebaseArray is unfortunately coupled to // FIRDataSnapshot @interface FUIFakeSnapshot: NSObject +- (instancetype)initWithKey:(NSString *)key value:(NSString *)value; @property (nonatomic, copy) NSString *key; +@property (nonatomic, copy) NSString *value; @end // A dummy observable so we can test this without relying on an internet connection. @@ -52,8 +54,10 @@ NS_ASSUME_NONNULL_BEGIN previousKey:(nullable NSString *)string error:(nullable NSError *)error; -// Inserts sequentially with data provided by the `generator` block. -- (void)populateWithCount:(NSUInteger)count generator:(FUIFakeSnapshot *(^)(NSUInteger))generator; +// Inserts sequentially with data provided by the `generator` block. Snapshot keys +// are increasing integers as strings, snapshot values are strings returned by the +// `generator` block. +- (void)populateWithCount:(NSUInteger)count generator:(NSString *(^)(NSUInteger))generator; // Sends a bunch of insertion events with snapshot keys as integer strings (i.e. @"0") of increasing // order, starting from 0. diff --git a/FirebaseUITests/FirebaseArrayTestUtils.m b/FirebaseUITests/FirebaseArrayTestUtils.m index 9ce2a95c276..3de71c37b31 100644 --- a/FirebaseUITests/FirebaseArrayTestUtils.m +++ b/FirebaseUITests/FirebaseArrayTestUtils.m @@ -24,6 +24,14 @@ @implementation FUIDataEventHandler @end @implementation FUIFakeSnapshot +- (instancetype)initWithKey:(NSString *)key value:(NSString *)value { + self = [super init]; + if (self != nil) { + _key = [key copy]; + _value = [value copy]; + } + return self; +} @end @implementation FUITestObservable @@ -72,20 +80,20 @@ - (void)sendEvent:(FIRDataEventType)event } } -- (void)populateWithCount:(NSUInteger)count generator:(FUIFakeSnapshot *(^)(NSUInteger))generator { +- (void)populateWithCount:(NSUInteger)count generator:(NSString *(^)(NSUInteger))generator { NSString *previous = nil; for (NSUInteger i = 0; i < count; i++) { - FUIFakeSnapshot *snap = generator(i); + FUIFakeSnapshot *snap = [[FUIFakeSnapshot alloc] init]; + snap.value = generator(i); + snap.key = @(i).stringValue; [self sendEvent:FIRDataEventTypeChildAdded withObject:snap previousKey:previous error:nil]; previous = snap.key; } } - (void)populateWithCount:(NSUInteger)count { - [self populateWithCount:count generator:^FUIFakeSnapshot *(NSUInteger index) { - FUIFakeSnapshot *snap = [[FUIFakeSnapshot alloc] init]; - snap.key = @(index).stringValue; - return snap; + [self populateWithCount:count generator:^NSString *(NSUInteger index) { + return @(index).stringValue; }]; } From e624ecf947f5cda64bd963efe91be8859338c6b3 Mon Sep 17 00:00:00 2001 From: Morgan Chen Date: Thu, 11 Aug 2016 11:26:07 -0700 Subject: [PATCH 24/28] deintegrate pods --- FirebaseUI.xcodeproj/project.pbxproj | 68 ---------------------------- 1 file changed, 68 deletions(-) diff --git a/FirebaseUI.xcodeproj/project.pbxproj b/FirebaseUI.xcodeproj/project.pbxproj index f6c7802276c..3192166802f 100644 --- a/FirebaseUI.xcodeproj/project.pbxproj +++ b/FirebaseUI.xcodeproj/project.pbxproj @@ -78,9 +78,6 @@ 1073FEB61CE50A8F00E2F73F /* FirebaseCollectionViewDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 1073FEAD1CE50A8F00E2F73F /* FirebaseCollectionViewDataSource.m */; }; 1073FEB71CE50A8F00E2F73F /* FirebaseDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 1073FEAE1CE50A8F00E2F73F /* FirebaseDataSource.m */; }; 1073FEB81CE50A8F00E2F73F /* FirebaseTableViewDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 1073FEAF1CE50A8F00E2F73F /* FirebaseTableViewDataSource.m */; }; - 44710093677365F50C912171 /* libPods-Database.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 528E8111C0AB5BA29070E357 /* libPods-Database.a */; }; - 811145D773C01673923850F9 /* libPods-Google.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E2AFB1D10DC084378036DA12 /* libPods-Google.a */; }; - 8621C9557B0F42B90A867731 /* libPods-FirebaseUI.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E25E2F8253FA11A3E072D265 /* libPods-FirebaseUI.a */; }; 8D2CB5E21D53F5AE0097FEEB /* libFirebaseUI.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D8C579A61B57349000899F86 /* libFirebaseUI.a */; }; 8D2CB5E91D53F5C50097FEEB /* FirebaseArrayTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D2CB5E81D53F5C50097FEEB /* FirebaseArrayTest.m */; }; 8DD3AACA1D5940E000E6B1F9 /* FirebaseCollectionViewDataSourceTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8DD3AAC91D5940E000E6B1F9 /* FirebaseCollectionViewDataSourceTest.m */; }; @@ -88,8 +85,6 @@ 8DD498F41D5BAAA30022D37E /* FirebaseTableViewDataSourceTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8DD498F31D5BAAA30022D37E /* FirebaseTableViewDataSourceTest.m */; }; 8DFCD1371D53FE8D00208D7B /* FIRAuthUISignInButton.h in Headers */ = {isa = PBXBuildFile; fileRef = 8DFCD1351D53FE8D00208D7B /* FIRAuthUISignInButton.h */; }; 8DFCD1381D53FE8D00208D7B /* FIRAuthUISignInButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 8DFCD1361D53FE8D00208D7B /* FIRAuthUISignInButton.m */; }; - 962E1417A825A57ED7034636 /* libPods-Facebook.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 56CCA3CB9295B6E71208403F /* libPods-Facebook.a */; }; - D0A910B983E334AD9CFE58E6 /* libPods-FirebaseUITests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 015DB5FB0D29CB8E1812F81E /* libPods-FirebaseUITests.a */; }; D8666CB71CEAFCD5002B7C26 /* FirebaseArray.m in Sources */ = {isa = PBXBuildFile; fileRef = 1073FEAC1CE50A8F00E2F73F /* FirebaseArray.m */; }; D8666CB81CEAFCD5002B7C26 /* FirebaseCollectionViewDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 1073FEAD1CE50A8F00E2F73F /* FirebaseCollectionViewDataSource.m */; }; D8666CB91CEAFCD5002B7C26 /* FirebaseDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 1073FEAE1CE50A8F00E2F73F /* FirebaseDataSource.m */; }; @@ -180,7 +175,6 @@ D8666D601CEBFB5C002B7C26 /* FirebaseDatabaseUI.h in Headers */ = {isa = PBXBuildFile; fileRef = D8666D5E1CEBFB5C002B7C26 /* FirebaseDatabaseUI.h */; }; D8B6ACE51B58383C005CDDB2 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D8C579BB1B5837DF00899F86 /* UIKit.framework */; }; D8B6ACE71B583877005CDDB2 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D8B6ACE61B583877005CDDB2 /* Foundation.framework */; }; - EF7744239E9F01AC07019DFD /* libPods-Auth.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 21FD6B795A82BA8A66795B8C /* libPods-Auth.a */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -257,7 +251,6 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 015DB5FB0D29CB8E1812F81E /* libPods-FirebaseUITests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-FirebaseUITests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 1073FE1B1CE509EC00E2F73F /* facebook.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = facebook.png; sourceTree = ""; }; 1073FE1C1CE509EC00E2F73F /* facebook@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "facebook@2x.png"; sourceTree = ""; }; 1073FE1D1CE509EC00E2F73F /* facebook@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "facebook@3x.png"; sourceTree = ""; }; @@ -329,18 +322,6 @@ 1073FEAD1CE50A8F00E2F73F /* FirebaseCollectionViewDataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = FirebaseCollectionViewDataSource.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 1073FEAE1CE50A8F00E2F73F /* FirebaseDataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FirebaseDataSource.m; sourceTree = ""; }; 1073FEAF1CE50A8F00E2F73F /* FirebaseTableViewDataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = FirebaseTableViewDataSource.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; - 21FD6B795A82BA8A66795B8C /* libPods-Auth.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Auth.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - 22227132D91A7F5C5A9C32B4 /* Pods-Facebook.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Facebook.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Facebook/Pods-Facebook.debug.xcconfig"; sourceTree = ""; }; - 2725F35BC499F7F0DC1A53EB /* Pods-FirebaseUI.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FirebaseUI.release.xcconfig"; path = "Pods/Target Support Files/Pods-FirebaseUI/Pods-FirebaseUI.release.xcconfig"; sourceTree = ""; }; - 2E4A5F1ED2EEA77B2C3C8B66 /* Pods-Auth.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Auth.release.xcconfig"; path = "Pods/Target Support Files/Pods-Auth/Pods-Auth.release.xcconfig"; sourceTree = ""; }; - 2FF74AE4572A156D0798CCAB /* Pods-FirebaseUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FirebaseUITests.release.xcconfig"; path = "Pods/Target Support Files/Pods-FirebaseUITests/Pods-FirebaseUITests.release.xcconfig"; sourceTree = ""; }; - 41B1C7A71057AC541FDDCF31 /* Pods-Database.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Database.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Database/Pods-Database.debug.xcconfig"; sourceTree = ""; }; - 4559C9C8BF02EE692280B11C /* Pods-Database.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Database.release.xcconfig"; path = "Pods/Target Support Files/Pods-Database/Pods-Database.release.xcconfig"; sourceTree = ""; }; - 528E8111C0AB5BA29070E357 /* libPods-Database.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Database.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - 558E0266324D3C1E4901FED8 /* Pods-FirebaseUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FirebaseUITests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-FirebaseUITests/Pods-FirebaseUITests.debug.xcconfig"; sourceTree = ""; }; - 56CCA3CB9295B6E71208403F /* libPods-Facebook.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Facebook.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - 5B66352410278E1BAAC6553A /* Pods-FirebaseUI.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FirebaseUI.debug.xcconfig"; path = "Pods/Target Support Files/Pods-FirebaseUI/Pods-FirebaseUI.debug.xcconfig"; sourceTree = ""; }; - 62AA11DC2BCAA83554A5CA5F /* Pods-Auth.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Auth.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Auth/Pods-Auth.debug.xcconfig"; sourceTree = ""; }; 8D2CB5DD1D53F5AE0097FEEB /* FirebaseUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FirebaseUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 8D2CB5E11D53F5AE0097FEEB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 8D2CB5E81D53F5C50097FEEB /* FirebaseArrayTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FirebaseArrayTest.m; sourceTree = ""; }; @@ -351,8 +332,6 @@ 8DD498F31D5BAAA30022D37E /* FirebaseTableViewDataSourceTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FirebaseTableViewDataSourceTest.m; sourceTree = ""; }; 8DFCD1351D53FE8D00208D7B /* FIRAuthUISignInButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FIRAuthUISignInButton.h; sourceTree = ""; }; 8DFCD1361D53FE8D00208D7B /* FIRAuthUISignInButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRAuthUISignInButton.m; sourceTree = ""; }; - B992B1D4DFBAE9C4E3453B15 /* Pods-Google.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Google.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Google/Pods-Google.debug.xcconfig"; sourceTree = ""; }; - D3D8DBF14682CFE73B51B6A5 /* Pods-Google.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Google.release.xcconfig"; path = "Pods/Target Support Files/Pods-Google/Pods-Google.release.xcconfig"; sourceTree = ""; }; D8666CAE1CEAFC93002B7C26 /* libDatabase.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libDatabase.a; sourceTree = BUILT_PRODUCTS_DIR; }; D8666CC61CEAFD40002B7C26 /* libAuth.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libAuth.a; sourceTree = BUILT_PRODUCTS_DIR; }; D8666CFE1CEAFDDB002B7C26 /* libPods-FirebaseUI.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libPods-FirebaseUI.a"; path = "../../../Library/Developer/Xcode/DerivedData/FirebaseUI-anhduclyafjbjahglzespojfewme/Build/Products/Debug-iphonesimulator/libPods-FirebaseUI.a"; sourceTree = ""; }; @@ -380,9 +359,6 @@ D8B6ACE61B583877005CDDB2 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; D8C579A61B57349000899F86 /* libFirebaseUI.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libFirebaseUI.a; sourceTree = BUILT_PRODUCTS_DIR; }; D8C579BB1B5837DF00899F86 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; - DF2E6787E92C161FA17FCC8A /* Pods-Facebook.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Facebook.release.xcconfig"; path = "Pods/Target Support Files/Pods-Facebook/Pods-Facebook.release.xcconfig"; sourceTree = ""; }; - E25E2F8253FA11A3E072D265 /* libPods-FirebaseUI.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-FirebaseUI.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - E2AFB1D10DC084378036DA12 /* libPods-Google.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Google.a"; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -391,7 +367,6 @@ buildActionMask = 2147483647; files = ( 8D2CB5E21D53F5AE0097FEEB /* libFirebaseUI.a in Frameworks */, - D0A910B983E334AD9CFE58E6 /* libPods-FirebaseUITests.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -400,7 +375,6 @@ buildActionMask = 2147483647; files = ( D8666D331CEB0187002B7C26 /* FirebaseDatabase.framework in Frameworks */, - 44710093677365F50C912171 /* libPods-Database.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -421,7 +395,6 @@ D8666D391CEB0210002B7C26 /* Security.framework in Frameworks */, D8666D371CEB01F0002B7C26 /* FirebaseAnalytics.framework in Frameworks */, D8666D351CEB01E2002B7C26 /* FirebaseAuth.framework in Frameworks */, - EF7744239E9F01AC07019DFD /* libPods-Auth.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -429,7 +402,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 962E1417A825A57ED7034636 /* libPods-Facebook.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -438,7 +410,6 @@ buildActionMask = 2147483647; files = ( D8666D591CEB03BA002B7C26 /* GoogleSignIn.framework in Frameworks */, - 811145D773C01673923850F9 /* libPods-Google.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -448,7 +419,6 @@ files = ( D8B6ACE51B58383C005CDDB2 /* UIKit.framework in Frameworks */, D8B6ACE71B583877005CDDB2 /* Foundation.framework in Frameworks */, - 8621C9557B0F42B90A867731 /* libPods-FirebaseUI.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -663,25 +633,6 @@ path = Implementation; sourceTree = ""; }; - 7C1F7BF9D46ABA4D64839CBD /* Pods */ = { - isa = PBXGroup; - children = ( - 62AA11DC2BCAA83554A5CA5F /* Pods-Auth.debug.xcconfig */, - 2E4A5F1ED2EEA77B2C3C8B66 /* Pods-Auth.release.xcconfig */, - 41B1C7A71057AC541FDDCF31 /* Pods-Database.debug.xcconfig */, - 4559C9C8BF02EE692280B11C /* Pods-Database.release.xcconfig */, - 22227132D91A7F5C5A9C32B4 /* Pods-Facebook.debug.xcconfig */, - DF2E6787E92C161FA17FCC8A /* Pods-Facebook.release.xcconfig */, - 5B66352410278E1BAAC6553A /* Pods-FirebaseUI.debug.xcconfig */, - 2725F35BC499F7F0DC1A53EB /* Pods-FirebaseUI.release.xcconfig */, - 558E0266324D3C1E4901FED8 /* Pods-FirebaseUITests.debug.xcconfig */, - 2FF74AE4572A156D0798CCAB /* Pods-FirebaseUITests.release.xcconfig */, - B992B1D4DFBAE9C4E3453B15 /* Pods-Google.debug.xcconfig */, - D3D8DBF14682CFE73B51B6A5 /* Pods-Google.release.xcconfig */, - ); - name = Pods; - sourceTree = ""; - }; 8D2CB5DE1D53F5AE0097FEEB /* FirebaseUITests */ = { isa = PBXGroup; children = ( @@ -728,12 +679,6 @@ D8666CFE1CEAFDDB002B7C26 /* libPods-FirebaseUI.a */, D8B6ACE61B583877005CDDB2 /* Foundation.framework */, D8C579BB1B5837DF00899F86 /* UIKit.framework */, - 21FD6B795A82BA8A66795B8C /* libPods-Auth.a */, - 528E8111C0AB5BA29070E357 /* libPods-Database.a */, - 56CCA3CB9295B6E71208403F /* libPods-Facebook.a */, - E25E2F8253FA11A3E072D265 /* libPods-FirebaseUI.a */, - 015DB5FB0D29CB8E1812F81E /* libPods-FirebaseUITests.a */, - E2AFB1D10DC084378036DA12 /* libPods-Google.a */, ); name = Frameworks; sourceTree = ""; @@ -745,7 +690,6 @@ 8D2CB5DE1D53F5AE0097FEEB /* FirebaseUITests */, D8C579A71B57349000899F86 /* Products */, D8B6ACE81B5839A5005CDDB2 /* Frameworks */, - 7C1F7BF9D46ABA4D64839CBD /* Pods */, ); sourceTree = ""; }; @@ -1470,7 +1414,6 @@ /* Begin XCBuildConfiguration section */ 8D2CB5E51D53F5AE0097FEEB /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 558E0266324D3C1E4901FED8 /* Pods-FirebaseUITests.debug.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -1488,7 +1431,6 @@ }; 8D2CB5E61D53F5AE0097FEEB /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 2FF74AE4572A156D0798CCAB /* Pods-FirebaseUITests.release.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -1502,7 +1444,6 @@ }; D8666CB41CEAFC93002B7C26 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 41B1C7A71057AC541FDDCF31 /* Pods-Database.debug.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -1526,7 +1467,6 @@ }; D8666CB51CEAFC93002B7C26 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 4559C9C8BF02EE692280B11C /* Pods-Database.release.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -1546,7 +1486,6 @@ }; D8666CCD1CEAFD40002B7C26 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 62AA11DC2BCAA83554A5CA5F /* Pods-Auth.debug.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -1576,7 +1515,6 @@ }; D8666CCE1CEAFD40002B7C26 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 2E4A5F1ED2EEA77B2C3C8B66 /* Pods-Auth.release.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -1602,7 +1540,6 @@ }; D8666D0D1CEAFF29002B7C26 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 22227132D91A7F5C5A9C32B4 /* Pods-Facebook.debug.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -1622,7 +1559,6 @@ }; D8666D0E1CEAFF29002B7C26 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = DF2E6787E92C161FA17FCC8A /* Pods-Facebook.release.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -1638,7 +1574,6 @@ }; D8666D1B1CEAFF41002B7C26 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = B992B1D4DFBAE9C4E3453B15 /* Pods-Google.debug.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -1662,7 +1597,6 @@ }; D8666D1C1CEAFF41002B7C26 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = D3D8DBF14682CFE73B51B6A5 /* Pods-Google.release.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -1765,7 +1699,6 @@ }; D8C579B01B57349000899F86 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 5B66352410278E1BAAC6553A /* Pods-FirebaseUI.debug.xcconfig */; buildSettings = { CLANG_MODULES_AUTOLINK = YES; DEAD_CODE_STRIPPING = NO; @@ -1808,7 +1741,6 @@ }; D8C579B11B57349000899F86 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 2725F35BC499F7F0DC1A53EB /* Pods-FirebaseUI.release.xcconfig */; buildSettings = { CLANG_MODULES_AUTOLINK = YES; DEAD_CODE_STRIPPING = NO; From 279794355c27a8f0a9318acc2b14e39cdb41468a Mon Sep 17 00:00:00 2001 From: Morgan Chen Date: Thu, 11 Aug 2016 12:02:45 -0700 Subject: [PATCH 25/28] add null_resettable to data sources --- .../API/FirebaseCollectionViewDataSource.h | 6 ++++-- .../Database/API/FirebaseTableViewDataSource.h | 3 ++- .../FirebaseCollectionViewDataSource.m | 18 ++++++++++++++++++ .../FirebaseTableViewDataSource.m | 10 ++++++++++ 4 files changed, 34 insertions(+), 3 deletions(-) diff --git a/FirebaseUI/Database/API/FirebaseCollectionViewDataSource.h b/FirebaseUI/Database/API/FirebaseCollectionViewDataSource.h index bb3941b7530..3b12b264942 100644 --- a/FirebaseUI/Database/API/FirebaseCollectionViewDataSource.h +++ b/FirebaseUI/Database/API/FirebaseCollectionViewDataSource.h @@ -52,8 +52,9 @@ NS_ASSUME_NONNULL_BEGIN * to [Message class] in Obj-C or Message.self in Swift, then objects of type * Message will be * returned instead of type FIRDataSnapshot. + * Defaults to FIRDataSnapshot. */ -@property(strong, nonatomic, nullable) Class modelClass; +@property(strong, nonatomic, null_resettable) Class modelClass; /** * The cell class to coerce UICollectionViewCells to (if desired). For instance, @@ -62,8 +63,9 @@ NS_ASSUME_NONNULL_BEGIN * in Swift, then * objects of type CustomCollectionViewCell will be returned instead of type * UICollectionViewCell. + * Defaults to UICollectionViewCell. */ -@property(strong, nonatomic, nullable) Class cellClass; +@property(strong, nonatomic, null_resettable) Class cellClass; /** * The reuse identifier for cells in the UICollectionView. diff --git a/FirebaseUI/Database/API/FirebaseTableViewDataSource.h b/FirebaseUI/Database/API/FirebaseTableViewDataSource.h index 204240ee4b3..c9b62f1d2e1 100644 --- a/FirebaseUI/Database/API/FirebaseTableViewDataSource.h +++ b/FirebaseUI/Database/API/FirebaseTableViewDataSource.h @@ -51,8 +51,9 @@ NS_ASSUME_NONNULL_BEGIN * to [Message class] in Obj-C or Message.self in Swift, then objects of type * Message will be * returned instead of type FIRDataSnapshot. + * Defaults to FIRDataSnapshot. */ -@property(strong, nonatomic) Class modelClass; +@property(strong, nonatomic, null_resettable) Class modelClass; /** * The reuse identifier for cells in the UITableView. diff --git a/FirebaseUI/Database/Implementation/FirebaseCollectionViewDataSource.m b/FirebaseUI/Database/Implementation/FirebaseCollectionViewDataSource.m index 2b43e3969b1..8c10cebc6b9 100644 --- a/FirebaseUI/Database/Implementation/FirebaseCollectionViewDataSource.m +++ b/FirebaseUI/Database/Implementation/FirebaseCollectionViewDataSource.m @@ -294,4 +294,22 @@ - (void)populateCellWithBlock:(void (^)(__kindof UICollectionViewCell *cell, self.populateCell = callback; } +#pragma mark - Accessors + +- (void)setModelClass:(Class)modelClass { + if (modelClass == nil) { + _modelClass = [FIRDataSnapshot class]; + } else { + _modelClass = modelClass; + } +} + +- (void)setCellClass:(Class)cellClass { + if (cellClass == nil) { + _cellClass = [UICollectionViewCell class]; + } else { + _cellClass = cellClass; + } +} + @end diff --git a/FirebaseUI/Database/Implementation/FirebaseTableViewDataSource.m b/FirebaseUI/Database/Implementation/FirebaseTableViewDataSource.m index c37c5e0f367..73d9ab19544 100644 --- a/FirebaseUI/Database/Implementation/FirebaseTableViewDataSource.m +++ b/FirebaseUI/Database/Implementation/FirebaseTableViewDataSource.m @@ -295,4 +295,14 @@ - (void)populateCellWithBlock:(void (^)(__kindof UITableViewCell *cell, self.populateCell = callback; } +#pragma mark - Accessors + +- (void)setModelClass:(Class)modelClass { + if (modelClass == nil) { + _modelClass = [FIRDataSnapshot class]; + } else { + _modelClass = modelClass; + } +} + @end From a2473daa77e7bf3e2188bbb9fd62bda3c3afa7da Mon Sep 17 00:00:00 2001 From: Morgan Chen Date: Thu, 11 Aug 2016 12:06:36 -0700 Subject: [PATCH 26/28] make table view data source's populateCell readonly --- FirebaseUI/Database/API/FirebaseTableViewDataSource.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FirebaseUI/Database/API/FirebaseTableViewDataSource.h b/FirebaseUI/Database/API/FirebaseTableViewDataSource.h index c9b62f1d2e1..6b840c71c81 100644 --- a/FirebaseUI/Database/API/FirebaseTableViewDataSource.h +++ b/FirebaseUI/Database/API/FirebaseTableViewDataSource.h @@ -77,8 +77,8 @@ NS_ASSUME_NONNULL_BEGIN * The callback to populate a subclass of UITableViewCell with an object * provided by the datasource. */ -@property(strong, nonatomic) void (^populateCell) - (__kindof UITableViewCell *cell, __kindof NSObject *object); +@property(strong, nonatomic, readonly) void (^populateCell) + (__kindof UITableViewCell *cell,__kindof NSObject *object); /** * Initialize an instance of FirebaseTableViewDataSource that populates From fa2918afbaaaba16e4cdb6cb1e301a98d3dd8bd7 Mon Sep 17 00:00:00 2001 From: Morgan Chen Date: Fri, 12 Aug 2016 10:53:38 -0700 Subject: [PATCH 27/28] rearrange property modifiers --- .../Auth/AuthProviderUI/Facebook/Source/FIRFacebookAuthUI.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FirebaseUI/Auth/AuthProviderUI/Facebook/Source/FIRFacebookAuthUI.h b/FirebaseUI/Auth/AuthProviderUI/Facebook/Source/FIRFacebookAuthUI.h index fd0b4cd7606..c11c2eeee31 100644 --- a/FirebaseUI/Auth/AuthProviderUI/Facebook/Source/FIRFacebookAuthUI.h +++ b/FirebaseUI/Auth/AuthProviderUI/Facebook/Source/FIRFacebookAuthUI.h @@ -28,13 +28,13 @@ NS_ASSUME_NONNULL_BEGIN /** @property appId @brief The Facebook App ID. */ -@property(nonatomic, copy, readonly) NSString *appID; +@property(nonatomic, readonly, copy) NSString *appID; /** @property scopes @brief The scopes to use with Facebook Login. @remarks Defaults to using "email" scopes. */ -@property(nonatomic, copy, readonly) NSArray *scopes; +@property(nonatomic, readonly, copy) NSArray *scopes; /** @fn init @brief Please use initWithAppId: From a1002713ee442ac1526c91eb837c81c304b3fbff Mon Sep 17 00:00:00 2001 From: Morgan Chen Date: Fri, 12 Aug 2016 10:56:46 -0700 Subject: [PATCH 28/28] properly copy init parameter --- FirebaseUI/Auth/AuthProviderUI/Google/Source/FIRGoogleAuthUI.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FirebaseUI/Auth/AuthProviderUI/Google/Source/FIRGoogleAuthUI.m b/FirebaseUI/Auth/AuthProviderUI/Google/Source/FIRGoogleAuthUI.m index 2637f6d6ba7..8df0d26b6e3 100644 --- a/FirebaseUI/Auth/AuthProviderUI/Google/Source/FIRGoogleAuthUI.m +++ b/FirebaseUI/Auth/AuthProviderUI/Google/Source/FIRGoogleAuthUI.m @@ -80,7 +80,7 @@ - (instancetype)initWithClientID:(NSString *)clientID scopes:(NSArray *)scopes { self = [super init]; if (self) { _clientID = [clientID copy]; - _scopes = scopes; + _scopes = [scopes copy]; } return self; }