- Upgrade to 1.0
@ -7,21 +7,22 @@
|
|||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
3F3C53CB2D851F471BE8A604 /* Pods_PNObject_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 89BBA9195EECA9F4625BB1DC /* Pods_PNObject_Example.framework */; };
|
2EC5979E315D48625574D725 /* Pods_PNObject_Tests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 808511432137F18DDFE44210 /* Pods_PNObject_Tests.framework */; };
|
||||||
6003F58E195388D20070C39A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58D195388D20070C39A /* Foundation.framework */; };
|
6003F58E195388D20070C39A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58D195388D20070C39A /* Foundation.framework */; };
|
||||||
6003F590195388D20070C39A /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58F195388D20070C39A /* CoreGraphics.framework */; };
|
6003F590195388D20070C39A /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58F195388D20070C39A /* CoreGraphics.framework */; };
|
||||||
6003F592195388D20070C39A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F591195388D20070C39A /* UIKit.framework */; };
|
6003F592195388D20070C39A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F591195388D20070C39A /* UIKit.framework */; };
|
||||||
6003F598195388D20070C39A /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6003F596195388D20070C39A /* InfoPlist.strings */; };
|
6003F598195388D20070C39A /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6003F596195388D20070C39A /* InfoPlist.strings */; };
|
||||||
6003F59A195388D20070C39A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 6003F599195388D20070C39A /* main.m */; };
|
6003F59A195388D20070C39A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 6003F599195388D20070C39A /* main.m */; };
|
||||||
6003F59E195388D20070C39A /* PNObjectAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 6003F59D195388D20070C39A /* PNObjectAppDelegate.m */; };
|
6003F59E195388D20070C39A /* PNObjAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 6003F59D195388D20070C39A /* PNObjAppDelegate.m */; };
|
||||||
6003F5A7195388D20070C39A /* PNObjectViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6003F5A6195388D20070C39A /* PNObjectViewController.m */; };
|
6003F5A7195388D20070C39A /* PNObjViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6003F5A6195388D20070C39A /* PNObjViewController.m */; };
|
||||||
6003F5A9195388D20070C39A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6003F5A8195388D20070C39A /* Images.xcassets */; };
|
6003F5A9195388D20070C39A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6003F5A8195388D20070C39A /* Images.xcassets */; };
|
||||||
6003F5B0195388D20070C39A /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F5AF195388D20070C39A /* XCTest.framework */; };
|
6003F5B0195388D20070C39A /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F5AF195388D20070C39A /* XCTest.framework */; };
|
||||||
6003F5B1195388D20070C39A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58D195388D20070C39A /* Foundation.framework */; };
|
6003F5B1195388D20070C39A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58D195388D20070C39A /* Foundation.framework */; };
|
||||||
6003F5B2195388D20070C39A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F591195388D20070C39A /* UIKit.framework */; };
|
6003F5B2195388D20070C39A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F591195388D20070C39A /* UIKit.framework */; };
|
||||||
6003F5BA195388D20070C39A /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6003F5B8195388D20070C39A /* InfoPlist.strings */; };
|
6003F5BA195388D20070C39A /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6003F5B8195388D20070C39A /* InfoPlist.strings */; };
|
||||||
6003F5BC195388D20070C39A /* Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6003F5BB195388D20070C39A /* Tests.m */; };
|
6003F5BC195388D20070C39A /* Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6003F5BB195388D20070C39A /* Tests.m */; };
|
||||||
60D833DF200A0D946F2E8C4D /* Pods_PNObject_Tests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CAD2FCF55030EAE61415B480 /* Pods_PNObject_Tests.framework */; };
|
873B8AEB1B1F5CCA007FD442 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 873B8AEA1B1F5CCA007FD442 /* Main.storyboard */; };
|
||||||
|
FD9FF8837F786E50B88531C0 /* Pods_PNObject_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F74BC1D549B9C619883DB7E0 /* Pods_PNObject_Example.framework */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
@ -35,8 +36,9 @@
|
|||||||
/* End PBXContainerItemProxy section */
|
/* End PBXContainerItemProxy section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
2DBDB9BA06776F1FFBD6EDC3 /* Pods-PNObject_Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PNObject_Tests.release.xcconfig"; path = "Pods/Target Support Files/Pods-PNObject_Tests/Pods-PNObject_Tests.release.xcconfig"; sourceTree = "<group>"; };
|
116AF818F8117B91EF290C9A /* Pods-PNObject_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PNObject_Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-PNObject_Example/Pods-PNObject_Example.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
4082E2E9CCB7F56C1A30AF72 /* Pods-PNObject_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PNObject_Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-PNObject_Example/Pods-PNObject_Example.release.xcconfig"; sourceTree = "<group>"; };
|
2661CEE1F223361CD1DACC25 /* PNObject.podspec */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = PNObject.podspec; path = ../PNObject.podspec; sourceTree = "<group>"; };
|
||||||
|
3E392C278361604C1602CAF0 /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = "<group>"; };
|
||||||
6003F58A195388D20070C39A /* PNObject_Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PNObject_Example.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
6003F58A195388D20070C39A /* PNObject_Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PNObject_Example.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
6003F58D195388D20070C39A /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
6003F58D195388D20070C39A /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
||||||
6003F58F195388D20070C39A /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
|
6003F58F195388D20070C39A /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
|
||||||
@ -45,10 +47,10 @@
|
|||||||
6003F597195388D20070C39A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
6003F597195388D20070C39A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||||
6003F599195388D20070C39A /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
6003F599195388D20070C39A /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||||
6003F59B195388D20070C39A /* PNObject-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "PNObject-Prefix.pch"; sourceTree = "<group>"; };
|
6003F59B195388D20070C39A /* PNObject-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "PNObject-Prefix.pch"; sourceTree = "<group>"; };
|
||||||
6003F59C195388D20070C39A /* PNObjectAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PNObjectAppDelegate.h; sourceTree = "<group>"; };
|
6003F59C195388D20070C39A /* PNObjAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PNObjAppDelegate.h; sourceTree = "<group>"; };
|
||||||
6003F59D195388D20070C39A /* PNObjectAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PNObjectAppDelegate.m; sourceTree = "<group>"; };
|
6003F59D195388D20070C39A /* PNObjAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PNObjAppDelegate.m; sourceTree = "<group>"; };
|
||||||
6003F5A5195388D20070C39A /* PNObjectViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PNObjectViewController.h; sourceTree = "<group>"; };
|
6003F5A5195388D20070C39A /* PNObjViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PNObjViewController.h; sourceTree = "<group>"; };
|
||||||
6003F5A6195388D20070C39A /* PNObjectViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PNObjectViewController.m; sourceTree = "<group>"; };
|
6003F5A6195388D20070C39A /* PNObjViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PNObjViewController.m; sourceTree = "<group>"; };
|
||||||
6003F5A8195388D20070C39A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
|
6003F5A8195388D20070C39A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
|
||||||
6003F5AE195388D20070C39A /* PNObject_Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PNObject_Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
6003F5AE195388D20070C39A /* PNObject_Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PNObject_Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
6003F5AF195388D20070C39A /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
|
6003F5AF195388D20070C39A /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
|
||||||
@ -56,15 +58,13 @@
|
|||||||
6003F5B9195388D20070C39A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
6003F5B9195388D20070C39A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||||
6003F5BB195388D20070C39A /* Tests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Tests.m; sourceTree = "<group>"; };
|
6003F5BB195388D20070C39A /* Tests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Tests.m; sourceTree = "<group>"; };
|
||||||
606FC2411953D9B200FFA9A0 /* Tests-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Tests-Prefix.pch"; sourceTree = "<group>"; };
|
606FC2411953D9B200FFA9A0 /* Tests-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Tests-Prefix.pch"; sourceTree = "<group>"; };
|
||||||
6805F44B1DF6DCC600C79B18 /* PNObject_Example.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = PNObject_Example.entitlements; sourceTree = "<group>"; };
|
808511432137F18DDFE44210 /* Pods_PNObject_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_PNObject_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
75FCB4EFD17838CCA4C93E4A /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = "<group>"; };
|
873B8AEA1B1F5CCA007FD442 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = "<group>"; };
|
||||||
89BBA9195EECA9F4625BB1DC /* Pods_PNObject_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_PNObject_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
A90E0E5930707E3F83662328 /* Pods-PNObject_Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PNObject_Tests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-PNObject_Tests/Pods-PNObject_Tests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
8C017F9292D546DE8DBC84F8 /* PNObject.podspec */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = PNObject.podspec; path = ../PNObject.podspec; sourceTree = "<group>"; };
|
C0F786F6B0C2234E3B3A5F30 /* Pods-PNObject_Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PNObject_Tests.release.xcconfig"; path = "Pods/Target Support Files/Pods-PNObject_Tests/Pods-PNObject_Tests.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
9898F9E5E65D3B402429FD73 /* Pods-PNObject_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PNObject_Example.debug.xcconfig"; path = "Pods/Target Support Files/Pods-PNObject_Example/Pods-PNObject_Example.debug.xcconfig"; sourceTree = "<group>"; };
|
C6D958A9E3E6FFB7818A72C7 /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = "<group>"; };
|
||||||
9F4B24EF58CA8BC69BFC569B /* Pods-PNObject_Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PNObject_Tests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-PNObject_Tests/Pods-PNObject_Tests.debug.xcconfig"; sourceTree = "<group>"; };
|
E20844B85780704FB196FA2A /* Pods-PNObject_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PNObject_Example.debug.xcconfig"; path = "Pods/Target Support Files/Pods-PNObject_Example/Pods-PNObject_Example.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
BA17B1571B43FAFAA8B45B6D /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = "<group>"; };
|
F74BC1D549B9C619883DB7E0 /* Pods_PNObject_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_PNObject_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
CAD2FCF55030EAE61415B480 /* Pods_PNObject_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_PNObject_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
||||||
DE7587A588720F0590F50755 /* Pods.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
@ -75,7 +75,7 @@
|
|||||||
6003F590195388D20070C39A /* CoreGraphics.framework in Frameworks */,
|
6003F590195388D20070C39A /* CoreGraphics.framework in Frameworks */,
|
||||||
6003F592195388D20070C39A /* UIKit.framework in Frameworks */,
|
6003F592195388D20070C39A /* UIKit.framework in Frameworks */,
|
||||||
6003F58E195388D20070C39A /* Foundation.framework in Frameworks */,
|
6003F58E195388D20070C39A /* Foundation.framework in Frameworks */,
|
||||||
3F3C53CB2D851F471BE8A604 /* Pods_PNObject_Example.framework in Frameworks */,
|
FD9FF8837F786E50B88531C0 /* Pods_PNObject_Example.framework in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@ -86,34 +86,22 @@
|
|||||||
6003F5B0195388D20070C39A /* XCTest.framework in Frameworks */,
|
6003F5B0195388D20070C39A /* XCTest.framework in Frameworks */,
|
||||||
6003F5B2195388D20070C39A /* UIKit.framework in Frameworks */,
|
6003F5B2195388D20070C39A /* UIKit.framework in Frameworks */,
|
||||||
6003F5B1195388D20070C39A /* Foundation.framework in Frameworks */,
|
6003F5B1195388D20070C39A /* Foundation.framework in Frameworks */,
|
||||||
60D833DF200A0D946F2E8C4D /* Pods_PNObject_Tests.framework in Frameworks */,
|
2EC5979E315D48625574D725 /* Pods_PNObject_Tests.framework in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
/* End PBXFrameworksBuildPhase section */
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXGroup section */
|
/* Begin PBXGroup section */
|
||||||
2DE160677BF4961C3D433201 /* Pods */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
9898F9E5E65D3B402429FD73 /* Pods-PNObject_Example.debug.xcconfig */,
|
|
||||||
4082E2E9CCB7F56C1A30AF72 /* Pods-PNObject_Example.release.xcconfig */,
|
|
||||||
9F4B24EF58CA8BC69BFC569B /* Pods-PNObject_Tests.debug.xcconfig */,
|
|
||||||
2DBDB9BA06776F1FFBD6EDC3 /* Pods-PNObject_Tests.release.xcconfig */,
|
|
||||||
);
|
|
||||||
name = Pods;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
6003F581195388D10070C39A = {
|
6003F581195388D10070C39A = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
6805F44B1DF6DCC600C79B18 /* PNObject_Example.entitlements */,
|
|
||||||
60FF7A9C1954A5C5007DD14C /* Podspec Metadata */,
|
60FF7A9C1954A5C5007DD14C /* Podspec Metadata */,
|
||||||
6003F593195388D20070C39A /* Example for PNObject */,
|
6003F593195388D20070C39A /* Example for PNObject */,
|
||||||
6003F5B5195388D20070C39A /* Tests */,
|
6003F5B5195388D20070C39A /* Tests */,
|
||||||
6003F58C195388D20070C39A /* Frameworks */,
|
6003F58C195388D20070C39A /* Frameworks */,
|
||||||
6003F58B195388D20070C39A /* Products */,
|
6003F58B195388D20070C39A /* Products */,
|
||||||
2DE160677BF4961C3D433201 /* Pods */,
|
977F1D998CB9116027C75157 /* Pods */,
|
||||||
);
|
);
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
@ -133,9 +121,8 @@
|
|||||||
6003F58F195388D20070C39A /* CoreGraphics.framework */,
|
6003F58F195388D20070C39A /* CoreGraphics.framework */,
|
||||||
6003F591195388D20070C39A /* UIKit.framework */,
|
6003F591195388D20070C39A /* UIKit.framework */,
|
||||||
6003F5AF195388D20070C39A /* XCTest.framework */,
|
6003F5AF195388D20070C39A /* XCTest.framework */,
|
||||||
DE7587A588720F0590F50755 /* Pods.framework */,
|
F74BC1D549B9C619883DB7E0 /* Pods_PNObject_Example.framework */,
|
||||||
89BBA9195EECA9F4625BB1DC /* Pods_PNObject_Example.framework */,
|
808511432137F18DDFE44210 /* Pods_PNObject_Tests.framework */,
|
||||||
CAD2FCF55030EAE61415B480 /* Pods_PNObject_Tests.framework */,
|
|
||||||
);
|
);
|
||||||
name = Frameworks;
|
name = Frameworks;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -143,10 +130,11 @@
|
|||||||
6003F593195388D20070C39A /* Example for PNObject */ = {
|
6003F593195388D20070C39A /* Example for PNObject */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
6003F59C195388D20070C39A /* PNObjectAppDelegate.h */,
|
6003F59C195388D20070C39A /* PNObjAppDelegate.h */,
|
||||||
6003F59D195388D20070C39A /* PNObjectAppDelegate.m */,
|
6003F59D195388D20070C39A /* PNObjAppDelegate.m */,
|
||||||
6003F5A5195388D20070C39A /* PNObjectViewController.h */,
|
873B8AEA1B1F5CCA007FD442 /* Main.storyboard */,
|
||||||
6003F5A6195388D20070C39A /* PNObjectViewController.m */,
|
6003F5A5195388D20070C39A /* PNObjViewController.h */,
|
||||||
|
6003F5A6195388D20070C39A /* PNObjViewController.m */,
|
||||||
6003F5A8195388D20070C39A /* Images.xcassets */,
|
6003F5A8195388D20070C39A /* Images.xcassets */,
|
||||||
6003F594195388D20070C39A /* Supporting Files */,
|
6003F594195388D20070C39A /* Supporting Files */,
|
||||||
);
|
);
|
||||||
@ -187,13 +175,24 @@
|
|||||||
60FF7A9C1954A5C5007DD14C /* Podspec Metadata */ = {
|
60FF7A9C1954A5C5007DD14C /* Podspec Metadata */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
8C017F9292D546DE8DBC84F8 /* PNObject.podspec */,
|
2661CEE1F223361CD1DACC25 /* PNObject.podspec */,
|
||||||
BA17B1571B43FAFAA8B45B6D /* README.md */,
|
3E392C278361604C1602CAF0 /* README.md */,
|
||||||
75FCB4EFD17838CCA4C93E4A /* LICENSE */,
|
C6D958A9E3E6FFB7818A72C7 /* LICENSE */,
|
||||||
);
|
);
|
||||||
name = "Podspec Metadata";
|
name = "Podspec Metadata";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
977F1D998CB9116027C75157 /* Pods */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
E20844B85780704FB196FA2A /* Pods-PNObject_Example.debug.xcconfig */,
|
||||||
|
116AF818F8117B91EF290C9A /* Pods-PNObject_Example.release.xcconfig */,
|
||||||
|
A90E0E5930707E3F83662328 /* Pods-PNObject_Tests.debug.xcconfig */,
|
||||||
|
C0F786F6B0C2234E3B3A5F30 /* Pods-PNObject_Tests.release.xcconfig */,
|
||||||
|
);
|
||||||
|
name = Pods;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
/* End PBXGroup section */
|
/* End PBXGroup section */
|
||||||
|
|
||||||
/* Begin PBXNativeTarget section */
|
/* Begin PBXNativeTarget section */
|
||||||
@ -201,12 +200,12 @@
|
|||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = 6003F5BF195388D20070C39A /* Build configuration list for PBXNativeTarget "PNObject_Example" */;
|
buildConfigurationList = 6003F5BF195388D20070C39A /* Build configuration list for PBXNativeTarget "PNObject_Example" */;
|
||||||
buildPhases = (
|
buildPhases = (
|
||||||
387C1DBC7D3E0673105ED546 /* [CP] Check Pods Manifest.lock */,
|
E4CE079F616C61EA34D08B8B /* [CP] Check Pods Manifest.lock */,
|
||||||
6003F586195388D20070C39A /* Sources */,
|
6003F586195388D20070C39A /* Sources */,
|
||||||
6003F587195388D20070C39A /* Frameworks */,
|
6003F587195388D20070C39A /* Frameworks */,
|
||||||
6003F588195388D20070C39A /* Resources */,
|
6003F588195388D20070C39A /* Resources */,
|
||||||
3695565DCFF7D29C95488878 /* [CP] Embed Pods Frameworks */,
|
C40CC8D7B1996A567BE82827 /* [CP] Embed Pods Frameworks */,
|
||||||
B84699CAD21D4AE39D658EC6 /* [CP] Copy Pods Resources */,
|
614EA73ED5E0ED0F8684468C /* [CP] Copy Pods Resources */,
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
@ -221,12 +220,12 @@
|
|||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = 6003F5C2195388D20070C39A /* Build configuration list for PBXNativeTarget "PNObject_Tests" */;
|
buildConfigurationList = 6003F5C2195388D20070C39A /* Build configuration list for PBXNativeTarget "PNObject_Tests" */;
|
||||||
buildPhases = (
|
buildPhases = (
|
||||||
F5E57EFDD9ADE887CAAAC837 /* [CP] Check Pods Manifest.lock */,
|
3FF38AA7E586B22171D1A118 /* [CP] Check Pods Manifest.lock */,
|
||||||
6003F5AA195388D20070C39A /* Sources */,
|
6003F5AA195388D20070C39A /* Sources */,
|
||||||
6003F5AB195388D20070C39A /* Frameworks */,
|
6003F5AB195388D20070C39A /* Frameworks */,
|
||||||
6003F5AC195388D20070C39A /* Resources */,
|
6003F5AC195388D20070C39A /* Resources */,
|
||||||
31A4834C1FAEFDFFFAEC6297 /* [CP] Embed Pods Frameworks */,
|
746A765B48FD98342716D81F /* [CP] Embed Pods Frameworks */,
|
||||||
C2D74CFB72423672ACF097D4 /* [CP] Copy Pods Resources */,
|
21411FBE0FE21EC75B6AB1E3 /* [CP] Copy Pods Resources */,
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
@ -244,17 +243,12 @@
|
|||||||
6003F582195388D10070C39A /* Project object */ = {
|
6003F582195388D10070C39A /* Project object */ = {
|
||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
CLASSPREFIX = PNObject;
|
CLASSPREFIX = PNObj;
|
||||||
LastUpgradeCheck = 0820;
|
LastUpgradeCheck = 0720;
|
||||||
ORGANIZATIONNAME = "Giuseppe Nucifora";
|
ORGANIZATIONNAME = "Giuseppe Nucifora";
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
6003F589195388D20070C39A = {
|
6003F589195388D20070C39A = {
|
||||||
DevelopmentTeam = 825G85A28E;
|
DevelopmentTeam = 825G85A28E;
|
||||||
SystemCapabilities = {
|
|
||||||
com.apple.Push = {
|
|
||||||
enabled = 1;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
6003F5AD195388D20070C39A = {
|
6003F5AD195388D20070C39A = {
|
||||||
TestTargetID = 6003F589195388D20070C39A;
|
TestTargetID = 6003F589195388D20070C39A;
|
||||||
@ -285,6 +279,7 @@
|
|||||||
isa = PBXResourcesBuildPhase;
|
isa = PBXResourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
873B8AEB1B1F5CCA007FD442 /* Main.storyboard in Resources */,
|
||||||
6003F5A9195388D20070C39A /* Images.xcassets in Resources */,
|
6003F5A9195388D20070C39A /* Images.xcassets in Resources */,
|
||||||
6003F598195388D20070C39A /* InfoPlist.strings in Resources */,
|
6003F598195388D20070C39A /* InfoPlist.strings in Resources */,
|
||||||
);
|
);
|
||||||
@ -301,67 +296,7 @@
|
|||||||
/* End PBXResourcesBuildPhase section */
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXShellScriptBuildPhase section */
|
/* Begin PBXShellScriptBuildPhase section */
|
||||||
31A4834C1FAEFDFFFAEC6297 /* [CP] Embed Pods Frameworks */ = {
|
21411FBE0FE21EC75B6AB1E3 /* [CP] Copy Pods Resources */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
inputPaths = (
|
|
||||||
);
|
|
||||||
name = "[CP] Embed Pods Frameworks";
|
|
||||||
outputPaths = (
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
shellPath = /bin/sh;
|
|
||||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-PNObject_Tests/Pods-PNObject_Tests-frameworks.sh\"\n";
|
|
||||||
showEnvVarsInLog = 0;
|
|
||||||
};
|
|
||||||
3695565DCFF7D29C95488878 /* [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-PNObject_Example/Pods-PNObject_Example-frameworks.sh\"\n";
|
|
||||||
showEnvVarsInLog = 0;
|
|
||||||
};
|
|
||||||
387C1DBC7D3E0673105ED546 /* [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 # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
|
|
||||||
showEnvVarsInLog = 0;
|
|
||||||
};
|
|
||||||
B84699CAD21D4AE39D658EC6 /* [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-PNObject_Example/Pods-PNObject_Example-resources.sh\"\n";
|
|
||||||
showEnvVarsInLog = 0;
|
|
||||||
};
|
|
||||||
C2D74CFB72423672ACF097D4 /* [CP] Copy Pods Resources */ = {
|
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
@ -376,7 +311,67 @@
|
|||||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-PNObject_Tests/Pods-PNObject_Tests-resources.sh\"\n";
|
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-PNObject_Tests/Pods-PNObject_Tests-resources.sh\"\n";
|
||||||
showEnvVarsInLog = 0;
|
showEnvVarsInLog = 0;
|
||||||
};
|
};
|
||||||
F5E57EFDD9ADE887CAAAC837 /* [CP] Check Pods Manifest.lock */ = {
|
3FF38AA7E586B22171D1A118 /* [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 # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
|
||||||
|
showEnvVarsInLog = 0;
|
||||||
|
};
|
||||||
|
614EA73ED5E0ED0F8684468C /* [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-PNObject_Example/Pods-PNObject_Example-resources.sh\"\n";
|
||||||
|
showEnvVarsInLog = 0;
|
||||||
|
};
|
||||||
|
746A765B48FD98342716D81F /* [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-PNObject_Tests/Pods-PNObject_Tests-frameworks.sh\"\n";
|
||||||
|
showEnvVarsInLog = 0;
|
||||||
|
};
|
||||||
|
C40CC8D7B1996A567BE82827 /* [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-PNObject_Example/Pods-PNObject_Example-frameworks.sh\"\n";
|
||||||
|
showEnvVarsInLog = 0;
|
||||||
|
};
|
||||||
|
E4CE079F616C61EA34D08B8B /* [CP] Check Pods Manifest.lock */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
@ -398,8 +393,8 @@
|
|||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
6003F59E195388D20070C39A /* PNObjectAppDelegate.m in Sources */,
|
6003F59E195388D20070C39A /* PNObjAppDelegate.m in Sources */,
|
||||||
6003F5A7195388D20070C39A /* PNObjectViewController.m in Sources */,
|
6003F5A7195388D20070C39A /* PNObjViewController.m in Sources */,
|
||||||
6003F59A195388D20070C39A /* main.m in Sources */,
|
6003F59A195388D20070C39A /* main.m in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
@ -455,19 +450,14 @@
|
|||||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
CLANG_WARN_EMPTY_BODY = YES;
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
|
||||||
CLANG_WARN_INT_CONVERSION = YES;
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
|
||||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
|
||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
COPY_PHASE_STRIP = NO;
|
COPY_PHASE_STRIP = NO;
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
|
||||||
ENABLE_TESTABILITY = YES;
|
ENABLE_TESTABILITY = YES;
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
GCC_DYNAMIC_NO_PIC = NO;
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
GCC_NO_COMMON_BLOCKS = YES;
|
|
||||||
GCC_OPTIMIZATION_LEVEL = 0;
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
"DEBUG=1",
|
"DEBUG=1",
|
||||||
@ -480,8 +470,8 @@
|
|||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 8.3;
|
||||||
ONLY_ACTIVE_ARCH = NO;
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
};
|
};
|
||||||
@ -500,25 +490,20 @@
|
|||||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
CLANG_WARN_EMPTY_BODY = YES;
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
|
||||||
CLANG_WARN_INT_CONVERSION = YES;
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
|
||||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
|
||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
COPY_PHASE_STRIP = YES;
|
COPY_PHASE_STRIP = YES;
|
||||||
ENABLE_NS_ASSERTIONS = NO;
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
GCC_NO_COMMON_BLOCKS = YES;
|
|
||||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 8.3;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
VALIDATE_PRODUCT = YES;
|
VALIDATE_PRODUCT = YES;
|
||||||
@ -527,15 +512,14 @@
|
|||||||
};
|
};
|
||||||
6003F5C0195388D20070C39A /* Debug */ = {
|
6003F5C0195388D20070C39A /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
baseConfigurationReference = 9898F9E5E65D3B402429FD73 /* Pods-PNObject_Example.debug.xcconfig */;
|
baseConfigurationReference = E20844B85780704FB196FA2A /* Pods-PNObject_Example.debug.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
|
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
|
||||||
CODE_SIGN_ENTITLEMENTS = PNObject_Example.entitlements;
|
DEVELOPMENT_TEAM = 825G85A28E;
|
||||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||||
GCC_PREFIX_HEADER = "PNObject/PNObject-Prefix.pch";
|
GCC_PREFIX_HEADER = "PNObject/PNObject-Prefix.pch";
|
||||||
INFOPLIST_FILE = "PNObject/PNObject-Info.plist";
|
INFOPLIST_FILE = "PNObject/PNObject-Info.plist";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
|
||||||
MODULE_NAME = ExampleApp;
|
MODULE_NAME = ExampleApp;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}";
|
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}";
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
@ -545,15 +529,14 @@
|
|||||||
};
|
};
|
||||||
6003F5C1195388D20070C39A /* Release */ = {
|
6003F5C1195388D20070C39A /* Release */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
baseConfigurationReference = 4082E2E9CCB7F56C1A30AF72 /* Pods-PNObject_Example.release.xcconfig */;
|
baseConfigurationReference = 116AF818F8117B91EF290C9A /* Pods-PNObject_Example.release.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
|
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
|
||||||
CODE_SIGN_ENTITLEMENTS = PNObject_Example.entitlements;
|
DEVELOPMENT_TEAM = 825G85A28E;
|
||||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||||
GCC_PREFIX_HEADER = "PNObject/PNObject-Prefix.pch";
|
GCC_PREFIX_HEADER = "PNObject/PNObject-Prefix.pch";
|
||||||
INFOPLIST_FILE = "PNObject/PNObject-Info.plist";
|
INFOPLIST_FILE = "PNObject/PNObject-Info.plist";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
|
||||||
MODULE_NAME = ExampleApp;
|
MODULE_NAME = ExampleApp;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}";
|
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}";
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
@ -563,9 +546,8 @@
|
|||||||
};
|
};
|
||||||
6003F5C3195388D20070C39A /* Debug */ = {
|
6003F5C3195388D20070C39A /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
baseConfigurationReference = 9F4B24EF58CA8BC69BFC569B /* Pods-PNObject_Tests.debug.xcconfig */;
|
baseConfigurationReference = A90E0E5930707E3F83662328 /* Pods-PNObject_Tests.debug.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
"$(SDKROOT)/Developer/Library/Frameworks",
|
"$(SDKROOT)/Developer/Library/Frameworks",
|
||||||
@ -588,9 +570,8 @@
|
|||||||
};
|
};
|
||||||
6003F5C4195388D20070C39A /* Release */ = {
|
6003F5C4195388D20070C39A /* Release */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
baseConfigurationReference = 2DBDB9BA06776F1FFBD6EDC3 /* Pods-PNObject_Tests.release.xcconfig */;
|
baseConfigurationReference = C0F786F6B0C2234E3B3A5F30 /* Pods-PNObject_Tests.release.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
"$(SDKROOT)/Developer/Library/Frameworks",
|
"$(SDKROOT)/Developer/Library/Frameworks",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Scheme
|
<Scheme
|
||||||
LastUpgradeVersion = "0820"
|
LastUpgradeVersion = "0720"
|
||||||
version = "1.3">
|
version = "1.3">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
@ -71,29 +71,7 @@
|
|||||||
ReferencedContainer = "container:PNObject.xcodeproj">
|
ReferencedContainer = "container:PNObject.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
</BuildableProductRunnable>
|
</BuildableProductRunnable>
|
||||||
<EnvironmentVariables>
|
|
||||||
<EnvironmentVariable
|
|
||||||
key = "NSZombieEnabled"
|
|
||||||
value = "YES"
|
|
||||||
isEnabled = "YES">
|
|
||||||
</EnvironmentVariable>
|
|
||||||
<EnvironmentVariable
|
|
||||||
key = "NSAutoreleaseFreedObjectCheckEnabled"
|
|
||||||
value = "YES"
|
|
||||||
isEnabled = "YES">
|
|
||||||
</EnvironmentVariable>
|
|
||||||
<EnvironmentVariable
|
|
||||||
key = "NSDebugEnabled"
|
|
||||||
value = "YES"
|
|
||||||
isEnabled = "YES">
|
|
||||||
</EnvironmentVariable>
|
|
||||||
</EnvironmentVariables>
|
|
||||||
<AdditionalOptions>
|
<AdditionalOptions>
|
||||||
<AdditionalOption
|
|
||||||
key = "NSZombieEnabled"
|
|
||||||
value = "YES"
|
|
||||||
isEnabled = "YES">
|
|
||||||
</AdditionalOption>
|
|
||||||
</AdditionalOptions>
|
</AdditionalOptions>
|
||||||
</LaunchAction>
|
</LaunchAction>
|
||||||
<ProfileAction
|
<ProfileAction
|
||||||
|
|||||||
@ -1,123 +1,48 @@
|
|||||||
{
|
{
|
||||||
"images" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
"size" : "29x29",
|
|
||||||
"idiom" : "iphone",
|
"idiom" : "iphone",
|
||||||
"filename" : "Icon-Small.png",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "29x29",
|
"size" : "29x29",
|
||||||
"idiom" : "iphone",
|
|
||||||
"filename" : "Icon-Small@2x.png",
|
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "29x29",
|
|
||||||
"idiom" : "iphone",
|
"idiom" : "iphone",
|
||||||
"filename" : "Icon-Small@3x.png",
|
|
||||||
"scale" : "3x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "40x40",
|
"size" : "40x40",
|
||||||
"idiom" : "iphone",
|
|
||||||
"filename" : "Icon-40@2x.png",
|
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "40x40",
|
|
||||||
"idiom" : "iphone",
|
"idiom" : "iphone",
|
||||||
"filename" : "Icon-40@3x.png",
|
|
||||||
"scale" : "3x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "57x57",
|
|
||||||
"idiom" : "iphone",
|
|
||||||
"filename" : "Icon.png",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "57x57",
|
|
||||||
"idiom" : "iphone",
|
|
||||||
"filename" : "Icon@2x.png",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "60x60",
|
"size" : "60x60",
|
||||||
"idiom" : "iphone",
|
|
||||||
"filename" : "Icon-60@2x.png",
|
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "60x60",
|
"idiom" : "ipad",
|
||||||
"idiom" : "iphone",
|
|
||||||
"filename" : "Icon-60@3x.png",
|
|
||||||
"scale" : "3x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "29x29",
|
"size" : "29x29",
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Icon-Small.png",
|
|
||||||
"scale" : "1x"
|
"scale" : "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"idiom" : "ipad",
|
||||||
"size" : "29x29",
|
"size" : "29x29",
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Icon-Small@2x.png",
|
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"idiom" : "ipad",
|
||||||
"size" : "40x40",
|
"size" : "40x40",
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Icon-40.png",
|
|
||||||
"scale" : "1x"
|
"scale" : "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"idiom" : "ipad",
|
||||||
"size" : "40x40",
|
"size" : "40x40",
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Icon-40@2x.png",
|
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "50x50",
|
|
||||||
"idiom" : "ipad",
|
"idiom" : "ipad",
|
||||||
"filename" : "Icon-Small-50.png",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "50x50",
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Icon-Small-50@2x.png",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "72x72",
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Icon-72.png",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "72x72",
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Icon-72@2x.png",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "76x76",
|
"size" : "76x76",
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Icon-76.png",
|
|
||||||
"scale" : "1x"
|
"scale" : "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"idiom" : "ipad",
|
||||||
"size" : "76x76",
|
"size" : "76x76",
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Icon-76@2x.png",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size" : "83.5x83.5",
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Icon-83.5@2x.png",
|
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@ -125,4 +50,4 @@
|
|||||||
"version" : 1,
|
"version" : 1,
|
||||||
"author" : "xcode"
|
"author" : "xcode"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 188 B |
|
Before Width: | Height: | Size: 353 B |
|
Before Width: | Height: | Size: 523 B |
|
Before Width: | Height: | Size: 523 B |
|
Before Width: | Height: | Size: 958 B |
|
Before Width: | Height: | Size: 317 B |
|
Before Width: | Height: | Size: 722 B |
|
Before Width: | Height: | Size: 341 B |
|
Before Width: | Height: | Size: 782 B |
|
Before Width: | Height: | Size: 899 B |
|
Before Width: | Height: | Size: 245 B |
|
Before Width: | Height: | Size: 458 B |
|
Before Width: | Height: | Size: 170 B |
|
Before Width: | Height: | Size: 263 B |
|
Before Width: | Height: | Size: 387 B |
|
Before Width: | Height: | Size: 261 B |
|
Before Width: | Height: | Size: 505 B |
@ -1,157 +1,46 @@
|
|||||||
{
|
{
|
||||||
"images" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
"extent" : "full-screen",
|
|
||||||
"idiom" : "iphone",
|
|
||||||
"filename" : "Default.png",
|
|
||||||
"orientation" : "portrait",
|
"orientation" : "portrait",
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"extent" : "full-screen",
|
|
||||||
"idiom" : "iphone",
|
"idiom" : "iphone",
|
||||||
"filename" : "Default@2x.png",
|
"extent" : "full-screen",
|
||||||
"minimum-system-version" : "7.0",
|
"minimum-system-version" : "7.0",
|
||||||
"orientation" : "portrait",
|
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"extent" : "full-screen",
|
"orientation" : "portrait",
|
||||||
"idiom" : "iphone",
|
"idiom" : "iphone",
|
||||||
"subtype" : "retina4",
|
"subtype" : "retina4",
|
||||||
"filename" : "Default-568h@2x.png",
|
|
||||||
"orientation" : "portrait",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"extent" : "full-screen",
|
"extent" : "full-screen",
|
||||||
"idiom" : "iphone",
|
|
||||||
"subtype" : "retina4",
|
|
||||||
"filename" : "Default-568h@2x.png",
|
|
||||||
"minimum-system-version" : "7.0",
|
"minimum-system-version" : "7.0",
|
||||||
"orientation" : "portrait",
|
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"orientation" : "portrait",
|
||||||
|
"idiom" : "ipad",
|
||||||
"extent" : "full-screen",
|
"extent" : "full-screen",
|
||||||
"idiom" : "iphone",
|
|
||||||
"filename" : "Default@2x.png",
|
|
||||||
"orientation" : "portrait",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"extent" : "to-status-bar",
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Default~ipad.png",
|
|
||||||
"orientation" : "portrait",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"extent" : "to-status-bar",
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Default~ipad@2x.png",
|
|
||||||
"orientation" : "portrait",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"extent" : "to-status-bar",
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Default~ipad~landscape.png",
|
|
||||||
"orientation" : "landscape",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"extent" : "to-status-bar",
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Default~ipad~landscape@2x.png",
|
|
||||||
"orientation" : "landscape",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"extent" : "full-screen",
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Default~ipad~nostatusbar.png",
|
|
||||||
"minimum-system-version" : "7.0",
|
"minimum-system-version" : "7.0",
|
||||||
"orientation" : "portrait",
|
|
||||||
"scale" : "1x"
|
"scale" : "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"extent" : "full-screen",
|
"orientation" : "landscape",
|
||||||
"idiom" : "ipad",
|
"idiom" : "ipad",
|
||||||
"filename" : "Default~ipad~nostatusbar.png",
|
|
||||||
"orientation" : "portrait",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"extent" : "full-screen",
|
"extent" : "full-screen",
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Default~ipad~nostatusbar@2x.png",
|
|
||||||
"minimum-system-version" : "7.0",
|
"minimum-system-version" : "7.0",
|
||||||
"orientation" : "portrait",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"extent" : "full-screen",
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Default~ipad~nostatusbar@2x.png",
|
|
||||||
"orientation" : "portrait",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"extent" : "full-screen",
|
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Default~ipad~landscape~nostatusbar.png",
|
|
||||||
"minimum-system-version" : "7.0",
|
|
||||||
"orientation" : "landscape",
|
|
||||||
"scale" : "1x"
|
"scale" : "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"extent" : "full-screen",
|
"orientation" : "portrait",
|
||||||
"idiom" : "ipad",
|
"idiom" : "ipad",
|
||||||
"filename" : "Default~ipad~landscape~nostatusbar.png",
|
|
||||||
"orientation" : "landscape",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"extent" : "full-screen",
|
"extent" : "full-screen",
|
||||||
"idiom" : "ipad",
|
|
||||||
"filename" : "Default~ipad~landscape~nostatusbar@2x.png",
|
|
||||||
"minimum-system-version" : "7.0",
|
"minimum-system-version" : "7.0",
|
||||||
"orientation" : "landscape",
|
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"extent" : "full-screen",
|
"orientation" : "landscape",
|
||||||
"idiom" : "ipad",
|
"idiom" : "ipad",
|
||||||
"filename" : "Default~ipad~landscape~nostatusbar@2x.png",
|
|
||||||
"orientation" : "landscape",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"extent" : "full-screen",
|
"extent" : "full-screen",
|
||||||
"idiom" : "iphone",
|
"minimum-system-version" : "7.0",
|
||||||
"subtype" : "736h",
|
|
||||||
"filename" : "Default-Portrait-736h@3x.png",
|
|
||||||
"minimum-system-version" : "8.0",
|
|
||||||
"orientation" : "portrait",
|
|
||||||
"scale" : "3x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"extent" : "full-screen",
|
|
||||||
"idiom" : "iphone",
|
|
||||||
"subtype" : "736h",
|
|
||||||
"filename" : "Default-Landscape-736h@3x.png",
|
|
||||||
"minimum-system-version" : "8.0",
|
|
||||||
"orientation" : "landscape",
|
|
||||||
"scale" : "3x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"extent" : "full-screen",
|
|
||||||
"idiom" : "iphone",
|
|
||||||
"subtype" : "667h",
|
|
||||||
"filename" : "Default-667h@2x.png",
|
|
||||||
"minimum-system-version" : "8.0",
|
|
||||||
"orientation" : "portrait",
|
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@ -159,4 +48,4 @@
|
|||||||
"version" : 1,
|
"version" : 1,
|
||||||
"author" : "xcode"
|
"author" : "xcode"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 58 KiB |
27
Example/PNObject/Main.storyboard
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="7706" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="whP-gf-Uak">
|
||||||
|
<dependencies>
|
||||||
|
<deployment identifier="iOS"/>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
|
||||||
|
</dependencies>
|
||||||
|
<scenes>
|
||||||
|
<!--View Controller-->
|
||||||
|
<scene sceneID="wQg-tq-qST">
|
||||||
|
<objects>
|
||||||
|
<viewController id="whP-gf-Uak" customClass="PNObjViewController" sceneMemberID="viewController">
|
||||||
|
<layoutGuides>
|
||||||
|
<viewControllerLayoutGuide type="top" id="uEw-UM-LJ8"/>
|
||||||
|
<viewControllerLayoutGuide type="bottom" id="Mvr-aV-6Um"/>
|
||||||
|
</layoutGuides>
|
||||||
|
<view key="view" contentMode="scaleToFill" id="TpU-gO-2f1">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
|
</view>
|
||||||
|
</viewController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="tc2-Qw-aMS" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
<point key="canvasLocation" x="305" y="433"/>
|
||||||
|
</scene>
|
||||||
|
</scenes>
|
||||||
|
</document>
|
||||||
15
Example/PNObject/PNObjAppDelegate.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
//
|
||||||
|
// PNObjAppDelegate.h
|
||||||
|
// PNObject
|
||||||
|
//
|
||||||
|
// Created by Giuseppe Nucifora on 12/28/2016.
|
||||||
|
// Copyright (c) 2016 Giuseppe Nucifora. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
@import UIKit;
|
||||||
|
|
||||||
|
@interface PNObjAppDelegate : UIResponder <UIApplicationDelegate>
|
||||||
|
|
||||||
|
@property (strong, nonatomic) UIWindow *window;
|
||||||
|
|
||||||
|
@end
|
||||||
@ -1,36 +1,34 @@
|
|||||||
//
|
//
|
||||||
// PNObjectAppDelegate.m
|
// PNObjAppDelegate.m
|
||||||
// PNObject
|
// PNObject
|
||||||
//
|
//
|
||||||
// Created by Giuseppe Nucifora on 12/28/2015.
|
// Created by Giuseppe Nucifora on 12/28/2016.
|
||||||
// Copyright (c) 2015 Giuseppe Nucifora. All rights reserved.
|
// Copyright (c) 2016 Giuseppe Nucifora. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
#import "PNObjectAppDelegate.h"
|
#import "PNObjAppDelegate.h"
|
||||||
#import "PNObjectViewController.h"
|
|
||||||
|
|
||||||
#import "PNObject.h"
|
#import <PNObject/PNUser.h>
|
||||||
#import "PNUser.h"
|
#import <PNObject/PNAddress.h>
|
||||||
#import "PNAddress.h"
|
#import <PNObject/PNObject+PNObjectConnection.h>
|
||||||
#import "PNObject+PNObjectConnection.h"
|
#import "PNObjViewController.h"
|
||||||
|
|
||||||
#import <FBSDKCoreKit/FBSDKCoreKit.h>
|
#import <FBSDKCoreKit/FBSDKCoreKit.h>
|
||||||
#import <FBSDKLoginKit/FBSDKLoginKit.h>
|
#import <FBSDKLoginKit/FBSDKLoginKit.h>
|
||||||
#import <FBSDKShareKit/FBSDKShareKit.h>
|
#import <FBSDKShareKit/FBSDKShareKit.h>
|
||||||
#import "UIDevice-Hardware.h"
|
#import "UIDevice-Hardware.h"
|
||||||
|
|
||||||
#import "PNInstallation.h"
|
#import <PNObject/PNInstallation.h>
|
||||||
|
|
||||||
|
@implementation PNObjAppDelegate
|
||||||
@implementation PNObjectAppDelegate
|
|
||||||
|
|
||||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
||||||
{
|
{
|
||||||
|
|
||||||
[FBSDKSettings setAppID:@"213761522305123"];
|
[FBSDKSettings setAppID:@"213761522305123"];
|
||||||
|
|
||||||
[[FBSDKApplicationDelegate sharedInstance] application:application didFinishLaunchingWithOptions:launchOptions];
|
[[FBSDKApplicationDelegate sharedInstance] application:application didFinishLaunchingWithOptions:launchOptions];
|
||||||
|
|
||||||
_window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
|
_window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
|
||||||
// Override point for customization after application launch.
|
// Override point for customization after application launch.
|
||||||
|
|
||||||
@ -47,7 +45,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
PNObjectViewController *viewController = [[PNObjectViewController alloc] init];
|
PNObjViewController *viewController = [[PNObjViewController alloc] init];
|
||||||
|
|
||||||
switch ([[UIDevice currentDevice] deviceFamily]) {
|
switch ([[UIDevice currentDevice] deviceFamily]) {
|
||||||
case UIDeviceFamilyiPhone:
|
case UIDeviceFamilyiPhone:
|
||||||
@ -65,17 +63,17 @@
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_window.rootViewController = viewController;
|
_window.rootViewController = viewController;
|
||||||
|
|
||||||
_window.backgroundColor = [UIColor whiteColor];
|
_window.backgroundColor = [UIColor whiteColor];
|
||||||
[_window makeKeyAndVisible];
|
[_window makeKeyAndVisible];
|
||||||
|
|
||||||
/*[PNUser loginCurrentUserWithEmail:@"socials2@giuseppenucifora.com" password:@"asdasdasd" withBlockSuccess:^(PNUser * _Nullable responseObject) {
|
/*[PNUser loginCurrentUserWithEmail:@"socials2@giuseppenucifora.com" password:@"asdasdasd" withBlockSuccess:^(PNUser * _Nullable responseObject) {
|
||||||
|
|
||||||
} failure:^(NSError * _Nonnull error) {
|
} failure:^(NSError * _Nonnull error) {
|
||||||
|
|
||||||
}];*/
|
}];*/
|
||||||
|
|
||||||
if ([PNUser currentUser] && [[PNUser currentUser] isAuthenticated]) {
|
if ([PNUser currentUser] && [[PNUser currentUser] isAuthenticated]) {
|
||||||
NSLogDebug(@"Login in corso...");
|
NSLogDebug(@"Login in corso...");
|
||||||
@ -87,6 +85,7 @@
|
|||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,8 +106,9 @@
|
|||||||
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
|
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)applicationDidBecomeActive:(UIApplication *)application {
|
- (void)applicationDidBecomeActive:(UIApplication *)application
|
||||||
[FBSDKAppEvents activateApp];
|
{
|
||||||
|
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)applicationWillTerminate:(UIApplication *)application
|
- (void)applicationWillTerminate:(UIApplication *)application
|
||||||
@ -116,17 +116,6 @@
|
|||||||
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
|
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)application:(UIApplication *)application
|
|
||||||
openURL:(NSURL *)url
|
|
||||||
sourceApplication:(NSString *)sourceApplication
|
|
||||||
annotation:(id)annotation {
|
|
||||||
return [[FBSDKApplicationDelegate sharedInstance] application:application
|
|
||||||
openURL:url
|
|
||||||
sourceApplication:sourceApplication
|
|
||||||
annotation:annotation];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#pragma mark - Remote Notification
|
#pragma mark - Remote Notification
|
||||||
|
|
||||||
- (void) application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
|
- (void) application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
|
||||||
13
Example/PNObject/PNObjViewController.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
//
|
||||||
|
// PNObjViewController.h
|
||||||
|
// PNObject
|
||||||
|
//
|
||||||
|
// Created by Giuseppe Nucifora on 12/28/2016.
|
||||||
|
// Copyright (c) 2016 Giuseppe Nucifora. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
@import UIKit;
|
||||||
|
|
||||||
|
@interface PNObjViewController : UIViewController
|
||||||
|
|
||||||
|
@end
|
||||||
@ -1,19 +1,19 @@
|
|||||||
//
|
//
|
||||||
// PNObjectViewController.m
|
// PNObjViewController.m
|
||||||
// PNObject
|
// PNObject
|
||||||
//
|
//
|
||||||
// Created by Giuseppe Nucifora on 12/28/2015.
|
// Created by Giuseppe Nucifora on 12/28/2016.
|
||||||
// Copyright (c) 2015 Giuseppe Nucifora. All rights reserved.
|
// Copyright (c) 2016 Giuseppe Nucifora. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
#import "PNObjectViewController.h"
|
#import "PNObjViewController.h"
|
||||||
|
#import <PNObject/PNObject.h>
|
||||||
|
#import <PNObject/PNUser.h>
|
||||||
|
#import <PNObject/PNAddress.h>
|
||||||
|
#import <PNObject/PNObject+PNObjectConnection.h>
|
||||||
#import <PureLayout/PureLayout.h>
|
#import <PureLayout/PureLayout.h>
|
||||||
#import "PNObject.h"
|
|
||||||
#import "PNUser.h"
|
|
||||||
#import "PNAddress.h"
|
|
||||||
#import "PNObject+PNObjectConnection.h"
|
|
||||||
|
|
||||||
@interface PNObjectViewController ()
|
@interface PNObjViewController ()
|
||||||
|
|
||||||
@property (nonatomic) BOOL didSetupConstraints;
|
@property (nonatomic) BOOL didSetupConstraints;
|
||||||
|
|
||||||
@ -23,15 +23,15 @@
|
|||||||
|
|
||||||
@property (nonatomic, strong) UIButton *cancelToken;
|
@property (nonatomic, strong) UIButton *cancelToken;
|
||||||
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation PNObjectViewController
|
@implementation PNObjViewController
|
||||||
|
|
||||||
- (void)viewDidLoad
|
- (void)viewDidLoad
|
||||||
{
|
{
|
||||||
[super viewDidLoad];
|
[super viewDidLoad];
|
||||||
|
// Do any additional setup after loading the view, typically from a nib.
|
||||||
|
|
||||||
_refreshToken = [UIButton newAutoLayoutView];
|
_refreshToken = [UIButton newAutoLayoutView];
|
||||||
[_refreshToken addTarget:self action:@selector(refreshTokenAction) forControlEvents:UIControlEventTouchUpInside];
|
[_refreshToken addTarget:self action:@selector(refreshTokenAction) forControlEvents:UIControlEventTouchUpInside];
|
||||||
[_refreshToken setTitle:@"Refresh Token" forState:UIControlStateNormal];
|
[_refreshToken setTitle:@"Refresh Token" forState:UIControlStateNormal];
|
||||||
@ -39,9 +39,9 @@
|
|||||||
[_refreshToken.layer setBorderColor:[UIColor blackColor].CGColor];
|
[_refreshToken.layer setBorderColor:[UIColor blackColor].CGColor];
|
||||||
[_refreshToken.layer setCornerRadius:4];
|
[_refreshToken.layer setCornerRadius:4];
|
||||||
[_refreshToken.layer setBorderWidth:2];
|
[_refreshToken.layer setBorderWidth:2];
|
||||||
|
|
||||||
[self.view addSubview:_refreshToken];
|
[self.view addSubview:_refreshToken];
|
||||||
|
|
||||||
_apiCall = [UIButton newAutoLayoutView];
|
_apiCall = [UIButton newAutoLayoutView];
|
||||||
[_apiCall addTarget:self action:@selector(apiCallAction) forControlEvents:UIControlEventTouchUpInside];
|
[_apiCall addTarget:self action:@selector(apiCallAction) forControlEvents:UIControlEventTouchUpInside];
|
||||||
[_apiCall setTitle:@"API Call" forState:UIControlStateNormal];
|
[_apiCall setTitle:@"API Call" forState:UIControlStateNormal];
|
||||||
@ -49,9 +49,9 @@
|
|||||||
[_apiCall.layer setBorderColor:[UIColor blackColor].CGColor];
|
[_apiCall.layer setBorderColor:[UIColor blackColor].CGColor];
|
||||||
[_apiCall.layer setCornerRadius:4];
|
[_apiCall.layer setCornerRadius:4];
|
||||||
[_apiCall.layer setBorderWidth:2];
|
[_apiCall.layer setBorderWidth:2];
|
||||||
|
|
||||||
[self.view addSubview:_apiCall];
|
[self.view addSubview:_apiCall];
|
||||||
|
|
||||||
_cancelToken = [UIButton newAutoLayoutView];
|
_cancelToken = [UIButton newAutoLayoutView];
|
||||||
[_cancelToken addTarget:self action:@selector(cancelTokenAction) forControlEvents:UIControlEventTouchUpInside];
|
[_cancelToken addTarget:self action:@selector(cancelTokenAction) forControlEvents:UIControlEventTouchUpInside];
|
||||||
[_cancelToken setTitle:@"Reset Token" forState:UIControlStateNormal];
|
[_cancelToken setTitle:@"Reset Token" forState:UIControlStateNormal];
|
||||||
@ -59,31 +59,31 @@
|
|||||||
[_cancelToken.layer setBorderColor:[UIColor blackColor].CGColor];
|
[_cancelToken.layer setBorderColor:[UIColor blackColor].CGColor];
|
||||||
[_cancelToken.layer setCornerRadius:4];
|
[_cancelToken.layer setCornerRadius:4];
|
||||||
[_cancelToken.layer setBorderWidth:2];
|
[_cancelToken.layer setBorderWidth:2];
|
||||||
|
|
||||||
[self.view addSubview:_cancelToken];
|
[self.view addSubview:_cancelToken];
|
||||||
|
|
||||||
//User * user = [User currentUser];
|
//User * user = [User currentUser];
|
||||||
|
|
||||||
[self.view setNeedsUpdateConstraints];
|
[self.view setNeedsUpdateConstraints];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) updateViewConstraints {
|
- (void) updateViewConstraints {
|
||||||
if (!_didSetupConstraints) {
|
if (!_didSetupConstraints) {
|
||||||
|
|
||||||
_didSetupConstraints = YES;
|
_didSetupConstraints = YES;
|
||||||
|
|
||||||
[self.view autoPinEdgesToSuperviewEdges];
|
[self.view autoPinEdgesToSuperviewEdges];
|
||||||
|
|
||||||
[_refreshToken autoAlignAxisToSuperviewAxis:ALAxisVertical];
|
[_refreshToken autoAlignAxisToSuperviewAxis:ALAxisVertical];
|
||||||
[_refreshToken autoAlignAxisToSuperviewAxis:ALAxisHorizontal];
|
[_refreshToken autoAlignAxisToSuperviewAxis:ALAxisHorizontal];
|
||||||
[_refreshToken autoSetDimension:ALDimensionWidth toSize:140];
|
[_refreshToken autoSetDimension:ALDimensionWidth toSize:140];
|
||||||
[_refreshToken autoSetDimension:ALDimensionHeight toSize:44];
|
[_refreshToken autoSetDimension:ALDimensionHeight toSize:44];
|
||||||
|
|
||||||
[_apiCall autoPinEdge:ALEdgeBottom toEdge:ALEdgeTop ofView:_refreshToken withOffset:-35];
|
[_apiCall autoPinEdge:ALEdgeBottom toEdge:ALEdgeTop ofView:_refreshToken withOffset:-35];
|
||||||
[_apiCall autoAlignAxisToSuperviewAxis:ALAxisVertical];
|
[_apiCall autoAlignAxisToSuperviewAxis:ALAxisVertical];
|
||||||
[_apiCall autoSetDimension:ALDimensionWidth toSize:140];
|
[_apiCall autoSetDimension:ALDimensionWidth toSize:140];
|
||||||
[_apiCall autoSetDimension:ALDimensionHeight toSize:44];
|
[_apiCall autoSetDimension:ALDimensionHeight toSize:44];
|
||||||
|
|
||||||
[_cancelToken autoAlignAxisToSuperviewAxis:ALAxisVertical];
|
[_cancelToken autoAlignAxisToSuperviewAxis:ALAxisVertical];
|
||||||
[_cancelToken autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:_refreshToken withOffset:35];
|
[_cancelToken autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:_refreshToken withOffset:35];
|
||||||
[_cancelToken autoSetDimension:ALDimensionWidth toSize:140];
|
[_cancelToken autoSetDimension:ALDimensionWidth toSize:140];
|
||||||
@ -101,67 +101,68 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void) apiCallAction {
|
- (void) apiCallAction {
|
||||||
|
|
||||||
/*PNObjcPassword *password = [PNObjcPassword new];
|
/*PNObjcPassword *password = [PNObjcPassword new];
|
||||||
[password setPassword:@"asdasdasd"];
|
[password setPassword:@"asdasdasd"];
|
||||||
[password setConfirmPassword:@"asdasdasd"];
|
[password setConfirmPassword:@"asdasdasd"];
|
||||||
|
|
||||||
User *user = [User new];
|
User *user = [User new];
|
||||||
[user setFirstName:@"Giuseppe"];
|
[user setFirstName:@"Giuseppe"];
|
||||||
[user setLastName:@"Nuficora"];
|
[user setLastName:@"Nuficora"];
|
||||||
[user setEmail:@"packman5@giuseppenucifora.com"];
|
[user setEmail:@"packman5@giuseppenucifora.com"];
|
||||||
[user setPassword:password];
|
[user setPassword:password];
|
||||||
[user setHasAcceptedNewsletter:YES];
|
[user setHasAcceptedNewsletter:YES];
|
||||||
[user setHasAcceptedPrivacy:YES];
|
[user setHasAcceptedPrivacy:YES];
|
||||||
*/
|
*/
|
||||||
//[user saveLocally];
|
//[user saveLocally];
|
||||||
|
|
||||||
NSLog(@"%@",[[PNUser currentUser] JSONFormObject]);
|
NSLog(@"%@",[[PNUser currentUser] JSONFormObject]);
|
||||||
//NSLog(@"%@",[user JSONObjectMap]);
|
//NSLog(@"%@",[user JSONObjectMap]);
|
||||||
/*[user registerWithBlockSuccess:^(PNUser * _Nullable responseObject) {
|
/*[user registerWithBlockSuccess:^(PNUser * _Nullable responseObject) {
|
||||||
|
|
||||||
} failure:^(NSError * _Nonnull error) {
|
} failure:^(NSError * _Nonnull error) {
|
||||||
|
|
||||||
}];*/
|
}];*/
|
||||||
|
|
||||||
/*[[User currentUser] socialLoginWithBlockSuccessFromViewController:self
|
/*[[User currentUser] socialLoginWithBlockSuccessFromViewController:self
|
||||||
blockSuccess:^(PNUser * _Nullable responseObject) {
|
blockSuccess:^(PNUser * _Nullable responseObject) {
|
||||||
|
|
||||||
} failure:^(NSError * _Nonnull error) {
|
} failure:^(NSError * _Nonnull error) {
|
||||||
|
|
||||||
}];*/
|
}];*/
|
||||||
|
|
||||||
//User * user = [User currentUser];
|
//User * user = [User currentUser];
|
||||||
|
|
||||||
//if ([user isAuthenticated]) {
|
//if ([user isAuthenticated]) {
|
||||||
|
|
||||||
/*[User loginCurrentUserWithEmail:@"demo@packman.example" password:@"demo@packman.example" withBlockSuccess:^(PNUser * _Nullable responseObject) {
|
/*[User loginCurrentUserWithEmail:@"demo@packman.example" password:@"demo@packman.example" withBlockSuccess:^(PNUser * _Nullable responseObject) {
|
||||||
|
|
||||||
NSLog(@"response : %@",responseObject);
|
NSLog(@"response : %@",responseObject);
|
||||||
|
|
||||||
NSLog(@"%@",[User currentUser]);
|
NSLog(@"%@",[User currentUser]);
|
||||||
} failure:^(NSError * _Nonnull error) {
|
} failure:^(NSError * _Nonnull error) {
|
||||||
NSLog(@"response : %@",error);
|
NSLog(@"response : %@",error);
|
||||||
}];*/
|
}];*/
|
||||||
|
|
||||||
[PNUser socialLoginWithBlockSuccess:^(PNUser * _Nullable responseObject) {
|
[PNUser socialLoginWithBlockSuccess:^(PNUser * _Nullable responseObject) {
|
||||||
|
|
||||||
} failure:^(NSError * _Nonnull error) {
|
} failure:^(NSError * _Nonnull error) {
|
||||||
|
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*[User resetPasswordForEmail:@"packman@giuseppenucifora.com" Progress:^(NSProgress * _Nonnull uploadProgress) {
|
/*[User resetPasswordForEmail:@"packman@giuseppenucifora.com" Progress:^(NSProgress * _Nonnull uploadProgress) {
|
||||||
|
|
||||||
} Success:^(NSDictionary * _Nullable responseObject) {
|
} Success:^(NSDictionary * _Nullable responseObject) {
|
||||||
|
|
||||||
} failure:^(NSError * _Nonnull error) {
|
} failure:^(NSError * _Nonnull error) {
|
||||||
|
|
||||||
}];*/
|
}];*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void)didReceiveMemoryWarning
|
- (void)didReceiveMemoryWarning
|
||||||
{
|
{
|
||||||
[super didReceiveMemoryWarning];
|
[super didReceiveMemoryWarning];
|
||||||
@ -24,6 +24,25 @@
|
|||||||
<string>1.0</string>
|
<string>1.0</string>
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
<true/>
|
<true/>
|
||||||
|
<key>UIMainStoryboardFile</key>
|
||||||
|
<string>Main</string>
|
||||||
|
<key>UIRequiredDeviceCapabilities</key>
|
||||||
|
<array>
|
||||||
|
<string>armv7</string>
|
||||||
|
</array>
|
||||||
|
<key>UISupportedInterfaceOrientations</key>
|
||||||
|
<array>
|
||||||
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
|
</array>
|
||||||
|
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||||
|
<array>
|
||||||
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
|
</array>
|
||||||
<key>NSAppTransportSecurity</key>
|
<key>NSAppTransportSecurity</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>NSAllowsArbitraryLoads</key>
|
<key>NSAllowsArbitraryLoads</key>
|
||||||
@ -64,26 +83,6 @@
|
|||||||
</dict>
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
<key>UIRequiredDeviceCapabilities</key>
|
|
||||||
<array>
|
|
||||||
<string>armv7</string>
|
|
||||||
</array>
|
|
||||||
<key>UIRequiresFullScreen</key>
|
|
||||||
<true/>
|
|
||||||
<key>UISupportedInterfaceOrientations</key>
|
|
||||||
<array>
|
|
||||||
<string>UIInterfaceOrientationPortrait</string>
|
|
||||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
|
||||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
|
||||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
|
||||||
</array>
|
|
||||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
|
||||||
<array>
|
|
||||||
<string>UIInterfaceOrientationPortrait</string>
|
|
||||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
|
||||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
|
||||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
|
||||||
</array>
|
|
||||||
<key>CFBundleURLTypes</key>
|
<key>CFBundleURLTypes</key>
|
||||||
<array>
|
<array>
|
||||||
<dict>
|
<dict>
|
||||||
|
|||||||
@ -1,15 +0,0 @@
|
|||||||
//
|
|
||||||
// PNObjectAppDelegate.h
|
|
||||||
// PNObject
|
|
||||||
//
|
|
||||||
// Created by Giuseppe Nucifora on 12/28/2015.
|
|
||||||
// Copyright (c) 2015 Giuseppe Nucifora. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
@import UIKit;
|
|
||||||
|
|
||||||
@interface PNObjectAppDelegate : UIResponder <UIApplicationDelegate>
|
|
||||||
|
|
||||||
@property (strong, nonatomic) UIWindow *window;
|
|
||||||
|
|
||||||
@end
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
//
|
|
||||||
// PNObjectViewController.h
|
|
||||||
// PNObject
|
|
||||||
//
|
|
||||||
// Created by Giuseppe Nucifora on 12/28/2015.
|
|
||||||
// Copyright (c) 2015 Giuseppe Nucifora. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
@import UIKit;
|
|
||||||
|
|
||||||
@interface PNObjectViewController : UIViewController
|
|
||||||
|
|
||||||
@end
|
|
||||||
@ -2,16 +2,16 @@
|
|||||||
// main.m
|
// main.m
|
||||||
// PNObject
|
// PNObject
|
||||||
//
|
//
|
||||||
// Created by Giuseppe Nucifora on 12/28/2015.
|
// Created by Giuseppe Nucifora on 12/28/2016.
|
||||||
// Copyright (c) 2015 Giuseppe Nucifora. All rights reserved.
|
// Copyright (c) 2016 Giuseppe Nucifora. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
@import UIKit;
|
@import UIKit;
|
||||||
#import "PNObjectAppDelegate.h"
|
#import "PNObjAppDelegate.h"
|
||||||
|
|
||||||
int main(int argc, char * argv[])
|
int main(int argc, char * argv[])
|
||||||
{
|
{
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
return UIApplicationMain(argc, argv, nil, NSStringFromClass([PNObjectAppDelegate class]));
|
return UIApplicationMain(argc, argv, nil, NSStringFromClass([PNObjAppDelegate class]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>aps-environment</key>
|
|
||||||
<string>development</string>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@ -1,27 +1,13 @@
|
|||||||
source 'https://github.com/CocoaPods/Specs.git'
|
|
||||||
use_frameworks!
|
use_frameworks!
|
||||||
|
|
||||||
target 'PNObject_Example' do
|
target 'PNObject_Example' do
|
||||||
pod 'PNObject', :path => '../'
|
pod 'PNObject', :path => '../'
|
||||||
pod 'PEAR-FileManager-iOS'
|
pod 'PureLayout'
|
||||||
pod 'NSDate_Utils'
|
|
||||||
pod 'UIDevice-Utils'
|
|
||||||
pod 'AFNetworking'
|
|
||||||
pod 'nv-ios-http-status'
|
|
||||||
pod 'NSString-Helper'
|
|
||||||
pod 'CodFis-Helper'
|
|
||||||
pod 'StrongestPasswordValidator'
|
|
||||||
pod 'PureLayout'
|
|
||||||
pod 'FBSDKCoreKit'
|
|
||||||
pod 'FBSDKShareKit'
|
|
||||||
pod 'FBSDKLoginKit'
|
|
||||||
|
|
||||||
end
|
target 'PNObject_Tests' do
|
||||||
|
inherit! :search_paths
|
||||||
|
|
||||||
target 'PNObject_Tests' do
|
|
||||||
pod 'PNObject', :path => '../'
|
|
||||||
pod 'Specta'
|
pod 'Specta'
|
||||||
pod 'Expecta'
|
pod 'Expecta'
|
||||||
pod 'FBSnapshotTestCase'
|
end
|
||||||
pod 'Expecta+Snapshots'
|
|
||||||
end
|
end
|
||||||
|
|||||||
@ -22,40 +22,35 @@ PODS:
|
|||||||
- Bolts/Tasks (1.8.4)
|
- Bolts/Tasks (1.8.4)
|
||||||
- CocoaSecurity (1.2.4)
|
- CocoaSecurity (1.2.4)
|
||||||
- CodFis-Helper (0.1.3)
|
- CodFis-Helper (0.1.3)
|
||||||
|
- DDDKeychainWrapper (1.0.0)
|
||||||
- DJLocalization (1.2.2):
|
- DJLocalization (1.2.2):
|
||||||
- DJLocalization/Core (= 1.2.2)
|
- DJLocalization/Core (= 1.2.2)
|
||||||
- DJLocalization/Core (1.2.2)
|
- DJLocalization/Core (1.2.2)
|
||||||
- Expecta (1.0.5)
|
- Expecta (1.0.5)
|
||||||
- Expecta+Snapshots (3.0.0):
|
|
||||||
- Expecta (~> 1.0)
|
|
||||||
- FBSnapshotTestCase/Core (~> 2.0)
|
|
||||||
- Specta (~> 1.0)
|
|
||||||
- FBSDKCoreKit (4.18.0):
|
- FBSDKCoreKit (4.18.0):
|
||||||
- Bolts (~> 1.7)
|
- Bolts (~> 1.7)
|
||||||
- FBSDKLoginKit (4.18.0):
|
- FBSDKLoginKit (4.18.0):
|
||||||
- FBSDKCoreKit
|
- FBSDKCoreKit
|
||||||
- FBSDKShareKit (4.18.0):
|
- FBSDKShareKit (4.18.0):
|
||||||
- FBSDKCoreKit
|
- FBSDKCoreKit
|
||||||
- FBSnapshotTestCase (2.1.4):
|
- libsodium (1.0.11)
|
||||||
- FBSnapshotTestCase/SwiftSupport (= 2.1.4)
|
- NAChloride (2.2.1):
|
||||||
- FBSnapshotTestCase/Core (2.1.4)
|
- libsodium
|
||||||
- FBSnapshotTestCase/SwiftSupport (2.1.4):
|
- NSDate_Utils (1.0.0)
|
||||||
- FBSnapshotTestCase/Core
|
|
||||||
- NACrypto (1.0.6)
|
|
||||||
- NSDate_Utils (0.1.3)
|
|
||||||
- NSString-Helper (1.0.5)
|
- NSString-Helper (1.0.5)
|
||||||
- NSUserDefaults-AESEncryptor (0.0.4):
|
- NSUserDefaults-AESEncryptor (0.0.4):
|
||||||
- CocoaSecurity (~> 1.2.2)
|
- CocoaSecurity (~> 1.2.2)
|
||||||
- nv-ios-http-status (0.0.1)
|
- nv-ios-http-status (0.0.1)
|
||||||
- PEAR-FileManager-iOS (1.3.1)
|
- PEAR-FileManager-iOS (1.3.1)
|
||||||
- PNObject (0.9.0):
|
- PNObject (1.0.0):
|
||||||
- AFNetworking
|
- AFNetworking
|
||||||
- CodFis-Helper
|
- CodFis-Helper
|
||||||
|
- DDDKeychainWrapper
|
||||||
- DJLocalization
|
- DJLocalization
|
||||||
- FBSDKCoreKit
|
- FBSDKCoreKit
|
||||||
- FBSDKLoginKit
|
- FBSDKLoginKit
|
||||||
- FBSDKShareKit
|
- FBSDKShareKit
|
||||||
- NACrypto
|
- NAChloride
|
||||||
- NSDate_Utils
|
- NSDate_Utils
|
||||||
- NSString-Helper
|
- NSString-Helper
|
||||||
- NSUserDefaults-AESEncryptor
|
- NSUserDefaults-AESEncryptor
|
||||||
@ -71,23 +66,10 @@ PODS:
|
|||||||
- UIDevice-Utils (0.1.6)
|
- UIDevice-Utils (0.1.6)
|
||||||
|
|
||||||
DEPENDENCIES:
|
DEPENDENCIES:
|
||||||
- AFNetworking
|
|
||||||
- CodFis-Helper
|
|
||||||
- Expecta
|
- Expecta
|
||||||
- Expecta+Snapshots
|
|
||||||
- FBSDKCoreKit
|
|
||||||
- FBSDKLoginKit
|
|
||||||
- FBSDKShareKit
|
|
||||||
- FBSnapshotTestCase
|
|
||||||
- NSDate_Utils
|
|
||||||
- NSString-Helper
|
|
||||||
- nv-ios-http-status
|
|
||||||
- PEAR-FileManager-iOS
|
|
||||||
- PNObject (from `../`)
|
- PNObject (from `../`)
|
||||||
- PureLayout
|
- PureLayout
|
||||||
- Specta
|
- Specta
|
||||||
- StrongestPasswordValidator
|
|
||||||
- UIDevice-Utils
|
|
||||||
|
|
||||||
EXTERNAL SOURCES:
|
EXTERNAL SOURCES:
|
||||||
PNObject:
|
PNObject:
|
||||||
@ -98,26 +80,26 @@ SPEC CHECKSUMS:
|
|||||||
Bolts: 8a7995239dbe724f9cba2248b766d48b7ebdd322
|
Bolts: 8a7995239dbe724f9cba2248b766d48b7ebdd322
|
||||||
CocoaSecurity: d288a6f87e0f363823d2cb83e753814a6944f71a
|
CocoaSecurity: d288a6f87e0f363823d2cb83e753814a6944f71a
|
||||||
CodFis-Helper: 28be4c74d7202542459d72354f59b1215871de87
|
CodFis-Helper: 28be4c74d7202542459d72354f59b1215871de87
|
||||||
|
DDDKeychainWrapper: e681a4daba6448786fa83b4941f58102a33b1897
|
||||||
DJLocalization: 0c84029af375647d4104a42ae36be87194c46c47
|
DJLocalization: 0c84029af375647d4104a42ae36be87194c46c47
|
||||||
Expecta: e1c022fcd33910b6be89c291d2775b3fe27a89fe
|
Expecta: e1c022fcd33910b6be89c291d2775b3fe27a89fe
|
||||||
Expecta+Snapshots: c343f410c7a6392f3e22e78f94c44b6c0749a516
|
|
||||||
FBSDKCoreKit: 15fef8804a4629f98c6f4e55e81a76c9d725d85e
|
FBSDKCoreKit: 15fef8804a4629f98c6f4e55e81a76c9d725d85e
|
||||||
FBSDKLoginKit: 6773073e970b2b15fb12e451ce7f11da0532b880
|
FBSDKLoginKit: 6773073e970b2b15fb12e451ce7f11da0532b880
|
||||||
FBSDKShareKit: 0b8d6cc3f103c75297eb3c62caec284a2ccf1b9e
|
FBSDKShareKit: 0b8d6cc3f103c75297eb3c62caec284a2ccf1b9e
|
||||||
FBSnapshotTestCase: '094f9f314decbabe373b87cc339bea235a63e07a'
|
libsodium: 9aba161d2ee096977ecbdcce1ada69ffe511970c
|
||||||
NACrypto: ce3900f1775f1b0cc27ce7c4953b94c598a74149
|
NAChloride: 8f3d4f9a20df6b68840789a22a70aa4fcc437b0c
|
||||||
NSDate_Utils: 68669d2c81f310ee13026c791f4f0ed227b94c65
|
NSDate_Utils: 45d47afab329001ccafe056308d0cc05460e5298
|
||||||
NSString-Helper: 459e1b6a62b3bf7db10f01b0d102548608e945c4
|
NSString-Helper: 459e1b6a62b3bf7db10f01b0d102548608e945c4
|
||||||
NSUserDefaults-AESEncryptor: da02cfef056f1e18ebe2748767915f08b274c9c5
|
NSUserDefaults-AESEncryptor: da02cfef056f1e18ebe2748767915f08b274c9c5
|
||||||
nv-ios-http-status: b6c2b5fc8656cc19e0d3000dadce2080b99d0e2f
|
nv-ios-http-status: b6c2b5fc8656cc19e0d3000dadce2080b99d0e2f
|
||||||
PEAR-FileManager-iOS: 3bc403f68a53483f5629aa822f4649e40275c4d3
|
PEAR-FileManager-iOS: 3bc403f68a53483f5629aa822f4649e40275c4d3
|
||||||
PNObject: f8d8116d0f72252552bddcbc3703d6d1e4719354
|
PNObject: 34839792d6fcc437b3123d0770b4d45e845bf2c9
|
||||||
PureLayout: 4d550abe49a94f24c2808b9b95db9131685fe4cd
|
PureLayout: 4d550abe49a94f24c2808b9b95db9131685fe4cd
|
||||||
RZDataBinding: 6981e90ddaae2f5e02028323b1043f8c31013109
|
RZDataBinding: 6981e90ddaae2f5e02028323b1043f8c31013109
|
||||||
Specta: ac94d110b865115fe60ff2c6d7281053c6f8e8a2
|
Specta: ac94d110b865115fe60ff2c6d7281053c6f8e8a2
|
||||||
StrongestPasswordValidator: 921e42615bdf353513c6f925bffd4fc29865dbd7
|
StrongestPasswordValidator: 921e42615bdf353513c6f925bffd4fc29865dbd7
|
||||||
UIDevice-Utils: 11c10b18d3c6489b45a97436e5ae6064a3622820
|
UIDevice-Utils: 11c10b18d3c6489b45a97436e5ae6064a3622820
|
||||||
|
|
||||||
PODFILE CHECKSUM: 7c7096ec3fa75c9e7a1d2b538e5719592b9f5e60
|
PODFILE CHECKSUM: 57090c7ea88a91b49ca8dd73d9e7c6b866e772ba
|
||||||
|
|
||||||
COCOAPODS: 1.2.0.beta.1
|
COCOAPODS: 1.2.0.beta.1
|
||||||
|
|||||||
@ -1,6 +1,4 @@
|
|||||||
The MIT License (MIT)
|
Copyright (c) 2014 axldyb <aksel.dybdal@shortcut.no>
|
||||||
|
|
||||||
Copyright (c) 2015 Gabriel Handford
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
@ -9,14 +7,13 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||||||
copies of the Software, and to permit persons to whom the Software is
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
furnished to do so, subject to the following conditions:
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
The above copyright notice and this permission notice shall be included in
|
||||||
copies or substantial portions of the Software.
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
SOFTWARE.
|
THE SOFTWARE.
|
||||||
|
|
||||||
46
Example/Pods/DDDKeychainWrapper/Pod/Classes/DDDKeychainWrapper.h
generated
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
//
|
||||||
|
// DDDKeychainWrapper.h
|
||||||
|
// Aksel Dybdal
|
||||||
|
//
|
||||||
|
// Created by Aksel Dybdal on 02.04.14.
|
||||||
|
// Copyright (c) 2014 Aksel Dybdal. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
/**
|
||||||
|
A small wrapper for Keychain access.
|
||||||
|
|
||||||
|
Inspired by:
|
||||||
|
http://useyourloaf.com/blog/2010/03/29/simple-iphone-keychain-access.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
@interface DDDKeychainWrapper : NSObject
|
||||||
|
|
||||||
|
+ (void)setString:(NSString *)string forKey:(NSString *)key;
|
||||||
|
+ (NSString *)stringForKey:(NSString *)key;
|
||||||
|
|
||||||
|
+ (void)setDate:(NSDate *)date forKey:(NSString *)key;
|
||||||
|
+ (NSDate *)dateForKey:(NSString *)key;
|
||||||
|
|
||||||
|
+ (void)setData:(NSData *)data forKey:(NSString *)key;
|
||||||
|
+ (NSData *)dataForKey:(NSString *)key;
|
||||||
|
|
||||||
|
+ (void)setArray:(NSArray *)array forKey:(NSString *)key;
|
||||||
|
+ (NSArray *)arrayForKey:(NSString *)key;
|
||||||
|
|
||||||
|
+ (void)setDictionary:(NSDictionary *)dictionary forKey:(NSString *)key;
|
||||||
|
+ (NSDictionary *)dictionaryForKey:(NSString *)key;
|
||||||
|
|
||||||
|
+ (void)setNumber:(NSNumber *)number forKey:(NSString *)key;
|
||||||
|
+ (NSNumber *)numberForKey:(NSString *)key;
|
||||||
|
|
||||||
|
+ (void)setBoolean:(BOOL)boolean forKey:(NSString *)key;
|
||||||
|
+ (BOOL)booleanForKey:(NSString *)key;
|
||||||
|
|
||||||
|
+ (void)setObject:(id)object forKey:(NSString *)key;
|
||||||
|
+ (id)objectForKey:(NSString *)key;
|
||||||
|
|
||||||
|
+ (void)wipeKeychain;
|
||||||
|
|
||||||
|
@end
|
||||||
373
Example/Pods/DDDKeychainWrapper/Pod/Classes/DDDKeychainWrapper.m
generated
Normal file
@ -0,0 +1,373 @@
|
|||||||
|
//
|
||||||
|
// DDDKeychainWrapper.m
|
||||||
|
// Aksel Dybdal
|
||||||
|
//
|
||||||
|
// Created by Aksel Dybdal on 02.04.14.
|
||||||
|
// Copyright (c) 2014 Aksel Dybdal. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "DDDKeychainWrapper.h"
|
||||||
|
#import <Security/Security.h>
|
||||||
|
|
||||||
|
typedef NS_ENUM(NSUInteger, DDDKeychainWrapperErrorCode) {
|
||||||
|
DDDKeychainWrapperErrorCreatingKeychainValue = 1,
|
||||||
|
DDDKeychainWrapperErrorUpdatingKeychainValue,
|
||||||
|
DDDKeychainWrapperErrorDeletingKeychainValue,
|
||||||
|
DDDKeychainWrapperErrorSearchingKeychainValue
|
||||||
|
};
|
||||||
|
|
||||||
|
NSString *const kDDDKeychainWrapperServiceName = @"com.dddkeychainwrapper.keychainService";
|
||||||
|
NSString *const kDDDKeychainWrapperErrorDomain = @"DDDKeychainWrapperErrorDomain";
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
# warning "Including NSLog"
|
||||||
|
# define DDDLOG(s, ...) NSLog(s, ## __VA_ARGS__)
|
||||||
|
#else
|
||||||
|
# define DDDLOG(s, ...) while(0){}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
@implementation DDDKeychainWrapper
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark - String
|
||||||
|
|
||||||
|
+ (void)setString:(NSString *)string forKey:(NSString *)key
|
||||||
|
{
|
||||||
|
NSData *stringData = [string dataUsingEncoding:NSUTF8StringEncoding];
|
||||||
|
[self setData:stringData forIdentifier:key];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSString *)stringForKey:(NSString *)key
|
||||||
|
{
|
||||||
|
NSData *stringData = [self dataForIdentifier:key];
|
||||||
|
return [[NSString alloc] initWithData:stringData encoding:NSUTF8StringEncoding];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark - Date
|
||||||
|
|
||||||
|
+ (void)setDate:(NSDate *)date forKey:(NSString *)key
|
||||||
|
{
|
||||||
|
NSData *dateData = [NSKeyedArchiver archivedDataWithRootObject:date];
|
||||||
|
[self setData:dateData forIdentifier:key];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSDate *)dateForKey:(NSString *)key
|
||||||
|
{
|
||||||
|
NSData *dateData = [self dataForIdentifier:key];
|
||||||
|
return (NSDate *)[NSKeyedUnarchiver unarchiveObjectWithData:dateData];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark - Data
|
||||||
|
|
||||||
|
+ (void)setData:(NSData *)data forKey:(NSString *)key
|
||||||
|
{
|
||||||
|
[self setData:data forIdentifier:key];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSData *)dataForKey:(NSString *)key
|
||||||
|
{
|
||||||
|
return [self dataForIdentifier:key];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark - Array
|
||||||
|
|
||||||
|
+ (void)setArray:(NSArray *)array forKey:(NSString *)key
|
||||||
|
{
|
||||||
|
for (id obj in array) {
|
||||||
|
NSAssert([obj conformsToProtocol:@protocol(NSCoding)], @"Objects must confirm to NSCoding protocol in order to be stored in keychain");
|
||||||
|
}
|
||||||
|
|
||||||
|
NSData *arrayData = [NSKeyedArchiver archivedDataWithRootObject:array];
|
||||||
|
[self setData:arrayData forIdentifier:key];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSArray *)arrayForKey:(NSString *)key
|
||||||
|
{
|
||||||
|
NSData *arrayData = [self dataForIdentifier:key];
|
||||||
|
return (NSArray *)[NSKeyedUnarchiver unarchiveObjectWithData:arrayData];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark - Dictionary
|
||||||
|
|
||||||
|
+ (void)setDictionary:(NSDictionary *)dictionary forKey:(NSString *)key
|
||||||
|
{
|
||||||
|
[dictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
|
||||||
|
NSAssert([key conformsToProtocol:@protocol(NSCoding)], @"Keys must confirm to NSCoding protocol in order to be stored in keychain");
|
||||||
|
NSAssert([obj conformsToProtocol:@protocol(NSCoding)], @"Objects must confirm to NSCoding protocol in order to be stored in keychain");
|
||||||
|
}];
|
||||||
|
|
||||||
|
NSData *dictionaryData = [NSKeyedArchiver archivedDataWithRootObject:dictionary];
|
||||||
|
[self setData:dictionaryData forIdentifier:key];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSDictionary *)dictionaryForKey:(NSString *)key
|
||||||
|
{
|
||||||
|
NSData *dictionaryData = [self dataForIdentifier:key];
|
||||||
|
return (NSDictionary *)[NSKeyedUnarchiver unarchiveObjectWithData:dictionaryData];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark - Number
|
||||||
|
|
||||||
|
+ (void)setNumber:(NSNumber *)number forKey:(NSString *)key
|
||||||
|
{
|
||||||
|
NSData *numberData = [NSKeyedArchiver archivedDataWithRootObject:number];
|
||||||
|
[self setData:numberData forIdentifier:key];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSNumber *)numberForKey:(NSString *)key
|
||||||
|
{
|
||||||
|
NSData *numberData = [self dataForIdentifier:key];
|
||||||
|
return (NSNumber *)[NSKeyedUnarchiver unarchiveObjectWithData:numberData];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark - BOOL
|
||||||
|
|
||||||
|
+ (void)setBoolean:(BOOL)boolean forKey:(NSString *)key
|
||||||
|
{
|
||||||
|
NSNumber *boolNumber = [NSNumber numberWithBool:boolean];
|
||||||
|
[self setNumber:boolNumber forKey:key];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (BOOL)booleanForKey:(NSString *)key
|
||||||
|
{
|
||||||
|
NSNumber *boolNumber = [self numberForKey:key];
|
||||||
|
return [boolNumber boolValue];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark - Object
|
||||||
|
|
||||||
|
+ (void)setObject:(id)object forKey:(NSString *)key
|
||||||
|
{
|
||||||
|
NSAssert([object conformsToProtocol:@protocol(NSCoding)], @"Object must confirm to NSCoding protocol in order to be stored in keychain");
|
||||||
|
|
||||||
|
NSData *objectData = [NSKeyedArchiver archivedDataWithRootObject:object];
|
||||||
|
[self setData:objectData forIdentifier:key];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (id)objectForKey:(NSString *)key
|
||||||
|
{
|
||||||
|
NSData *objectData = [self dataForIdentifier:key];
|
||||||
|
return (id)[NSKeyedUnarchiver unarchiveObjectWithData:objectData];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark - Clear Keychain
|
||||||
|
|
||||||
|
+ (void)wipeKeychain
|
||||||
|
{
|
||||||
|
NSArray *secItemClasses = @[(__bridge id)kSecClassGenericPassword,
|
||||||
|
(__bridge id)kSecClassInternetPassword,
|
||||||
|
(__bridge id)kSecClassCertificate,
|
||||||
|
(__bridge id)kSecClassKey,
|
||||||
|
(__bridge id)kSecClassIdentity];
|
||||||
|
|
||||||
|
for (id secItemClass in secItemClasses) {
|
||||||
|
NSDictionary *spec = @{(__bridge id)kSecClass: (id)secItemClass};
|
||||||
|
SecItemDelete((__bridge CFDictionaryRef)spec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark - Private
|
||||||
|
|
||||||
|
+ (void)setData:(NSData *)data forIdentifier:(NSString *)identifier
|
||||||
|
{
|
||||||
|
NSError *error = nil;
|
||||||
|
|
||||||
|
// If no data provided we assume we want to delete the value
|
||||||
|
if (nil == data || NO == [data bytes]) {
|
||||||
|
[self deleteKeychainValueForIdentifier:identifier error:&error];
|
||||||
|
if (error) {
|
||||||
|
DDDLOG(@"Error deleting keychain value for key: \"%@\" Error: %@", identifier, [error localizedDescription]);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We first look up the key in order to see if we need to update or create the value
|
||||||
|
if ([self searchKeychainCopyMatching:identifier error:&error]) {
|
||||||
|
if (error) {
|
||||||
|
DDDLOG(@"Error finding keychain value for key: \"%@\" Error: %@", identifier, [error localizedDescription]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (![self updateKeychainValue:data forIdentifier:identifier error:&error]) {
|
||||||
|
DDDLOG(@"Error updating keychain value for key: \"%@\" Error: %@", identifier, [error localizedDescription]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (![self createKeychainValue:data forIdentifier:identifier error:&error]) {
|
||||||
|
DDDLOG(@"Error creating keychain value for key: \"%@\" Error: %@", identifier, [error localizedDescription]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSData *)dataForIdentifier:(NSString *)identifier
|
||||||
|
{
|
||||||
|
NSError *error = nil;
|
||||||
|
NSData *stringData = [self searchKeychainCopyMatching:identifier error:&error];
|
||||||
|
if (error) {
|
||||||
|
DDDLOG(@"Error finding keychain value for key: \"%@\" Error: %@", identifier, [error localizedDescription]);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
return stringData;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSMutableDictionary *)newSearchDictionary:(NSString *)identifier
|
||||||
|
{
|
||||||
|
NSMutableDictionary *searchDictionary = [[NSMutableDictionary alloc] init];
|
||||||
|
|
||||||
|
[searchDictionary setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
|
||||||
|
|
||||||
|
NSData *encodedIdentifier = [identifier dataUsingEncoding:NSUTF8StringEncoding];
|
||||||
|
[searchDictionary setObject:encodedIdentifier forKey:(__bridge id)kSecAttrGeneric];
|
||||||
|
[searchDictionary setObject:encodedIdentifier forKey:(__bridge id)kSecAttrAccount];
|
||||||
|
[searchDictionary setObject:(__bridge id)kSecAttrAccessibleAfterFirstUnlock forKey:(__bridge id)kSecAttrAccessible];
|
||||||
|
[searchDictionary setObject:kDDDKeychainWrapperServiceName forKey:(__bridge id)kSecAttrService];
|
||||||
|
|
||||||
|
return searchDictionary;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSData *)searchKeychainCopyMatching:(NSString *)identifier error:(NSError **)error
|
||||||
|
{
|
||||||
|
NSMutableDictionary *searchDictionary = [self newSearchDictionary:identifier];
|
||||||
|
|
||||||
|
[searchDictionary setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
|
||||||
|
[searchDictionary setObject:(__bridge id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData];
|
||||||
|
|
||||||
|
CFDataRef result;
|
||||||
|
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)searchDictionary, (CFTypeRef *)&result);
|
||||||
|
|
||||||
|
if (status != errSecSuccess) {
|
||||||
|
[self keychainError:error forStatus:status domain:DDDKeychainWrapperErrorSearchingKeychainValue];
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSData *data = (__bridge NSData *)result;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (BOOL)createKeychainValue:(NSData *)data forIdentifier:(NSString *)identifier error:(NSError **)error
|
||||||
|
{
|
||||||
|
NSMutableDictionary *dictionary = [self newSearchDictionary:identifier];
|
||||||
|
[dictionary setObject:data forKey:(__bridge id)kSecValueData];
|
||||||
|
|
||||||
|
OSStatus status = SecItemAdd((__bridge CFDictionaryRef)dictionary, NULL);
|
||||||
|
|
||||||
|
if (status == errSecSuccess) {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
[self keychainError:error forStatus:status domain:DDDKeychainWrapperErrorCreatingKeychainValue];
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (BOOL)updateKeychainValue:(NSData *)data forIdentifier:(NSString *)identifier error:(NSError **)error
|
||||||
|
{
|
||||||
|
NSMutableDictionary *searchDictionary = [self newSearchDictionary:identifier];
|
||||||
|
NSMutableDictionary *updateDictionary = [[NSMutableDictionary alloc] init];
|
||||||
|
[updateDictionary setObject:data forKey:(__bridge id)kSecValueData];
|
||||||
|
|
||||||
|
OSStatus status = SecItemUpdate((__bridge CFDictionaryRef)searchDictionary,
|
||||||
|
(__bridge CFDictionaryRef)updateDictionary);
|
||||||
|
|
||||||
|
if (status == errSecSuccess) {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
[self keychainError:error forStatus:status domain:DDDKeychainWrapperErrorUpdatingKeychainValue];
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (BOOL)deleteKeychainValueForIdentifier:(NSString *)identifier error:(NSError **)error
|
||||||
|
{
|
||||||
|
NSMutableDictionary *searchDictionary = [self newSearchDictionary:identifier];
|
||||||
|
OSStatus status = SecItemDelete((__bridge CFDictionaryRef)searchDictionary);
|
||||||
|
|
||||||
|
if (status == errSecSuccess) {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
[self keychainError:error forStatus:status domain:DDDKeychainWrapperErrorDeletingKeychainValue];
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Error
|
||||||
|
|
||||||
|
+ (void)keychainError:(NSError **)error forStatus:(OSStatus)status domain:(NSUInteger)domain
|
||||||
|
{
|
||||||
|
NSString *errorString = @"";
|
||||||
|
|
||||||
|
switch (status) {
|
||||||
|
case errSecUnimplemented:
|
||||||
|
errorString = @"Function or operation not implemented.";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case errSecIO:
|
||||||
|
errorString = @"I/O error (bummers)";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case errSecOpWr:
|
||||||
|
errorString = @"File already open with write permission";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case errSecParam:
|
||||||
|
errorString = @"One or more parameters passed to a function where not valid.";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case errSecAllocate:
|
||||||
|
errorString = @"Failed to allocate memory.";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case errSecUserCanceled:
|
||||||
|
errorString = @"User canceled the operation.";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case errSecBadReq:
|
||||||
|
errorString = @"Bad parameter or invalid state for operation.";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case errSecInternalComponent:
|
||||||
|
errorString = @"errSecInternalComponent";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case errSecNotAvailable:
|
||||||
|
errorString = @"No keychain is available. You may need to restart your computer.";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case errSecDuplicateItem:
|
||||||
|
errorString = @"The specified item already exists in the keychain.";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case errSecItemNotFound:
|
||||||
|
errorString = @"The specified item could not be found in the keychain.";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case errSecInteractionNotAllowed:
|
||||||
|
errorString = @"User interaction is not allowed.";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case errSecDecode:
|
||||||
|
errorString = @"Unable to decode the provided data.";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case errSecAuthFailed:
|
||||||
|
errorString = @"The user name or passphrase you entered is not correct.";
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
errorString = @"Unknown error";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
*error = [NSError errorWithDomain:kDDDKeychainWrapperErrorDomain
|
||||||
|
code:domain
|
||||||
|
userInfo:@{NSLocalizedDescriptionKey: errorString}];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
47
Example/Pods/DDDKeychainWrapper/README.md
generated
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
# DDDKeychainWrapper
|
||||||
|
|
||||||
|
[](https://travis-ci.org/axldyb/DDDKeychainWrapper)
|
||||||
|
[](http://cocoadocs.org/docsets/DDDKeychainWrapper)
|
||||||
|
[](http://cocoadocs.org/docsets/DDDKeychainWrapper)
|
||||||
|
[](http://cocoadocs.org/docsets/DDDKeychainWrapper)
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Storing your sensitive data in the keychain can take up a lot of time and effort. It should be easy to just drop something in there and retrive it with a few simple lines of code. DDDKeychainWrapper offers this simplicity and here is how we do it:
|
||||||
|
|
||||||
|
```objective-c
|
||||||
|
// Writing to the Keychain
|
||||||
|
[DDDKeychainWrapper setString:@"Secret string" forKey:@"my_key"];
|
||||||
|
|
||||||
|
// Reading from the Keychain
|
||||||
|
NSString *secretString = [DDDKeychainWrapper stringForKey:@"my_key"];
|
||||||
|
```
|
||||||
|
|
||||||
|
DDDKeychainWrapper has support for the following types
|
||||||
|
|
||||||
|
* NSString
|
||||||
|
* NSDate
|
||||||
|
* NSData
|
||||||
|
* NSArray
|
||||||
|
* NSDictionary
|
||||||
|
* NSNumber
|
||||||
|
* BOOL
|
||||||
|
* Objects (Must confirm to NSCoding)
|
||||||
|
|
||||||
|
A method for wiping the keychain data inserted via the wrapper exists as well.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
DDDKeychainWrapper is available through [CocoaPods](http://cocoapods.org). To install
|
||||||
|
it, simply add the following line to your Podfile:
|
||||||
|
|
||||||
|
pod "DDDKeychainWrapper"
|
||||||
|
|
||||||
|
## Author
|
||||||
|
|
||||||
|
axldyb, aksel.dybdal@shortcut.no
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
DDDKeychainWrapper is available under the MIT license. See the LICENSE file for more info.
|
||||||
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
#import <Expecta/Expecta.h>
|
|
||||||
#import "ExpectaObject+FBSnapshotTest.h"
|
|
||||||
|
|
||||||
@interface EXPExpectFBSnapshotTest : NSObject
|
|
||||||
@end
|
|
||||||
|
|
||||||
/// Set the default folder for image tests to run in
|
|
||||||
extern void setGlobalReferenceImageDir(char *reference);
|
|
||||||
|
|
||||||
EXPMatcherInterface(haveValidSnapshot, (void));
|
|
||||||
EXPMatcherInterface(recordSnapshot, (void));
|
|
||||||
|
|
||||||
EXPMatcherInterface(haveValidSnapshotNamed, (NSString *snapshot));
|
|
||||||
EXPMatcherInterface(recordSnapshotNamed, (NSString *snapshot));
|
|
||||||
@ -1,284 +0,0 @@
|
|||||||
#import "EXPMatchers+FBSnapshotTest.h"
|
|
||||||
#import <Expecta/EXPMatcherHelpers.h>
|
|
||||||
#import <FBSnapshotTestCase/FBSnapshotTestController.h>
|
|
||||||
|
|
||||||
@interface EXPExpectFBSnapshotTest()
|
|
||||||
@property (nonatomic, strong) NSString *referenceImagesDirectory;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation EXPExpectFBSnapshotTest
|
|
||||||
|
|
||||||
+ (id)instance
|
|
||||||
{
|
|
||||||
static EXPExpectFBSnapshotTest *instance = nil;
|
|
||||||
static dispatch_once_t onceToken;
|
|
||||||
dispatch_once(&onceToken, ^{
|
|
||||||
instance = [[self alloc] init];
|
|
||||||
});
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (BOOL)compareSnapshotOfViewOrLayer:(id)viewOrLayer snapshot:(NSString *)snapshot testCase:(id)testCase record:(BOOL)record referenceDirectory:(NSString *)referenceDirectory error:(NSError **)error
|
|
||||||
|
|
||||||
{
|
|
||||||
FBSnapshotTestController *snapshotController = [[FBSnapshotTestController alloc] initWithTestClass:[testCase class]];
|
|
||||||
snapshotController.recordMode = record;
|
|
||||||
snapshotController.referenceImagesDirectory = referenceDirectory;
|
|
||||||
snapshotController.usesDrawViewHierarchyInRect = [Expecta usesDrawViewHierarchyInRect];
|
|
||||||
|
|
||||||
if (! snapshotController.referenceImagesDirectory) {
|
|
||||||
[NSException raise:@"Missing value for referenceImagesDirectory" format:@"Call [[EXPExpectFBSnapshotTest instance] setReferenceImagesDirectory"];
|
|
||||||
}
|
|
||||||
|
|
||||||
return [snapshotController compareSnapshotOfViewOrLayer:viewOrLayer
|
|
||||||
selector:NSSelectorFromString(snapshot)
|
|
||||||
identifier:nil
|
|
||||||
tolerance:0
|
|
||||||
error:error];
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (NSString *)combinedError:(NSString *)message test:(NSString *)test error:(NSError *)error
|
|
||||||
{
|
|
||||||
NSAssert(message, @"missing message");
|
|
||||||
NSAssert(test, @"missing test name");
|
|
||||||
|
|
||||||
NSMutableArray *ary = [NSMutableArray array];
|
|
||||||
|
|
||||||
[ary addObject:[NSString stringWithFormat:@"%@ %@", message, test]];
|
|
||||||
|
|
||||||
for(NSString *key in error.userInfo.keyEnumerator) {
|
|
||||||
[ary addObject:[NSString stringWithFormat:@" %@: %@", key, [error.userInfo valueForKey:key]]];
|
|
||||||
}
|
|
||||||
|
|
||||||
return [ary componentsJoinedByString:@"\n"];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
void setGlobalReferenceImageDir(char *reference) {
|
|
||||||
NSString *referenceImagesDirectory = [NSString stringWithFormat:@"%s", reference];
|
|
||||||
[[EXPExpectFBSnapshotTest instance] setReferenceImagesDirectory:referenceImagesDirectory];
|
|
||||||
};
|
|
||||||
|
|
||||||
@interface EXPExpect(ReferenceDirExtension)
|
|
||||||
- (NSString *)_getDefaultReferenceDirectory;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation EXPExpect(ReferenceDirExtension)
|
|
||||||
|
|
||||||
- (NSString *)_getDefaultReferenceDirectory
|
|
||||||
{
|
|
||||||
NSString *globalReference = [[EXPExpectFBSnapshotTest instance] referenceImagesDirectory];
|
|
||||||
if (globalReference) {
|
|
||||||
return globalReference;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Search the test file's path to find the first folder with the substring "tests"
|
|
||||||
// then append "/ReferenceImages" and use that
|
|
||||||
|
|
||||||
NSString *testFileName = [NSString stringWithCString:self.fileName encoding:NSUTF8StringEncoding];
|
|
||||||
NSArray *pathComponents = [testFileName pathComponents];
|
|
||||||
|
|
||||||
for (NSString *folder in pathComponents) {
|
|
||||||
if ([folder.lowercaseString rangeOfString:@"tests"].location != NSNotFound) {
|
|
||||||
|
|
||||||
NSArray *folderPathComponents = [pathComponents subarrayWithRange:NSMakeRange(0, [pathComponents indexOfObject:folder] + 1)];
|
|
||||||
return [NSString stringWithFormat:@"%@/ReferenceImages", [folderPathComponents componentsJoinedByString:@"/"]];
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[NSException raise:@"Could not infer reference image folder" format:@"You should provide a reference dir using setGlobalReferenceImageDir(FB_REFERENCE_IMAGE_DIR);"];
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
|
|
||||||
|
|
||||||
#import <Specta/Specta.h>
|
|
||||||
#import <Specta/SpectaUtility.h>
|
|
||||||
#import <Specta/SPTExample.h>
|
|
||||||
|
|
||||||
NSString *sanitizedTestPath();
|
|
||||||
|
|
||||||
NSString *sanitizedTestPath(){
|
|
||||||
id compiledExample = [[NSThread currentThread] threadDictionary][@"SPTCurrentSpec"]; // SPTSpec
|
|
||||||
NSString *name;
|
|
||||||
if ([compiledExample respondsToSelector:@selector(name)]) {
|
|
||||||
// Specta 0.3 syntax
|
|
||||||
name = [compiledExample performSelector:@selector(name)];
|
|
||||||
} else if ([compiledExample respondsToSelector:@selector(fileName)]) {
|
|
||||||
// Specta 0.2 syntax
|
|
||||||
name = [compiledExample performSelector:@selector(fileName)];
|
|
||||||
}
|
|
||||||
name = [[[[name componentsSeparatedByString:@" test_"] lastObject] stringByReplacingOccurrencesOfString:@"__" withString:@"_"] stringByReplacingOccurrencesOfString:@"]" withString:@""];
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
EXPMatcherImplementationBegin(haveValidSnapshot, (void)){
|
|
||||||
__block NSError *error = nil;
|
|
||||||
|
|
||||||
prerequisite(^BOOL{
|
|
||||||
return actual;
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
match(^BOOL{
|
|
||||||
NSString *referenceImageDir = [self _getDefaultReferenceDirectory];
|
|
||||||
NSString *name = sanitizedTestPath();
|
|
||||||
if ([actual isKindOfClass:UIViewController.class]) {
|
|
||||||
[actual beginAppearanceTransition:YES animated:NO];
|
|
||||||
[actual endAppearanceTransition];
|
|
||||||
|
|
||||||
actual = [actual view];
|
|
||||||
}
|
|
||||||
|
|
||||||
return [EXPExpectFBSnapshotTest compareSnapshotOfViewOrLayer:actual snapshot:name testCase:[self testCase] record:NO referenceDirectory:referenceImageDir error:&error];
|
|
||||||
});
|
|
||||||
|
|
||||||
failureMessageForTo(^NSString *{
|
|
||||||
if (!actual) {
|
|
||||||
return [EXPExpectFBSnapshotTest combinedError:@"Nil was passed into haveValidSnapshot." test:sanitizedTestPath() error:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
return [EXPExpectFBSnapshotTest combinedError:@"expected a matching snapshot in" test:sanitizedTestPath() error:error];
|
|
||||||
});
|
|
||||||
|
|
||||||
failureMessageForNotTo(^NSString *{
|
|
||||||
return [EXPExpectFBSnapshotTest combinedError:@"expected to not have a matching snapshot in" test:sanitizedTestPath() error:error];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
EXPMatcherImplementationEnd
|
|
||||||
|
|
||||||
EXPMatcherImplementationBegin(recordSnapshot, (void)) {
|
|
||||||
__block NSError *error = nil;
|
|
||||||
|
|
||||||
BOOL actualIsViewLayerOrViewController = ([actual isKindOfClass:UIView.class] || [actual isKindOfClass:CALayer.class] || [actual isKindOfClass:UIViewController.class]);
|
|
||||||
|
|
||||||
prerequisite(^BOOL{
|
|
||||||
return actual && actualIsViewLayerOrViewController;
|
|
||||||
});
|
|
||||||
|
|
||||||
match(^BOOL{
|
|
||||||
NSString *referenceImageDir = [self _getDefaultReferenceDirectory];
|
|
||||||
|
|
||||||
// For view controllers do the viewWill/viewDid dance, then pass view through
|
|
||||||
if ([actual isKindOfClass:UIViewController.class]) {
|
|
||||||
|
|
||||||
[actual beginAppearanceTransition:YES animated:NO];
|
|
||||||
[actual endAppearanceTransition];
|
|
||||||
actual = [actual view];
|
|
||||||
}
|
|
||||||
|
|
||||||
[EXPExpectFBSnapshotTest compareSnapshotOfViewOrLayer:actual snapshot:sanitizedTestPath() testCase:[self testCase] record:YES referenceDirectory:referenceImageDir error:&error];
|
|
||||||
return NO;
|
|
||||||
});
|
|
||||||
|
|
||||||
failureMessageForTo(^NSString *{
|
|
||||||
if (!actual) {
|
|
||||||
return [EXPExpectFBSnapshotTest combinedError:@"Nil was passed into recordSnapshot." test:sanitizedTestPath() error:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!actualIsViewLayerOrViewController) {
|
|
||||||
return [EXPExpectFBSnapshotTest combinedError:@"Expected a View, Layer or View Controller." test:sanitizedTestPath() error:nil];
|
|
||||||
}
|
|
||||||
if (error) {
|
|
||||||
return [EXPExpectFBSnapshotTest combinedError:@"expected to record a snapshot in" test:sanitizedTestPath() error:error];
|
|
||||||
} else {
|
|
||||||
return [NSString stringWithFormat:@"snapshot %@ successfully recorded, replace recordSnapshot with a check", sanitizedTestPath()];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
failureMessageForNotTo(^NSString *{
|
|
||||||
if (error) {
|
|
||||||
return [EXPExpectFBSnapshotTest combinedError:@"expected to record a snapshot in" test:sanitizedTestPath() error:error];
|
|
||||||
} else {
|
|
||||||
return [NSString stringWithFormat:@"snapshot %@ successfully recorded, replace recordSnapshot with a check", sanitizedTestPath()];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
EXPMatcherImplementationEnd
|
|
||||||
|
|
||||||
EXPMatcherImplementationBegin(haveValidSnapshotNamed, (NSString *snapshot)){
|
|
||||||
BOOL snapshotIsNil = (snapshot == nil);
|
|
||||||
__block NSError *error = nil;
|
|
||||||
|
|
||||||
prerequisite(^BOOL{
|
|
||||||
return actual && !(snapshotIsNil);
|
|
||||||
});
|
|
||||||
|
|
||||||
match(^BOOL{
|
|
||||||
NSString *referenceImageDir = [self _getDefaultReferenceDirectory];
|
|
||||||
if ([actual isKindOfClass:UIViewController.class]) {
|
|
||||||
[actual beginAppearanceTransition:YES animated:NO];
|
|
||||||
[actual endAppearanceTransition];
|
|
||||||
|
|
||||||
actual = [actual view];
|
|
||||||
}
|
|
||||||
return [EXPExpectFBSnapshotTest compareSnapshotOfViewOrLayer:actual snapshot:snapshot testCase:[self testCase] record:NO referenceDirectory:referenceImageDir error:&error];
|
|
||||||
});
|
|
||||||
|
|
||||||
failureMessageForTo(^NSString *{
|
|
||||||
if (!actual) {
|
|
||||||
return [EXPExpectFBSnapshotTest combinedError:@"Nil was passed into haveValidSnapshotNamed." test:sanitizedTestPath() error:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
return [EXPExpectFBSnapshotTest combinedError:@"expected a matching snapshot named" test:snapshot error:error];
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
failureMessageForNotTo(^NSString *{
|
|
||||||
return [EXPExpectFBSnapshotTest combinedError:@"expected not to have a matching snapshot named" test:snapshot error:error];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
EXPMatcherImplementationEnd
|
|
||||||
|
|
||||||
EXPMatcherImplementationBegin(recordSnapshotNamed, (NSString *snapshot)) {
|
|
||||||
BOOL snapshotExists = (snapshot != nil);
|
|
||||||
BOOL actualIsViewLayerOrViewController = ([actual isKindOfClass:UIView.class] || [actual isKindOfClass:CALayer.class] || [actual isKindOfClass:UIViewController.class]);
|
|
||||||
__block NSError *error = nil;
|
|
||||||
id actualRef = actual;
|
|
||||||
|
|
||||||
prerequisite(^BOOL{
|
|
||||||
return actualRef && snapshotExists && actualIsViewLayerOrViewController;
|
|
||||||
});
|
|
||||||
|
|
||||||
match(^BOOL{
|
|
||||||
NSString *referenceImageDir = [self _getDefaultReferenceDirectory];
|
|
||||||
|
|
||||||
// For view controllers do the viewWill/viewDid dance, then pass view through
|
|
||||||
if ([actual isKindOfClass:UIViewController.class]) {
|
|
||||||
[actual beginAppearanceTransition:YES animated:NO];
|
|
||||||
[actual endAppearanceTransition];
|
|
||||||
actual = [actual view];
|
|
||||||
}
|
|
||||||
|
|
||||||
[EXPExpectFBSnapshotTest compareSnapshotOfViewOrLayer:actual snapshot:snapshot testCase:[self testCase] record:YES referenceDirectory:referenceImageDir error:&error];
|
|
||||||
return NO;
|
|
||||||
});
|
|
||||||
|
|
||||||
failureMessageForTo(^NSString *{
|
|
||||||
if (!actual) {
|
|
||||||
return [EXPExpectFBSnapshotTest combinedError:@"Nil was passed into recordSnapshotNamed." test:sanitizedTestPath() error:nil];
|
|
||||||
}
|
|
||||||
if (!actualIsViewLayerOrViewController) {
|
|
||||||
return [EXPExpectFBSnapshotTest combinedError:@"Expected a View, Layer or View Controller." test:snapshot error:nil];
|
|
||||||
}
|
|
||||||
if (error) {
|
|
||||||
return [EXPExpectFBSnapshotTest combinedError:@"expected to record a matching snapshot named" test:snapshot error:error];
|
|
||||||
} else {
|
|
||||||
return [NSString stringWithFormat:@"snapshot %@ successfully recorded, replace recordSnapshot with a check", snapshot];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
failureMessageForNotTo(^NSString *{
|
|
||||||
if (!actualIsViewLayerOrViewController) {
|
|
||||||
return [EXPExpectFBSnapshotTest combinedError:@"Expected a View, Layer or View Controller." test:snapshot error:nil];
|
|
||||||
}
|
|
||||||
if (error) {
|
|
||||||
return [EXPExpectFBSnapshotTest combinedError:@"expected to record a matching snapshot named" test:snapshot error:error];
|
|
||||||
} else {
|
|
||||||
return [NSString stringWithFormat:@"snapshot %@ successfully recorded, replace recordSnapshot with a check", snapshot];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
EXPMatcherImplementationEnd
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
//
|
|
||||||
// ExpectaObject+FBSnapshotTest.h
|
|
||||||
// Expecta+Snapshots
|
|
||||||
//
|
|
||||||
// Created by John Boiles on 8/3/15.
|
|
||||||
// Copyright (c) 2015 Expecta+Snapshots All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import <Expecta/ExpectaObject.h>
|
|
||||||
|
|
||||||
@interface Expecta (FBSnapshotTest)
|
|
||||||
|
|
||||||
+ (void)setUsesDrawViewHierarchyInRect:(BOOL)usesDrawViewHierarchyInRect;
|
|
||||||
|
|
||||||
+ (BOOL)usesDrawViewHierarchyInRect;
|
|
||||||
|
|
||||||
@end
|
|
||||||
@ -1,25 +0,0 @@
|
|||||||
//
|
|
||||||
// ExpectaObject+FBSnapshotTest.m
|
|
||||||
// Expecta+Snapshots
|
|
||||||
//
|
|
||||||
// Created by John Boiles on 8/3/15.
|
|
||||||
// Copyright (c) 2015 Expecta+Snapshots All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import "ExpectaObject+FBSnapshotTest.h"
|
|
||||||
#import <objc/runtime.h>
|
|
||||||
|
|
||||||
static NSString const *kUsesDrawViewHierarchyInRectKey = @"ExpectaObject+FBSnapshotTest.usesDrawViewHierarchyInRect";
|
|
||||||
|
|
||||||
@implementation Expecta (FBSnapshotTest)
|
|
||||||
|
|
||||||
+ (void)setUsesDrawViewHierarchyInRect:(BOOL)usesDrawViewHierarchyInRect {
|
|
||||||
objc_setAssociatedObject(self, (__bridge const void *)(kUsesDrawViewHierarchyInRectKey), @(usesDrawViewHierarchyInRect), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (BOOL)usesDrawViewHierarchyInRect {
|
|
||||||
NSNumber *usesDrawViewHierarchyInRect = objc_getAssociatedObject(self, (__bridge const void *)(kUsesDrawViewHierarchyInRectKey));
|
|
||||||
return usesDrawViewHierarchyInRect.boolValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
22
Example/Pods/Expecta+Snapshots/LICENSE.md
generated
@ -1,22 +0,0 @@
|
|||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2014 Daniel Doubrovkine, Artsy Inc.
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
a copy of this software and associated documentation files (the
|
|
||||||
"Software"), to deal in the Software without restriction, including
|
|
||||||
without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be
|
|
||||||
included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
||||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
87
Example/Pods/Expecta+Snapshots/README.md
generated
@ -1,87 +0,0 @@
|
|||||||
Expecta Matchers for FBSnapshotTestCase
|
|
||||||
=======================================
|
|
||||||
|
|
||||||
[Expecta](https://github.com/specta/expecta) matchers for [ios-snapshot-test-case](https://github.com/facebook/ios-snapshot-test-case).
|
|
||||||
|
|
||||||
[](https://travis-ci.org/dblock/ios-snapshot-test-case-expecta)
|
|
||||||
|
|
||||||
### Usage
|
|
||||||
|
|
||||||
Add `Expecta+Snapshots` to your Podfile, the latest `FBSnapshotTestCase` will come in as a dependency.
|
|
||||||
|
|
||||||
``` ruby
|
|
||||||
pod 'Expecta+Snapshots'
|
|
||||||
```
|
|
||||||
|
|
||||||
### App setup
|
|
||||||
|
|
||||||
Use `expect(view).to.recordSnapshotNamed(@"unique snapshot name")` to record a snapshot and `expect(view).to.haveValidSnapshotNamed(@"unique snapshot name")` to check it.
|
|
||||||
|
|
||||||
If you project was compiled with Specta included, you have two extra methods that use the spec hierarchy to generate the snapshot name for you: `recordSnapshot()` and `haveValidSnapshot()`. You should only call these once per `it()` block.
|
|
||||||
|
|
||||||
If you need the `usesDrawViewHierarchyInRect` property in order to correctly render UIVisualEffect, UIAppearance and Size Classes, call `[Expecta setUsesDrawViewHierarchyInRect:NO];` inside `beforeAll`.
|
|
||||||
|
|
||||||
``` Objective-C
|
|
||||||
#define EXP_SHORTHAND
|
|
||||||
#include <Specta/Specta.h>
|
|
||||||
#include <Expecta/Expecta.h>
|
|
||||||
#include <Expecta+Snapshots/EXPMatchers+FBSnapshotTest.h>
|
|
||||||
#include "FBExampleView.h"
|
|
||||||
|
|
||||||
SpecBegin(FBExampleView)
|
|
||||||
|
|
||||||
describe(@"manual matching", ^{
|
|
||||||
|
|
||||||
it(@"matches view", ^{
|
|
||||||
FBExampleView *view = [[FBExampleView alloc] initWithFrame:CGRectMake(0, 0, 64, 64)];
|
|
||||||
expect(view).to.recordSnapshotNamed(@"FBExampleView");
|
|
||||||
expect(view).to.haveValidSnapshotNamed(@"FBExampleView");
|
|
||||||
});
|
|
||||||
|
|
||||||
it(@"doesn't match a view", ^{
|
|
||||||
FBExampleView *view = [[FBExampleView alloc] initWithFrame:CGRectMake(0, 0, 64, 64)];
|
|
||||||
expect(view).toNot.haveValidSnapshotNamed(@"FBExampleViewDoesNotExist");
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
describe(@"test name derived matching", ^{
|
|
||||||
|
|
||||||
it(@"matches view", ^{
|
|
||||||
FBExampleView *view = [[FBExampleView alloc] initWithFrame:CGRectMake(0, 0, 64, 64)];
|
|
||||||
expect(view).to.recordSnapshot();
|
|
||||||
expect(view).to.haveValidSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
it(@"doesn't match a view", ^{
|
|
||||||
FBExampleView *view = [[FBExampleView alloc] initWithFrame:CGRectMake(0, 0, 64, 64)];
|
|
||||||
expect(view).toNot.haveValidSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
SpecEnd
|
|
||||||
```
|
|
||||||
|
|
||||||
### Sane defaults
|
|
||||||
|
|
||||||
`EXPMatchers+FBSnapshotTest` will automatically figure out the tests folder, and [add a reference image](https://github.com/dblock/ios-snapshot-test-case-expecta/blob/master/EXPMatchers%2BFBSnapshotTest.m#L84-L85) directory, if you'd like to override this, you should include a `beforeAll` block setting the `setGlobalReferenceImageDir` in each file containing tests.
|
|
||||||
|
|
||||||
```
|
|
||||||
beforeAll(^{
|
|
||||||
setGlobalReferenceImageDir(FB_REFERENCE_IMAGE_DIR);
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
### Example
|
|
||||||
|
|
||||||
A complete project can be found in [FBSnapshotTestCaseDemo](FBSnapshotTestCaseDemo).
|
|
||||||
|
|
||||||
Notably, take a look at [FBSnapshotTestCaseDemoSpecs.m](FBSnapshotTestCaseDemo/FBSnapshotTestCaseDemoTests/FBSnapshotTestCaseDemoSpecs.m) for a complete example, which is an expanded Specta version version of [FBSnapshotTestCaseDemoTests.m](https://github.com/facebook/ios-snapshot-test-case/blob/master/FBSnapshotTestCaseDemo/FBSnapshotTestCaseDemoTests/FBSnapshotTestCaseDemoTests.m).
|
|
||||||
|
|
||||||
Finally you can consult the tests for [ARTiledImageView](https://github.com/dblock/ARTiledImageView/tree/master/IntegrationTests) or [NAMapKit](https://github.com/neilang/NAMapKit/tree/master/Demo/DemoTests).
|
|
||||||
|
|
||||||
### License
|
|
||||||
|
|
||||||
MIT, see [LICENSE](LICENSE.md)
|
|
||||||
@ -1,20 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2015, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
|
||||||
|
|
||||||
@interface UIApplication (StrictKeyWindow)
|
|
||||||
|
|
||||||
/**
|
|
||||||
@return The receiver's @c keyWindow. Raises an assertion if @c nil.
|
|
||||||
*/
|
|
||||||
- (UIWindow *)fb_strictKeyWindow;
|
|
||||||
|
|
||||||
@end
|
|
||||||
@ -1,27 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2015, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <FBSnapshotTestCase/UIApplication+StrictKeyWindow.h>
|
|
||||||
|
|
||||||
@implementation UIApplication (StrictKeyWindow)
|
|
||||||
|
|
||||||
- (UIWindow *)fb_strictKeyWindow
|
|
||||||
{
|
|
||||||
UIWindow *keyWindow = [UIApplication sharedApplication].keyWindow;
|
|
||||||
if (!keyWindow) {
|
|
||||||
[NSException raise:@"FBSnapshotTestCaseNilKeyWindowException"
|
|
||||||
format:@"Snapshot tests must be hosted by an application with a key window. Please ensure your test"
|
|
||||||
" host sets up a key window at launch (either via storyboards or programmatically) and doesn't"
|
|
||||||
" do anything to remove it while snapshot tests are running."];
|
|
||||||
}
|
|
||||||
return keyWindow;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
@ -1,37 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by Gabriel Handford on 3/1/09.
|
|
||||||
// Copyright 2009-2013. All rights reserved.
|
|
||||||
// Created by John Boiles on 10/20/11.
|
|
||||||
// Copyright (c) 2011. All rights reserved
|
|
||||||
// Modified by Felix Schulze on 2/11/13.
|
|
||||||
// Copyright 2013. All rights reserved.
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person
|
|
||||||
// obtaining a copy of this software and associated documentation
|
|
||||||
// files (the "Software"), to deal in the Software without
|
|
||||||
// restriction, including without limitation the rights to use,
|
|
||||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the
|
|
||||||
// Software is furnished to do so, subject to the following
|
|
||||||
// conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be
|
|
||||||
// included in all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
||||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
||||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
||||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
||||||
// OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
|
||||||
|
|
||||||
@interface UIImage (Compare)
|
|
||||||
|
|
||||||
- (BOOL)fb_compareWithImage:(UIImage *)image tolerance:(CGFloat)tolerance;
|
|
||||||
|
|
||||||
@end
|
|
||||||
@ -1,134 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by Gabriel Handford on 3/1/09.
|
|
||||||
// Copyright 2009-2013. All rights reserved.
|
|
||||||
// Created by John Boiles on 10/20/11.
|
|
||||||
// Copyright (c) 2011. All rights reserved
|
|
||||||
// Modified by Felix Schulze on 2/11/13.
|
|
||||||
// Copyright 2013. All rights reserved.
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person
|
|
||||||
// obtaining a copy of this software and associated documentation
|
|
||||||
// files (the "Software"), to deal in the Software without
|
|
||||||
// restriction, including without limitation the rights to use,
|
|
||||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the
|
|
||||||
// Software is furnished to do so, subject to the following
|
|
||||||
// conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be
|
|
||||||
// included in all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
||||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
||||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
||||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
||||||
// OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import <FBSnapshotTestCase/UIImage+Compare.h>
|
|
||||||
|
|
||||||
// This makes debugging much more fun
|
|
||||||
typedef union {
|
|
||||||
uint32_t raw;
|
|
||||||
unsigned char bytes[4];
|
|
||||||
struct {
|
|
||||||
char red;
|
|
||||||
char green;
|
|
||||||
char blue;
|
|
||||||
char alpha;
|
|
||||||
} __attribute__ ((packed)) pixels;
|
|
||||||
} FBComparePixel;
|
|
||||||
|
|
||||||
@implementation UIImage (Compare)
|
|
||||||
|
|
||||||
- (BOOL)fb_compareWithImage:(UIImage *)image tolerance:(CGFloat)tolerance
|
|
||||||
{
|
|
||||||
NSAssert(CGSizeEqualToSize(self.size, image.size), @"Images must be same size.");
|
|
||||||
|
|
||||||
CGSize referenceImageSize = CGSizeMake(CGImageGetWidth(self.CGImage), CGImageGetHeight(self.CGImage));
|
|
||||||
CGSize imageSize = CGSizeMake(CGImageGetWidth(image.CGImage), CGImageGetHeight(image.CGImage));
|
|
||||||
|
|
||||||
// The images have the equal size, so we could use the smallest amount of bytes because of byte padding
|
|
||||||
size_t minBytesPerRow = MIN(CGImageGetBytesPerRow(self.CGImage), CGImageGetBytesPerRow(image.CGImage));
|
|
||||||
size_t referenceImageSizeBytes = referenceImageSize.height * minBytesPerRow;
|
|
||||||
void *referenceImagePixels = calloc(1, referenceImageSizeBytes);
|
|
||||||
void *imagePixels = calloc(1, referenceImageSizeBytes);
|
|
||||||
|
|
||||||
if (!referenceImagePixels || !imagePixels) {
|
|
||||||
free(referenceImagePixels);
|
|
||||||
free(imagePixels);
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
CGContextRef referenceImageContext = CGBitmapContextCreate(referenceImagePixels,
|
|
||||||
referenceImageSize.width,
|
|
||||||
referenceImageSize.height,
|
|
||||||
CGImageGetBitsPerComponent(self.CGImage),
|
|
||||||
minBytesPerRow,
|
|
||||||
CGImageGetColorSpace(self.CGImage),
|
|
||||||
(CGBitmapInfo)kCGImageAlphaPremultipliedLast
|
|
||||||
);
|
|
||||||
CGContextRef imageContext = CGBitmapContextCreate(imagePixels,
|
|
||||||
imageSize.width,
|
|
||||||
imageSize.height,
|
|
||||||
CGImageGetBitsPerComponent(image.CGImage),
|
|
||||||
minBytesPerRow,
|
|
||||||
CGImageGetColorSpace(image.CGImage),
|
|
||||||
(CGBitmapInfo)kCGImageAlphaPremultipliedLast
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!referenceImageContext || !imageContext) {
|
|
||||||
CGContextRelease(referenceImageContext);
|
|
||||||
CGContextRelease(imageContext);
|
|
||||||
free(referenceImagePixels);
|
|
||||||
free(imagePixels);
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
CGContextDrawImage(referenceImageContext, CGRectMake(0, 0, referenceImageSize.width, referenceImageSize.height), self.CGImage);
|
|
||||||
CGContextDrawImage(imageContext, CGRectMake(0, 0, imageSize.width, imageSize.height), image.CGImage);
|
|
||||||
|
|
||||||
CGContextRelease(referenceImageContext);
|
|
||||||
CGContextRelease(imageContext);
|
|
||||||
|
|
||||||
BOOL imageEqual = YES;
|
|
||||||
|
|
||||||
// Do a fast compare if we can
|
|
||||||
if (tolerance == 0) {
|
|
||||||
imageEqual = (memcmp(referenceImagePixels, imagePixels, referenceImageSizeBytes) == 0);
|
|
||||||
} else {
|
|
||||||
// Go through each pixel in turn and see if it is different
|
|
||||||
const NSInteger pixelCount = referenceImageSize.width * referenceImageSize.height;
|
|
||||||
|
|
||||||
FBComparePixel *p1 = referenceImagePixels;
|
|
||||||
FBComparePixel *p2 = imagePixels;
|
|
||||||
|
|
||||||
NSInteger numDiffPixels = 0;
|
|
||||||
for (int n = 0; n < pixelCount; ++n) {
|
|
||||||
// If this pixel is different, increment the pixel diff count and see
|
|
||||||
// if we have hit our limit.
|
|
||||||
if (p1->raw != p2->raw) {
|
|
||||||
numDiffPixels ++;
|
|
||||||
|
|
||||||
CGFloat percent = (CGFloat)numDiffPixels / pixelCount;
|
|
||||||
if (percent > tolerance) {
|
|
||||||
imageEqual = NO;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
p1++;
|
|
||||||
p2++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(referenceImagePixels);
|
|
||||||
free(imagePixels);
|
|
||||||
|
|
||||||
return imageEqual;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
@ -1,37 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by Gabriel Handford on 3/1/09.
|
|
||||||
// Copyright 2009-2013. All rights reserved.
|
|
||||||
// Created by John Boiles on 10/20/11.
|
|
||||||
// Copyright (c) 2011. All rights reserved
|
|
||||||
// Modified by Felix Schulze on 2/11/13.
|
|
||||||
// Copyright 2013. All rights reserved.
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person
|
|
||||||
// obtaining a copy of this software and associated documentation
|
|
||||||
// files (the "Software"), to deal in the Software without
|
|
||||||
// restriction, including without limitation the rights to use,
|
|
||||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the
|
|
||||||
// Software is furnished to do so, subject to the following
|
|
||||||
// conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be
|
|
||||||
// included in all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
||||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
||||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
||||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
||||||
// OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
|
||||||
|
|
||||||
@interface UIImage (Diff)
|
|
||||||
|
|
||||||
- (UIImage *)fb_diffWithImage:(UIImage *)image;
|
|
||||||
|
|
||||||
@end
|
|
||||||
@ -1,56 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by Gabriel Handford on 3/1/09.
|
|
||||||
// Copyright 2009-2013. All rights reserved.
|
|
||||||
// Created by John Boiles on 10/20/11.
|
|
||||||
// Copyright (c) 2011. All rights reserved
|
|
||||||
// Modified by Felix Schulze on 2/11/13.
|
|
||||||
// Copyright 2013. All rights reserved.
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person
|
|
||||||
// obtaining a copy of this software and associated documentation
|
|
||||||
// files (the "Software"), to deal in the Software without
|
|
||||||
// restriction, including without limitation the rights to use,
|
|
||||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the
|
|
||||||
// Software is furnished to do so, subject to the following
|
|
||||||
// conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be
|
|
||||||
// included in all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
||||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
||||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
||||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
||||||
// OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import <FBSnapshotTestCase/UIImage+Diff.h>
|
|
||||||
|
|
||||||
@implementation UIImage (Diff)
|
|
||||||
|
|
||||||
- (UIImage *)fb_diffWithImage:(UIImage *)image
|
|
||||||
{
|
|
||||||
if (!image) {
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
CGSize imageSize = CGSizeMake(MAX(self.size.width, image.size.width), MAX(self.size.height, image.size.height));
|
|
||||||
UIGraphicsBeginImageContextWithOptions(imageSize, YES, 0);
|
|
||||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
|
||||||
[self drawInRect:CGRectMake(0, 0, self.size.width, self.size.height)];
|
|
||||||
CGContextSetAlpha(context, 0.5);
|
|
||||||
CGContextBeginTransparencyLayer(context, NULL);
|
|
||||||
[image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
|
|
||||||
CGContextSetBlendMode(context, kCGBlendModeDifference);
|
|
||||||
CGContextSetFillColorWithColor(context,[UIColor whiteColor].CGColor);
|
|
||||||
CGContextFillRect(context, CGRectMake(0, 0, self.size.width, self.size.height));
|
|
||||||
CGContextEndTransparencyLayer(context);
|
|
||||||
UIImage *returnImage = UIGraphicsGetImageFromCurrentImageContext();
|
|
||||||
UIGraphicsEndImageContext();
|
|
||||||
return returnImage;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2015, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
|
||||||
|
|
||||||
@interface UIImage (Snapshot)
|
|
||||||
|
|
||||||
/// Uses renderInContext: to get a snapshot of the layer.
|
|
||||||
+ (UIImage *)fb_imageForLayer:(CALayer *)layer;
|
|
||||||
|
|
||||||
/// Uses renderInContext: to get a snapshot of the view layer.
|
|
||||||
+ (UIImage *)fb_imageForViewLayer:(UIView *)view;
|
|
||||||
|
|
||||||
/// Uses drawViewHierarchyInRect: to get a snapshot of the view and adds the view into a window if needed.
|
|
||||||
+ (UIImage *)fb_imageForView:(UIView *)view;
|
|
||||||
|
|
||||||
@end
|
|
||||||
@ -1,73 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2015, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <FBSnapshotTestCase/UIImage+Snapshot.h>
|
|
||||||
#import <FBSnapshotTestCase/UIApplication+StrictKeyWindow.h>
|
|
||||||
|
|
||||||
@implementation UIImage (Snapshot)
|
|
||||||
|
|
||||||
+ (UIImage *)fb_imageForLayer:(CALayer *)layer
|
|
||||||
{
|
|
||||||
CGRect bounds = layer.bounds;
|
|
||||||
NSAssert1(CGRectGetWidth(bounds), @"Zero width for layer %@", layer);
|
|
||||||
NSAssert1(CGRectGetHeight(bounds), @"Zero height for layer %@", layer);
|
|
||||||
|
|
||||||
UIGraphicsBeginImageContextWithOptions(bounds.size, NO, 0);
|
|
||||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
|
||||||
NSAssert1(context, @"Could not generate context for layer %@", layer);
|
|
||||||
CGContextSaveGState(context);
|
|
||||||
[layer layoutIfNeeded];
|
|
||||||
[layer renderInContext:context];
|
|
||||||
CGContextRestoreGState(context);
|
|
||||||
|
|
||||||
UIImage *snapshot = UIGraphicsGetImageFromCurrentImageContext();
|
|
||||||
UIGraphicsEndImageContext();
|
|
||||||
return snapshot;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (UIImage *)fb_imageForViewLayer:(UIView *)view
|
|
||||||
{
|
|
||||||
[view layoutIfNeeded];
|
|
||||||
return [self fb_imageForLayer:view.layer];
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (UIImage *)fb_imageForView:(UIView *)view
|
|
||||||
{
|
|
||||||
CGRect bounds = view.bounds;
|
|
||||||
NSAssert1(CGRectGetWidth(bounds), @"Zero width for view %@", view);
|
|
||||||
NSAssert1(CGRectGetHeight(bounds), @"Zero height for view %@", view);
|
|
||||||
|
|
||||||
// If the input view is already a UIWindow, then just use that. Otherwise wrap in a window.
|
|
||||||
UIWindow *window = [view isKindOfClass:[UIWindow class]] ? (UIWindow *)view : view.window;
|
|
||||||
BOOL removeFromSuperview = NO;
|
|
||||||
if (!window) {
|
|
||||||
window = [[UIApplication sharedApplication] fb_strictKeyWindow];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!view.window && view != window) {
|
|
||||||
[window addSubview:view];
|
|
||||||
removeFromSuperview = YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
UIGraphicsBeginImageContextWithOptions(bounds.size, NO, 0);
|
|
||||||
[view layoutIfNeeded];
|
|
||||||
[view drawViewHierarchyInRect:view.bounds afterScreenUpdates:YES];
|
|
||||||
|
|
||||||
UIImage *snapshot = UIGraphicsGetImageFromCurrentImageContext();
|
|
||||||
UIGraphicsEndImageContext();
|
|
||||||
|
|
||||||
if (removeFromSuperview) {
|
|
||||||
[view removeFromSuperview];
|
|
||||||
}
|
|
||||||
|
|
||||||
return snapshot;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
@ -1,180 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2015, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <FBSnapshotTestCase/FBSnapshotTestCasePlatform.h>
|
|
||||||
#import <FBSnapshotTestCase/FBSnapshotTestController.h>
|
|
||||||
|
|
||||||
#import <QuartzCore/QuartzCore.h>
|
|
||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
|
||||||
|
|
||||||
#import <XCTest/XCTest.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
There are three ways of setting reference image directories.
|
|
||||||
|
|
||||||
1. Set the preprocessor macro FB_REFERENCE_IMAGE_DIR to a double quoted
|
|
||||||
c-string with the path.
|
|
||||||
2. Set an environment variable named FB_REFERENCE_IMAGE_DIR with the path. This
|
|
||||||
takes precedence over the preprocessor macro to allow for run-time override.
|
|
||||||
3. Keep everything unset, which will cause the reference images to be looked up
|
|
||||||
inside the bundle holding the current test, in the
|
|
||||||
Resources/ReferenceImages_* directories.
|
|
||||||
*/
|
|
||||||
#ifndef FB_REFERENCE_IMAGE_DIR
|
|
||||||
#define FB_REFERENCE_IMAGE_DIR ""
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
Similar to our much-loved XCTAssert() macros. Use this to perform your test. No need to write an explanation, though.
|
|
||||||
@param view The view to snapshot
|
|
||||||
@param identifier An optional identifier, used if there are multiple snapshot tests in a given -test method.
|
|
||||||
@param suffixes An NSOrderedSet of strings for the different suffixes
|
|
||||||
@param tolerance The percentage of pixels that can differ and still count as an 'identical' view
|
|
||||||
*/
|
|
||||||
#define FBSnapshotVerifyViewWithOptions(view__, identifier__, suffixes__, tolerance__) \
|
|
||||||
FBSnapshotVerifyViewOrLayerWithOptions(View, view__, identifier__, suffixes__, tolerance__)
|
|
||||||
|
|
||||||
#define FBSnapshotVerifyView(view__, identifier__) \
|
|
||||||
FBSnapshotVerifyViewWithOptions(view__, identifier__, FBSnapshotTestCaseDefaultSuffixes(), 0)
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Similar to our much-loved XCTAssert() macros. Use this to perform your test. No need to write an explanation, though.
|
|
||||||
@param layer The layer to snapshot
|
|
||||||
@param identifier An optional identifier, used if there are multiple snapshot tests in a given -test method.
|
|
||||||
@param suffixes An NSOrderedSet of strings for the different suffixes
|
|
||||||
@param tolerance The percentage of pixels that can differ and still count as an 'identical' layer
|
|
||||||
*/
|
|
||||||
#define FBSnapshotVerifyLayerWithOptions(layer__, identifier__, suffixes__, tolerance__) \
|
|
||||||
FBSnapshotVerifyViewOrLayerWithOptions(Layer, layer__, identifier__, suffixes__, tolerance__)
|
|
||||||
|
|
||||||
#define FBSnapshotVerifyLayer(layer__, identifier__) \
|
|
||||||
FBSnapshotVerifyLayerWithOptions(layer__, identifier__, FBSnapshotTestCaseDefaultSuffixes(), 0)
|
|
||||||
|
|
||||||
|
|
||||||
#define FBSnapshotVerifyViewOrLayerWithOptions(what__, viewOrLayer__, identifier__, suffixes__, tolerance__) \
|
|
||||||
{ \
|
|
||||||
NSString *errorDescription = [self snapshotVerifyViewOrLayer:viewOrLayer__ identifier:identifier__ suffixes:suffixes__ tolerance:tolerance__]; \
|
|
||||||
BOOL noErrors = (errorDescription == nil); \
|
|
||||||
XCTAssertTrue(noErrors, @"%@", errorDescription); \
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
The base class of view snapshotting tests. If you have small UI component, it's often easier to configure it in a test
|
|
||||||
and compare an image of the view to a reference image that write lots of complex layout-code tests.
|
|
||||||
|
|
||||||
In order to flip the tests in your subclass to record the reference images set @c recordMode to @c YES.
|
|
||||||
|
|
||||||
@attention When recording, the reference image directory should be explicitly
|
|
||||||
set, otherwise the images may be written to somewhere inside the
|
|
||||||
simulator directory.
|
|
||||||
|
|
||||||
For example:
|
|
||||||
@code
|
|
||||||
- (void)setUp
|
|
||||||
{
|
|
||||||
[super setUp];
|
|
||||||
self.recordMode = YES;
|
|
||||||
}
|
|
||||||
@endcode
|
|
||||||
*/
|
|
||||||
@interface FBSnapshotTestCase : XCTestCase
|
|
||||||
|
|
||||||
/**
|
|
||||||
When YES, the test macros will save reference images, rather than performing an actual test.
|
|
||||||
*/
|
|
||||||
@property (readwrite, nonatomic, assign) BOOL recordMode;
|
|
||||||
|
|
||||||
/**
|
|
||||||
When @c YES appends the name of the device model and OS to the snapshot file name.
|
|
||||||
The default value is @c NO.
|
|
||||||
*/
|
|
||||||
@property (readwrite, nonatomic, assign, getter=isDeviceAgnostic) BOOL deviceAgnostic;
|
|
||||||
|
|
||||||
/**
|
|
||||||
When YES, renders a snapshot of the complete view hierarchy as visible onscreen.
|
|
||||||
There are several things that do not work if renderInContext: is used.
|
|
||||||
- UIVisualEffect #70
|
|
||||||
- UIAppearance #91
|
|
||||||
- Size Classes #92
|
|
||||||
|
|
||||||
@attention If the view does't belong to a UIWindow, it will create one and add the view as a subview.
|
|
||||||
*/
|
|
||||||
@property (readwrite, nonatomic, assign) BOOL usesDrawViewHierarchyInRect;
|
|
||||||
|
|
||||||
- (void)setUp NS_REQUIRES_SUPER;
|
|
||||||
- (void)tearDown NS_REQUIRES_SUPER;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Performs the comparison or records a snapshot of the layer if recordMode is YES.
|
|
||||||
@param viewOrLayer The UIView or CALayer to snapshot
|
|
||||||
@param identifier An optional identifier, used if there are multiple snapshot tests in a given -test method.
|
|
||||||
@param suffixes An NSOrderedSet of strings for the different suffixes
|
|
||||||
@param tolerance The percentage difference to still count as identical - 0 mean pixel perfect, 1 means I don't care
|
|
||||||
@returns nil if the comparison (or saving of the reference image) succeeded. Otherwise it contains an error description.
|
|
||||||
*/
|
|
||||||
- (NSString *)snapshotVerifyViewOrLayer:(id)viewOrLayer
|
|
||||||
identifier:(NSString *)identifier
|
|
||||||
suffixes:(NSOrderedSet *)suffixes
|
|
||||||
tolerance:(CGFloat)tolerance;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Performs the comparison or records a snapshot of the layer if recordMode is YES.
|
|
||||||
@param layer The Layer to snapshot
|
|
||||||
@param referenceImagesDirectory The directory in which reference images are stored.
|
|
||||||
@param identifier An optional identifier, used if there are multiple snapshot tests in a given -test method.
|
|
||||||
@param tolerance The percentage difference to still count as identical - 0 mean pixel perfect, 1 means I don't care
|
|
||||||
@param errorPtr An error to log in an XCTAssert() macro if the method fails (missing reference image, images differ, etc).
|
|
||||||
@returns YES if the comparison (or saving of the reference image) succeeded.
|
|
||||||
*/
|
|
||||||
- (BOOL)compareSnapshotOfLayer:(CALayer *)layer
|
|
||||||
referenceImagesDirectory:(NSString *)referenceImagesDirectory
|
|
||||||
identifier:(NSString *)identifier
|
|
||||||
tolerance:(CGFloat)tolerance
|
|
||||||
error:(NSError **)errorPtr;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Performs the comparison or records a snapshot of the view if recordMode is YES.
|
|
||||||
@param view The view to snapshot
|
|
||||||
@param referenceImagesDirectory The directory in which reference images are stored.
|
|
||||||
@param identifier An optional identifier, used if there are multiple snapshot tests in a given -test method.
|
|
||||||
@param tolerance The percentage difference to still count as identical - 0 mean pixel perfect, 1 means I don't care
|
|
||||||
@param errorPtr An error to log in an XCTAssert() macro if the method fails (missing reference image, images differ, etc).
|
|
||||||
@returns YES if the comparison (or saving of the reference image) succeeded.
|
|
||||||
*/
|
|
||||||
- (BOOL)compareSnapshotOfView:(UIView *)view
|
|
||||||
referenceImagesDirectory:(NSString *)referenceImagesDirectory
|
|
||||||
identifier:(NSString *)identifier
|
|
||||||
tolerance:(CGFloat)tolerance
|
|
||||||
error:(NSError **)errorPtr;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Checks if reference image with identifier based name exists in the reference images directory.
|
|
||||||
@param referenceImagesDirectory The directory in which reference images are stored.
|
|
||||||
@param identifier An optional identifier, used if there are multiple snapshot tests in a given -test method.
|
|
||||||
@param errorPtr An error to log in an XCTAssert() macro if the method fails (missing reference image, images differ, etc).
|
|
||||||
@returns YES if reference image exists.
|
|
||||||
*/
|
|
||||||
- (BOOL)referenceImageRecordedInDirectory:(NSString *)referenceImagesDirectory
|
|
||||||
identifier:(NSString *)identifier
|
|
||||||
error:(NSError **)errorPtr;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the reference image directory.
|
|
||||||
|
|
||||||
Helper function used to implement the assert macros.
|
|
||||||
|
|
||||||
@param dir directory to use if environment variable not specified. Ignored if null or empty.
|
|
||||||
*/
|
|
||||||
- (NSString *)getReferenceImageDirectoryWithDefault:(NSString *)dir;
|
|
||||||
|
|
||||||
@end
|
|
||||||
@ -1,192 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2015, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <FBSnapshotTestCase/FBSnapshotTestCase.h>
|
|
||||||
#import <FBSnapshotTestCase/FBSnapshotTestController.h>
|
|
||||||
|
|
||||||
@implementation FBSnapshotTestCase
|
|
||||||
{
|
|
||||||
FBSnapshotTestController *_snapshotController;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - Overrides
|
|
||||||
|
|
||||||
- (void)setUp
|
|
||||||
{
|
|
||||||
[super setUp];
|
|
||||||
_snapshotController = [[FBSnapshotTestController alloc] initWithTestName:NSStringFromClass([self class])];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)tearDown
|
|
||||||
{
|
|
||||||
_snapshotController = nil;
|
|
||||||
[super tearDown];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)recordMode
|
|
||||||
{
|
|
||||||
return _snapshotController.recordMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setRecordMode:(BOOL)recordMode
|
|
||||||
{
|
|
||||||
NSAssert1(_snapshotController, @"%s cannot be called before [super setUp]", __FUNCTION__);
|
|
||||||
_snapshotController.recordMode = recordMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)isDeviceAgnostic
|
|
||||||
{
|
|
||||||
return _snapshotController.deviceAgnostic;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setDeviceAgnostic:(BOOL)deviceAgnostic
|
|
||||||
{
|
|
||||||
NSAssert1(_snapshotController, @"%s cannot be called before [super setUp]", __FUNCTION__);
|
|
||||||
_snapshotController.deviceAgnostic = deviceAgnostic;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)usesDrawViewHierarchyInRect
|
|
||||||
{
|
|
||||||
return _snapshotController.usesDrawViewHierarchyInRect;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setUsesDrawViewHierarchyInRect:(BOOL)usesDrawViewHierarchyInRect
|
|
||||||
{
|
|
||||||
NSAssert1(_snapshotController, @"%s cannot be called before [super setUp]", __FUNCTION__);
|
|
||||||
_snapshotController.usesDrawViewHierarchyInRect = usesDrawViewHierarchyInRect;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - Public API
|
|
||||||
|
|
||||||
- (NSString *)snapshotVerifyViewOrLayer:(id)viewOrLayer
|
|
||||||
identifier:(NSString *)identifier
|
|
||||||
suffixes:(NSOrderedSet *)suffixes
|
|
||||||
tolerance:(CGFloat)tolerance
|
|
||||||
{
|
|
||||||
if (nil == viewOrLayer) {
|
|
||||||
return @"Object to be snapshotted must not be nil";
|
|
||||||
}
|
|
||||||
NSString *referenceImageDirectory = [self getReferenceImageDirectoryWithDefault:(@ FB_REFERENCE_IMAGE_DIR)];
|
|
||||||
if (referenceImageDirectory == nil) {
|
|
||||||
return @"Missing value for referenceImagesDirectory - Set FB_REFERENCE_IMAGE_DIR as Environment variable in your scheme.";
|
|
||||||
}
|
|
||||||
if (suffixes.count == 0) {
|
|
||||||
return [NSString stringWithFormat:@"Suffixes set cannot be empty %@", suffixes];
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL testSuccess = NO;
|
|
||||||
NSError *error = nil;
|
|
||||||
NSMutableArray *errors = [NSMutableArray array];
|
|
||||||
|
|
||||||
if (self.recordMode) {
|
|
||||||
NSString *referenceImagesDirectory = [NSString stringWithFormat:@"%@%@", referenceImageDirectory, suffixes.firstObject];
|
|
||||||
BOOL referenceImageSaved = [self _compareSnapshotOfViewOrLayer:viewOrLayer referenceImagesDirectory:referenceImagesDirectory identifier:(identifier) tolerance:tolerance error:&error];
|
|
||||||
if (!referenceImageSaved) {
|
|
||||||
[errors addObject:error];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (NSString *suffix in suffixes) {
|
|
||||||
NSString *referenceImagesDirectory = [NSString stringWithFormat:@"%@%@", referenceImageDirectory, suffix];
|
|
||||||
BOOL referenceImageAvailable = [self referenceImageRecordedInDirectory:referenceImagesDirectory identifier:(identifier) error:&error];
|
|
||||||
|
|
||||||
if (referenceImageAvailable) {
|
|
||||||
BOOL comparisonSuccess = [self _compareSnapshotOfViewOrLayer:viewOrLayer referenceImagesDirectory:referenceImagesDirectory identifier:identifier tolerance:tolerance error:&error];
|
|
||||||
[errors removeAllObjects];
|
|
||||||
if (comparisonSuccess) {
|
|
||||||
testSuccess = YES;
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
[errors addObject:error];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
[errors addObject:error];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!testSuccess) {
|
|
||||||
return [NSString stringWithFormat:@"Snapshot comparison failed: %@", errors.firstObject];
|
|
||||||
}
|
|
||||||
if (self.recordMode) {
|
|
||||||
return @"Test ran in record mode. Reference image is now saved. Disable record mode to perform an actual snapshot comparison!";
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)compareSnapshotOfLayer:(CALayer *)layer
|
|
||||||
referenceImagesDirectory:(NSString *)referenceImagesDirectory
|
|
||||||
identifier:(NSString *)identifier
|
|
||||||
tolerance:(CGFloat)tolerance
|
|
||||||
error:(NSError **)errorPtr
|
|
||||||
{
|
|
||||||
return [self _compareSnapshotOfViewOrLayer:layer
|
|
||||||
referenceImagesDirectory:referenceImagesDirectory
|
|
||||||
identifier:identifier
|
|
||||||
tolerance:tolerance
|
|
||||||
error:errorPtr];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)compareSnapshotOfView:(UIView *)view
|
|
||||||
referenceImagesDirectory:(NSString *)referenceImagesDirectory
|
|
||||||
identifier:(NSString *)identifier
|
|
||||||
tolerance:(CGFloat)tolerance
|
|
||||||
error:(NSError **)errorPtr
|
|
||||||
{
|
|
||||||
return [self _compareSnapshotOfViewOrLayer:view
|
|
||||||
referenceImagesDirectory:referenceImagesDirectory
|
|
||||||
identifier:identifier
|
|
||||||
tolerance:tolerance
|
|
||||||
error:errorPtr];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)referenceImageRecordedInDirectory:(NSString *)referenceImagesDirectory
|
|
||||||
identifier:(NSString *)identifier
|
|
||||||
error:(NSError **)errorPtr
|
|
||||||
{
|
|
||||||
NSAssert1(_snapshotController, @"%s cannot be called before [super setUp]", __FUNCTION__);
|
|
||||||
_snapshotController.referenceImagesDirectory = referenceImagesDirectory;
|
|
||||||
UIImage *referenceImage = [_snapshotController referenceImageForSelector:self.invocation.selector
|
|
||||||
identifier:identifier
|
|
||||||
error:errorPtr];
|
|
||||||
|
|
||||||
return (referenceImage != nil);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSString *)getReferenceImageDirectoryWithDefault:(NSString *)dir
|
|
||||||
{
|
|
||||||
NSString *envReferenceImageDirectory = [NSProcessInfo processInfo].environment[@"FB_REFERENCE_IMAGE_DIR"];
|
|
||||||
if (envReferenceImageDirectory) {
|
|
||||||
return envReferenceImageDirectory;
|
|
||||||
}
|
|
||||||
if (dir && dir.length > 0) {
|
|
||||||
return dir;
|
|
||||||
}
|
|
||||||
return [[NSBundle bundleForClass:self.class].resourcePath stringByAppendingPathComponent:@"ReferenceImages"];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#pragma mark - Private API
|
|
||||||
|
|
||||||
- (BOOL)_compareSnapshotOfViewOrLayer:(id)viewOrLayer
|
|
||||||
referenceImagesDirectory:(NSString *)referenceImagesDirectory
|
|
||||||
identifier:(NSString *)identifier
|
|
||||||
tolerance:(CGFloat)tolerance
|
|
||||||
error:(NSError **)errorPtr
|
|
||||||
{
|
|
||||||
_snapshotController.referenceImagesDirectory = referenceImagesDirectory;
|
|
||||||
return [_snapshotController compareSnapshotOfViewOrLayer:viewOrLayer
|
|
||||||
selector:self.invocation.selector
|
|
||||||
identifier:identifier
|
|
||||||
tolerance:tolerance
|
|
||||||
error:errorPtr];
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
@ -1,44 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2015, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns a Boolean value that indicates whether the snapshot test is running in 64Bit.
|
|
||||||
This method is a convenience for creating the suffixes set based on the architecture
|
|
||||||
that the test is running.
|
|
||||||
|
|
||||||
@returns @c YES if the test is running in 64bit, otherwise @c NO.
|
|
||||||
*/
|
|
||||||
BOOL FBSnapshotTestCaseIs64Bit(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns a default set of strings that is used to append a suffix based on the architectures.
|
|
||||||
@warning Do not modify this function, you can create your own and use it with @c FBSnapshotVerifyViewWithOptions()
|
|
||||||
|
|
||||||
@returns An @c NSOrderedSet object containing strings that are appended to the reference images directory.
|
|
||||||
*/
|
|
||||||
NSOrderedSet *FBSnapshotTestCaseDefaultSuffixes(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns a fully «normalized» file name.
|
|
||||||
Strips punctuation and spaces and replaces them with @c _. Also appends the device model, running OS and screen size to the file name.
|
|
||||||
|
|
||||||
@returns An @c NSString object containing the passed @c fileName with the device model, OS and screen size appended at the end.
|
|
||||||
*/
|
|
||||||
NSString *FBDeviceAgnosticNormalizedFileName(NSString *fileName);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@ -1,51 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2015, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <FBSnapshotTestCase/FBSnapshotTestCasePlatform.h>
|
|
||||||
#import <FBSnapshotTestCase/UIApplication+StrictKeyWindow.h>
|
|
||||||
#import <UIKit/UIKit.h>
|
|
||||||
|
|
||||||
BOOL FBSnapshotTestCaseIs64Bit(void)
|
|
||||||
{
|
|
||||||
#if __LP64__
|
|
||||||
return YES;
|
|
||||||
#else
|
|
||||||
return NO;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
NSOrderedSet *FBSnapshotTestCaseDefaultSuffixes(void)
|
|
||||||
{
|
|
||||||
NSMutableOrderedSet *suffixesSet = [[NSMutableOrderedSet alloc] init];
|
|
||||||
[suffixesSet addObject:@"_32"];
|
|
||||||
[suffixesSet addObject:@"_64"];
|
|
||||||
if (FBSnapshotTestCaseIs64Bit()) {
|
|
||||||
return [suffixesSet reversedOrderedSet];
|
|
||||||
}
|
|
||||||
return [suffixesSet copy];
|
|
||||||
}
|
|
||||||
|
|
||||||
NSString *FBDeviceAgnosticNormalizedFileName(NSString *fileName)
|
|
||||||
{
|
|
||||||
UIDevice *device = [UIDevice currentDevice];
|
|
||||||
UIWindow *keyWindow = [[UIApplication sharedApplication] fb_strictKeyWindow];
|
|
||||||
CGSize screenSize = keyWindow.bounds.size;
|
|
||||||
NSString *os = device.systemVersion;
|
|
||||||
|
|
||||||
fileName = [NSString stringWithFormat:@"%@_%@%@_%.0fx%.0f", fileName, device.model, os, screenSize.width, screenSize.height];
|
|
||||||
|
|
||||||
NSMutableCharacterSet *invalidCharacters = [NSMutableCharacterSet new];
|
|
||||||
[invalidCharacters formUnionWithCharacterSet:[NSCharacterSet whitespaceCharacterSet]];
|
|
||||||
[invalidCharacters formUnionWithCharacterSet:[NSCharacterSet punctuationCharacterSet]];
|
|
||||||
NSArray *validComponents = [fileName componentsSeparatedByCharactersInSet:invalidCharacters];
|
|
||||||
fileName = [validComponents componentsJoinedByString:@"_"];
|
|
||||||
|
|
||||||
return fileName;
|
|
||||||
}
|
|
||||||
@ -1,166 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2015, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
#import <UIKit/UIKit.h>
|
|
||||||
|
|
||||||
typedef NS_ENUM(NSInteger, FBSnapshotTestControllerErrorCode) {
|
|
||||||
FBSnapshotTestControllerErrorCodeUnknown,
|
|
||||||
FBSnapshotTestControllerErrorCodeNeedsRecord,
|
|
||||||
FBSnapshotTestControllerErrorCodePNGCreationFailed,
|
|
||||||
FBSnapshotTestControllerErrorCodeImagesDifferentSizes,
|
|
||||||
FBSnapshotTestControllerErrorCodeImagesDifferent,
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
Errors returned by the methods of FBSnapshotTestController use this domain.
|
|
||||||
*/
|
|
||||||
extern NSString *const FBSnapshotTestControllerErrorDomain;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Errors returned by the methods of FBSnapshotTestController sometimes contain this key in the `userInfo` dictionary.
|
|
||||||
*/
|
|
||||||
extern NSString *const FBReferenceImageFilePathKey;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Errors returned by the methods of FBSnapshotTestController sometimes contain this key in the `userInfo` dictionary.
|
|
||||||
*/
|
|
||||||
extern NSString *const FBReferenceImageKey;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Errors returned by the methods of FBSnapshotTestController sometimes contain this key in the `userInfo` dictionary.
|
|
||||||
*/
|
|
||||||
extern NSString *const FBCapturedImageKey;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Errors returned by the methods of FBSnapshotTestController sometimes contain this key in the `userInfo` dictionary.
|
|
||||||
*/
|
|
||||||
extern NSString *const FBDiffedImageKey;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Provides the heavy-lifting for FBSnapshotTestCase. It loads and saves images, along with performing the actual pixel-
|
|
||||||
by-pixel comparison of images.
|
|
||||||
Instances are initialized with the test class, and directories to read and write to.
|
|
||||||
*/
|
|
||||||
@interface FBSnapshotTestController : NSObject
|
|
||||||
|
|
||||||
/**
|
|
||||||
Record snapshots.
|
|
||||||
*/
|
|
||||||
@property (readwrite, nonatomic, assign) BOOL recordMode;
|
|
||||||
|
|
||||||
/**
|
|
||||||
When @c YES appends the name of the device model and OS to the snapshot file name.
|
|
||||||
The default value is @c NO.
|
|
||||||
*/
|
|
||||||
@property (readwrite, nonatomic, assign, getter=isDeviceAgnostic) BOOL deviceAgnostic;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Uses drawViewHierarchyInRect:afterScreenUpdates: to draw the image instead of renderInContext:
|
|
||||||
*/
|
|
||||||
@property (readwrite, nonatomic, assign) BOOL usesDrawViewHierarchyInRect;
|
|
||||||
|
|
||||||
/**
|
|
||||||
The directory in which referfence images are stored.
|
|
||||||
*/
|
|
||||||
@property (readwrite, nonatomic, copy) NSString *referenceImagesDirectory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
@param testClass The subclass of FBSnapshotTestCase that is using this controller.
|
|
||||||
@returns An instance of FBSnapshotTestController.
|
|
||||||
*/
|
|
||||||
- (instancetype)initWithTestClass:(Class)testClass;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Designated initializer.
|
|
||||||
@param testName The name of the tests.
|
|
||||||
@returns An instance of FBSnapshotTestController.
|
|
||||||
*/
|
|
||||||
- (instancetype)initWithTestName:(NSString *)testName;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Performs the comparison of the layer.
|
|
||||||
@param layer The Layer to snapshot.
|
|
||||||
@param selector The test method being run.
|
|
||||||
@param identifier An optional identifier, used is there are muliptle snapshot tests in a given -test method.
|
|
||||||
@param error An error to log in an XCTAssert() macro if the method fails (missing reference image, images differ, etc).
|
|
||||||
@returns YES if the comparison (or saving of the reference image) succeeded.
|
|
||||||
*/
|
|
||||||
- (BOOL)compareSnapshotOfLayer:(CALayer *)layer
|
|
||||||
selector:(SEL)selector
|
|
||||||
identifier:(NSString *)identifier
|
|
||||||
error:(NSError **)errorPtr;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Performs the comparison of the view.
|
|
||||||
@param view The view to snapshot.
|
|
||||||
@param selector The test method being run.
|
|
||||||
@param identifier An optional identifier, used is there are muliptle snapshot tests in a given -test method.
|
|
||||||
@param error An error to log in an XCTAssert() macro if the method fails (missing reference image, images differ, etc).
|
|
||||||
@returns YES if the comparison (or saving of the reference image) succeeded.
|
|
||||||
*/
|
|
||||||
- (BOOL)compareSnapshotOfView:(UIView *)view
|
|
||||||
selector:(SEL)selector
|
|
||||||
identifier:(NSString *)identifier
|
|
||||||
error:(NSError **)errorPtr;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Performs the comparison of a view or layer.
|
|
||||||
@param view The view or layer to snapshot.
|
|
||||||
@param selector The test method being run.
|
|
||||||
@param identifier An optional identifier, used is there are muliptle snapshot tests in a given -test method.
|
|
||||||
@param tolerance The percentage of pixels that can differ and still be considered 'identical'
|
|
||||||
@param error An error to log in an XCTAssert() macro if the method fails (missing reference image, images differ, etc).
|
|
||||||
@returns YES if the comparison (or saving of the reference image) succeeded.
|
|
||||||
*/
|
|
||||||
- (BOOL)compareSnapshotOfViewOrLayer:(id)viewOrLayer
|
|
||||||
selector:(SEL)selector
|
|
||||||
identifier:(NSString *)identifier
|
|
||||||
tolerance:(CGFloat)tolerance
|
|
||||||
error:(NSError **)errorPtr;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Loads a reference image.
|
|
||||||
@param selector The test method being run.
|
|
||||||
@param identifier The optional identifier, used when multiple images are tested in a single -test method.
|
|
||||||
@param errorPtr An error, if this methods returns nil, the error will be something useful.
|
|
||||||
@returns An image.
|
|
||||||
*/
|
|
||||||
- (UIImage *)referenceImageForSelector:(SEL)selector
|
|
||||||
identifier:(NSString *)identifier
|
|
||||||
error:(NSError **)errorPtr;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Performs a pixel-by-pixel comparison of the two images with an allowable margin of error.
|
|
||||||
@param referenceImage The reference (correct) image.
|
|
||||||
@param image The image to test against the reference.
|
|
||||||
@param tolerance The percentage of pixels that can differ and still be considered 'identical'
|
|
||||||
@param errorPtr An error that indicates why the comparison failed if it does.
|
|
||||||
@returns YES if the comparison succeeded and the images are the same(ish).
|
|
||||||
*/
|
|
||||||
- (BOOL)compareReferenceImage:(UIImage *)referenceImage
|
|
||||||
toImage:(UIImage *)image
|
|
||||||
tolerance:(CGFloat)tolerance
|
|
||||||
error:(NSError **)errorPtr;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Saves the reference image and the test image to `failedOutputDirectory`.
|
|
||||||
@param referenceImage The reference (correct) image.
|
|
||||||
@param testImage The image to test against the reference.
|
|
||||||
@param selector The test method being run.
|
|
||||||
@param identifier The optional identifier, used when multiple images are tested in a single -test method.
|
|
||||||
@param errorPtr An error that indicates why the comparison failed if it does.
|
|
||||||
@returns YES if the save succeeded.
|
|
||||||
*/
|
|
||||||
- (BOOL)saveFailedReferenceImage:(UIImage *)referenceImage
|
|
||||||
testImage:(UIImage *)testImage
|
|
||||||
selector:(SEL)selector
|
|
||||||
identifier:(NSString *)identifier
|
|
||||||
error:(NSError **)errorPtr;
|
|
||||||
@end
|
|
||||||
@ -1,358 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2015, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <FBSnapshotTestCase/FBSnapshotTestController.h>
|
|
||||||
#import <FBSnapshotTestCase/FBSnapshotTestCasePlatform.h>
|
|
||||||
#import <FBSnapshotTestCase/UIImage+Compare.h>
|
|
||||||
#import <FBSnapshotTestCase/UIImage+Diff.h>
|
|
||||||
#import <FBSnapshotTestCase/UIImage+Snapshot.h>
|
|
||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
|
||||||
|
|
||||||
NSString *const FBSnapshotTestControllerErrorDomain = @"FBSnapshotTestControllerErrorDomain";
|
|
||||||
NSString *const FBReferenceImageFilePathKey = @"FBReferenceImageFilePathKey";
|
|
||||||
NSString *const FBReferenceImageKey = @"FBReferenceImageKey";
|
|
||||||
NSString *const FBCapturedImageKey = @"FBCapturedImageKey";
|
|
||||||
NSString *const FBDiffedImageKey = @"FBDiffedImageKey";
|
|
||||||
|
|
||||||
typedef NS_ENUM(NSUInteger, FBTestSnapshotFileNameType) {
|
|
||||||
FBTestSnapshotFileNameTypeReference,
|
|
||||||
FBTestSnapshotFileNameTypeFailedReference,
|
|
||||||
FBTestSnapshotFileNameTypeFailedTest,
|
|
||||||
FBTestSnapshotFileNameTypeFailedTestDiff,
|
|
||||||
};
|
|
||||||
|
|
||||||
@implementation FBSnapshotTestController
|
|
||||||
{
|
|
||||||
NSString *_testName;
|
|
||||||
NSFileManager *_fileManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - Initializers
|
|
||||||
|
|
||||||
- (instancetype)initWithTestClass:(Class)testClass;
|
|
||||||
{
|
|
||||||
return [self initWithTestName:NSStringFromClass(testClass)];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (instancetype)initWithTestName:(NSString *)testName
|
|
||||||
{
|
|
||||||
if (self = [super init]) {
|
|
||||||
_testName = [testName copy];
|
|
||||||
_deviceAgnostic = NO;
|
|
||||||
|
|
||||||
_fileManager = [[NSFileManager alloc] init];
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - Overrides
|
|
||||||
|
|
||||||
- (NSString *)description
|
|
||||||
{
|
|
||||||
return [NSString stringWithFormat:@"%@ %@", [super description], _referenceImagesDirectory];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - Public API
|
|
||||||
|
|
||||||
- (BOOL)compareSnapshotOfLayer:(CALayer *)layer
|
|
||||||
selector:(SEL)selector
|
|
||||||
identifier:(NSString *)identifier
|
|
||||||
error:(NSError **)errorPtr
|
|
||||||
{
|
|
||||||
return [self compareSnapshotOfViewOrLayer:layer
|
|
||||||
selector:selector
|
|
||||||
identifier:identifier
|
|
||||||
tolerance:0
|
|
||||||
error:errorPtr];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)compareSnapshotOfView:(UIView *)view
|
|
||||||
selector:(SEL)selector
|
|
||||||
identifier:(NSString *)identifier
|
|
||||||
error:(NSError **)errorPtr
|
|
||||||
{
|
|
||||||
return [self compareSnapshotOfViewOrLayer:view
|
|
||||||
selector:selector
|
|
||||||
identifier:identifier
|
|
||||||
tolerance:0
|
|
||||||
error:errorPtr];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)compareSnapshotOfViewOrLayer:(id)viewOrLayer
|
|
||||||
selector:(SEL)selector
|
|
||||||
identifier:(NSString *)identifier
|
|
||||||
tolerance:(CGFloat)tolerance
|
|
||||||
error:(NSError **)errorPtr
|
|
||||||
{
|
|
||||||
if (self.recordMode) {
|
|
||||||
return [self _recordSnapshotOfViewOrLayer:viewOrLayer selector:selector identifier:identifier error:errorPtr];
|
|
||||||
} else {
|
|
||||||
return [self _performPixelComparisonWithViewOrLayer:viewOrLayer selector:selector identifier:identifier tolerance:tolerance error:errorPtr];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (UIImage *)referenceImageForSelector:(SEL)selector
|
|
||||||
identifier:(NSString *)identifier
|
|
||||||
error:(NSError **)errorPtr
|
|
||||||
{
|
|
||||||
NSString *filePath = [self _referenceFilePathForSelector:selector identifier:identifier];
|
|
||||||
UIImage *image = [UIImage imageWithContentsOfFile:filePath];
|
|
||||||
if (nil == image && NULL != errorPtr) {
|
|
||||||
BOOL exists = [_fileManager fileExistsAtPath:filePath];
|
|
||||||
if (!exists) {
|
|
||||||
*errorPtr = [NSError errorWithDomain:FBSnapshotTestControllerErrorDomain
|
|
||||||
code:FBSnapshotTestControllerErrorCodeNeedsRecord
|
|
||||||
userInfo:@{
|
|
||||||
FBReferenceImageFilePathKey: filePath,
|
|
||||||
NSLocalizedDescriptionKey: @"Unable to load reference image.",
|
|
||||||
NSLocalizedFailureReasonErrorKey: @"Reference image not found. You need to run the test in record mode",
|
|
||||||
}];
|
|
||||||
} else {
|
|
||||||
*errorPtr = [NSError errorWithDomain:FBSnapshotTestControllerErrorDomain
|
|
||||||
code:FBSnapshotTestControllerErrorCodeUnknown
|
|
||||||
userInfo:nil];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return image;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)compareReferenceImage:(UIImage *)referenceImage
|
|
||||||
toImage:(UIImage *)image
|
|
||||||
tolerance:(CGFloat)tolerance
|
|
||||||
error:(NSError **)errorPtr
|
|
||||||
{
|
|
||||||
BOOL sameImageDimensions = CGSizeEqualToSize(referenceImage.size, image.size);
|
|
||||||
if (sameImageDimensions && [referenceImage fb_compareWithImage:image tolerance:tolerance]) {
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (NULL != errorPtr) {
|
|
||||||
NSString *errorDescription = sameImageDimensions ? @"Images different" : @"Images different sizes";
|
|
||||||
NSString *errorReason = sameImageDimensions ? [NSString stringWithFormat:@"image pixels differed by more than %.2f%% from the reference image", tolerance * 100]
|
|
||||||
: [NSString stringWithFormat:@"referenceImage:%@, image:%@", NSStringFromCGSize(referenceImage.size), NSStringFromCGSize(image.size)];
|
|
||||||
FBSnapshotTestControllerErrorCode errorCode = sameImageDimensions ? FBSnapshotTestControllerErrorCodeImagesDifferent : FBSnapshotTestControllerErrorCodeImagesDifferentSizes;
|
|
||||||
|
|
||||||
*errorPtr = [NSError errorWithDomain:FBSnapshotTestControllerErrorDomain
|
|
||||||
code:errorCode
|
|
||||||
userInfo:@{
|
|
||||||
NSLocalizedDescriptionKey: errorDescription,
|
|
||||||
NSLocalizedFailureReasonErrorKey: errorReason,
|
|
||||||
FBReferenceImageKey: referenceImage,
|
|
||||||
FBCapturedImageKey: image,
|
|
||||||
FBDiffedImageKey: [referenceImage fb_diffWithImage:image],
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)saveFailedReferenceImage:(UIImage *)referenceImage
|
|
||||||
testImage:(UIImage *)testImage
|
|
||||||
selector:(SEL)selector
|
|
||||||
identifier:(NSString *)identifier
|
|
||||||
error:(NSError **)errorPtr
|
|
||||||
{
|
|
||||||
NSData *referencePNGData = UIImagePNGRepresentation(referenceImage);
|
|
||||||
NSData *testPNGData = UIImagePNGRepresentation(testImage);
|
|
||||||
|
|
||||||
NSString *referencePath = [self _failedFilePathForSelector:selector
|
|
||||||
identifier:identifier
|
|
||||||
fileNameType:FBTestSnapshotFileNameTypeFailedReference];
|
|
||||||
|
|
||||||
NSError *creationError = nil;
|
|
||||||
BOOL didCreateDir = [_fileManager createDirectoryAtPath:[referencePath stringByDeletingLastPathComponent]
|
|
||||||
withIntermediateDirectories:YES
|
|
||||||
attributes:nil
|
|
||||||
error:&creationError];
|
|
||||||
if (!didCreateDir) {
|
|
||||||
if (NULL != errorPtr) {
|
|
||||||
*errorPtr = creationError;
|
|
||||||
}
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (![referencePNGData writeToFile:referencePath options:NSDataWritingAtomic error:errorPtr]) {
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
NSString *testPath = [self _failedFilePathForSelector:selector
|
|
||||||
identifier:identifier
|
|
||||||
fileNameType:FBTestSnapshotFileNameTypeFailedTest];
|
|
||||||
|
|
||||||
if (![testPNGData writeToFile:testPath options:NSDataWritingAtomic error:errorPtr]) {
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
NSString *diffPath = [self _failedFilePathForSelector:selector
|
|
||||||
identifier:identifier
|
|
||||||
fileNameType:FBTestSnapshotFileNameTypeFailedTestDiff];
|
|
||||||
|
|
||||||
UIImage *diffImage = [referenceImage fb_diffWithImage:testImage];
|
|
||||||
NSData *diffImageData = UIImagePNGRepresentation(diffImage);
|
|
||||||
|
|
||||||
if (![diffImageData writeToFile:diffPath options:NSDataWritingAtomic error:errorPtr]) {
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
NSLog(@"If you have Kaleidoscope installed you can run this command to see an image diff:\n"
|
|
||||||
@"ksdiff \"%@\" \"%@\"", referencePath, testPath);
|
|
||||||
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - Private API
|
|
||||||
|
|
||||||
- (NSString *)_fileNameForSelector:(SEL)selector
|
|
||||||
identifier:(NSString *)identifier
|
|
||||||
fileNameType:(FBTestSnapshotFileNameType)fileNameType
|
|
||||||
{
|
|
||||||
NSString *fileName = nil;
|
|
||||||
switch (fileNameType) {
|
|
||||||
case FBTestSnapshotFileNameTypeFailedReference:
|
|
||||||
fileName = @"reference_";
|
|
||||||
break;
|
|
||||||
case FBTestSnapshotFileNameTypeFailedTest:
|
|
||||||
fileName = @"failed_";
|
|
||||||
break;
|
|
||||||
case FBTestSnapshotFileNameTypeFailedTestDiff:
|
|
||||||
fileName = @"diff_";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fileName = @"";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
fileName = [fileName stringByAppendingString:NSStringFromSelector(selector)];
|
|
||||||
if (0 < identifier.length) {
|
|
||||||
fileName = [fileName stringByAppendingFormat:@"_%@", identifier];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self.isDeviceAgnostic) {
|
|
||||||
fileName = FBDeviceAgnosticNormalizedFileName(fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ([[UIScreen mainScreen] scale] > 1) {
|
|
||||||
fileName = [fileName stringByAppendingFormat:@"@%.fx", [[UIScreen mainScreen] scale]];
|
|
||||||
}
|
|
||||||
fileName = [fileName stringByAppendingPathExtension:@"png"];
|
|
||||||
return fileName;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSString *)_referenceFilePathForSelector:(SEL)selector
|
|
||||||
identifier:(NSString *)identifier
|
|
||||||
{
|
|
||||||
NSString *fileName = [self _fileNameForSelector:selector
|
|
||||||
identifier:identifier
|
|
||||||
fileNameType:FBTestSnapshotFileNameTypeReference];
|
|
||||||
NSString *filePath = [_referenceImagesDirectory stringByAppendingPathComponent:_testName];
|
|
||||||
filePath = [filePath stringByAppendingPathComponent:fileName];
|
|
||||||
return filePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSString *)_failedFilePathForSelector:(SEL)selector
|
|
||||||
identifier:(NSString *)identifier
|
|
||||||
fileNameType:(FBTestSnapshotFileNameType)fileNameType
|
|
||||||
{
|
|
||||||
NSString *fileName = [self _fileNameForSelector:selector
|
|
||||||
identifier:identifier
|
|
||||||
fileNameType:fileNameType];
|
|
||||||
NSString *folderPath = NSTemporaryDirectory();
|
|
||||||
if (getenv("IMAGE_DIFF_DIR")) {
|
|
||||||
folderPath = @(getenv("IMAGE_DIFF_DIR"));
|
|
||||||
}
|
|
||||||
NSString *filePath = [folderPath stringByAppendingPathComponent:_testName];
|
|
||||||
filePath = [filePath stringByAppendingPathComponent:fileName];
|
|
||||||
return filePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)_performPixelComparisonWithViewOrLayer:(id)viewOrLayer
|
|
||||||
selector:(SEL)selector
|
|
||||||
identifier:(NSString *)identifier
|
|
||||||
tolerance:(CGFloat)tolerance
|
|
||||||
error:(NSError **)errorPtr
|
|
||||||
{
|
|
||||||
UIImage *referenceImage = [self referenceImageForSelector:selector identifier:identifier error:errorPtr];
|
|
||||||
if (nil != referenceImage) {
|
|
||||||
UIImage *snapshot = [self _imageForViewOrLayer:viewOrLayer];
|
|
||||||
BOOL imagesSame = [self compareReferenceImage:referenceImage toImage:snapshot tolerance:tolerance error:errorPtr];
|
|
||||||
if (!imagesSame) {
|
|
||||||
NSError *saveError = nil;
|
|
||||||
if ([self saveFailedReferenceImage:referenceImage testImage:snapshot selector:selector identifier:identifier error:&saveError] == NO) {
|
|
||||||
NSLog(@"Error saving test images: %@", saveError);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return imagesSame;
|
|
||||||
}
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)_recordSnapshotOfViewOrLayer:(id)viewOrLayer
|
|
||||||
selector:(SEL)selector
|
|
||||||
identifier:(NSString *)identifier
|
|
||||||
error:(NSError **)errorPtr
|
|
||||||
{
|
|
||||||
UIImage *snapshot = [self _imageForViewOrLayer:viewOrLayer];
|
|
||||||
return [self _saveReferenceImage:snapshot selector:selector identifier:identifier error:errorPtr];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)_saveReferenceImage:(UIImage *)image
|
|
||||||
selector:(SEL)selector
|
|
||||||
identifier:(NSString *)identifier
|
|
||||||
error:(NSError **)errorPtr
|
|
||||||
{
|
|
||||||
BOOL didWrite = NO;
|
|
||||||
if (nil != image) {
|
|
||||||
NSString *filePath = [self _referenceFilePathForSelector:selector identifier:identifier];
|
|
||||||
NSData *pngData = UIImagePNGRepresentation(image);
|
|
||||||
if (nil != pngData) {
|
|
||||||
NSError *creationError = nil;
|
|
||||||
BOOL didCreateDir = [_fileManager createDirectoryAtPath:[filePath stringByDeletingLastPathComponent]
|
|
||||||
withIntermediateDirectories:YES
|
|
||||||
attributes:nil
|
|
||||||
error:&creationError];
|
|
||||||
if (!didCreateDir) {
|
|
||||||
if (NULL != errorPtr) {
|
|
||||||
*errorPtr = creationError;
|
|
||||||
}
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
didWrite = [pngData writeToFile:filePath options:NSDataWritingAtomic error:errorPtr];
|
|
||||||
if (didWrite) {
|
|
||||||
NSLog(@"Reference image save at: %@", filePath);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (nil != errorPtr) {
|
|
||||||
*errorPtr = [NSError errorWithDomain:FBSnapshotTestControllerErrorDomain
|
|
||||||
code:FBSnapshotTestControllerErrorCodePNGCreationFailed
|
|
||||||
userInfo:@{
|
|
||||||
FBReferenceImageFilePathKey: filePath,
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return didWrite;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (UIImage *)_imageForViewOrLayer:(id)viewOrLayer
|
|
||||||
{
|
|
||||||
if ([viewOrLayer isKindOfClass:[UIView class]]) {
|
|
||||||
if (_usesDrawViewHierarchyInRect) {
|
|
||||||
return [UIImage fb_imageForView:viewOrLayer];
|
|
||||||
} else {
|
|
||||||
return [UIImage fb_imageForViewLayer:viewOrLayer];
|
|
||||||
}
|
|
||||||
} else if ([viewOrLayer isKindOfClass:[CALayer class]]) {
|
|
||||||
return [UIImage fb_imageForLayer:viewOrLayer];
|
|
||||||
} else {
|
|
||||||
[NSException raise:@"Only UIView and CALayer classes can be snapshotted" format:@"%@", viewOrLayer];
|
|
||||||
}
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
@ -1,125 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2015, Facebook, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the BSD-style license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree. An additional grant
|
|
||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if swift(>=3)
|
|
||||||
public extension FBSnapshotTestCase {
|
|
||||||
public func FBSnapshotVerifyView(_ view: UIView, identifier: String = "", suffixes: NSOrderedSet = FBSnapshotTestCaseDefaultSuffixes(), tolerance: CGFloat = 0, file: StaticString = #file, line: UInt = #line) {
|
|
||||||
FBSnapshotVerifyViewOrLayer(view, identifier: identifier, suffixes: suffixes, tolerance: tolerance, file: file, line: line)
|
|
||||||
}
|
|
||||||
|
|
||||||
public func FBSnapshotVerifyLayer(_ layer: CALayer, identifier: String = "", suffixes: NSOrderedSet = FBSnapshotTestCaseDefaultSuffixes(), tolerance: CGFloat = 0, file: StaticString = #file, line: UInt = #line) {
|
|
||||||
FBSnapshotVerifyViewOrLayer(layer, identifier: identifier, suffixes: suffixes, tolerance: tolerance, file: file, line: line)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func FBSnapshotVerifyViewOrLayer(_ viewOrLayer: AnyObject, identifier: String = "", suffixes: NSOrderedSet = FBSnapshotTestCaseDefaultSuffixes(), tolerance: CGFloat = 0, file: StaticString = #file, line: UInt = #line) {
|
|
||||||
let envReferenceImageDirectory = self.getReferenceImageDirectory(withDefault: FB_REFERENCE_IMAGE_DIR)
|
|
||||||
var error: NSError?
|
|
||||||
var comparisonSuccess = false
|
|
||||||
|
|
||||||
if let envReferenceImageDirectory = envReferenceImageDirectory {
|
|
||||||
for suffix in suffixes {
|
|
||||||
let referenceImagesDirectory = "\(envReferenceImageDirectory)\(suffix)"
|
|
||||||
if viewOrLayer.isKind(of: UIView.self) {
|
|
||||||
do {
|
|
||||||
try compareSnapshot(of: viewOrLayer as! UIView, referenceImagesDirectory: referenceImagesDirectory, identifier: identifier, tolerance: tolerance)
|
|
||||||
comparisonSuccess = true
|
|
||||||
} catch let error1 as NSError {
|
|
||||||
error = error1
|
|
||||||
comparisonSuccess = false
|
|
||||||
}
|
|
||||||
} else if viewOrLayer.isKind(of: CALayer.self) {
|
|
||||||
do {
|
|
||||||
try compareSnapshot(of: viewOrLayer as! CALayer, referenceImagesDirectory: referenceImagesDirectory, identifier: identifier, tolerance: tolerance)
|
|
||||||
comparisonSuccess = true
|
|
||||||
} catch let error1 as NSError {
|
|
||||||
error = error1
|
|
||||||
comparisonSuccess = false
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
assertionFailure("Only UIView and CALayer classes can be snapshotted")
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(recordMode == false, message: "Test ran in record mode. Reference image is now saved. Disable record mode to perform an actual snapshot comparison!", file: file, line: line)
|
|
||||||
|
|
||||||
if comparisonSuccess || recordMode {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(comparisonSuccess, message: "Snapshot comparison failed: \(error)", file: file, line: line)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
XCTFail("Missing value for referenceImagesDirectory - Set FB_REFERENCE_IMAGE_DIR as Environment variable in your scheme.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func assert(_ assertion: Bool, message: String, file: StaticString, line: UInt) {
|
|
||||||
if !assertion {
|
|
||||||
XCTFail(message, file: file, line: line)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
public extension FBSnapshotTestCase {
|
|
||||||
public func FBSnapshotVerifyView(view: UIView, identifier: String = "", suffixes: NSOrderedSet = FBSnapshotTestCaseDefaultSuffixes(), tolerance: CGFloat = 0, file: StaticString = #file, line: UInt = #line) {
|
|
||||||
FBSnapshotVerifyViewOrLayer(view, identifier: identifier, suffixes: suffixes, tolerance: tolerance, file: file, line: line)
|
|
||||||
}
|
|
||||||
|
|
||||||
public func FBSnapshotVerifyLayer(layer: CALayer, identifier: String = "", suffixes: NSOrderedSet = FBSnapshotTestCaseDefaultSuffixes(), tolerance: CGFloat = 0, file: StaticString = #file, line: UInt = #line) {
|
|
||||||
FBSnapshotVerifyViewOrLayer(layer, identifier: identifier, suffixes: suffixes, tolerance: tolerance, file: file, line: line)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func FBSnapshotVerifyViewOrLayer(viewOrLayer: AnyObject, identifier: String = "", suffixes: NSOrderedSet = FBSnapshotTestCaseDefaultSuffixes(), tolerance: CGFloat = 0, file: StaticString = #file, line: UInt = #line) {
|
|
||||||
let envReferenceImageDirectory = self.getReferenceImageDirectoryWithDefault(FB_REFERENCE_IMAGE_DIR)
|
|
||||||
var error: NSError?
|
|
||||||
var comparisonSuccess = false
|
|
||||||
|
|
||||||
if let envReferenceImageDirectory = envReferenceImageDirectory {
|
|
||||||
for suffix in suffixes {
|
|
||||||
let referenceImagesDirectory = "\(envReferenceImageDirectory)\(suffix)"
|
|
||||||
if viewOrLayer.isKindOfClass(UIView) {
|
|
||||||
do {
|
|
||||||
try compareSnapshotOfView(viewOrLayer as! UIView, referenceImagesDirectory: referenceImagesDirectory, identifier: identifier, tolerance: tolerance)
|
|
||||||
comparisonSuccess = true
|
|
||||||
} catch let error1 as NSError {
|
|
||||||
error = error1
|
|
||||||
comparisonSuccess = false
|
|
||||||
}
|
|
||||||
} else if viewOrLayer.isKindOfClass(CALayer) {
|
|
||||||
do {
|
|
||||||
try compareSnapshotOfLayer(viewOrLayer as! CALayer, referenceImagesDirectory: referenceImagesDirectory, identifier: identifier, tolerance: tolerance)
|
|
||||||
comparisonSuccess = true
|
|
||||||
} catch let error1 as NSError {
|
|
||||||
error = error1
|
|
||||||
comparisonSuccess = false
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
assertionFailure("Only UIView and CALayer classes can be snapshotted")
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(recordMode == false, message: "Test ran in record mode. Reference image is now saved. Disable record mode to perform an actual snapshot comparison!", file: file, line: line)
|
|
||||||
|
|
||||||
if comparisonSuccess || recordMode {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(comparisonSuccess, message: "Snapshot comparison failed: \(error)", file: file, line: line)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
XCTFail("Missing value for referenceImagesDirectory - Set FB_REFERENCE_IMAGE_DIR as Environment variable in your scheme.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func assert(assertion: Bool, message: String, file: StaticString, line: UInt) {
|
|
||||||
if !assertion {
|
|
||||||
XCTFail(message, file: file, line: line)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
29
Example/Pods/FBSnapshotTestCase/LICENSE
generated
@ -1,29 +0,0 @@
|
|||||||
BSD License
|
|
||||||
|
|
||||||
For the FBSnapshotTestCase software
|
|
||||||
|
|
||||||
Copyright (c) 2013, Facebook, Inc.
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer.
|
|
||||||
* Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer in the documentation
|
|
||||||
and/or other materials provided with the distribution.
|
|
||||||
* Neither the name Facebook nor the names of its contributors may be used to
|
|
||||||
endorse or promote products derived from this software without specific
|
|
||||||
prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
||||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
||||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
||||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
||||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
97
Example/Pods/FBSnapshotTestCase/README.md
generated
@ -1,97 +0,0 @@
|
|||||||
FBSnapshotTestCase
|
|
||||||
======================
|
|
||||||
|
|
||||||
[](https://travis-ci.org/facebook/ios-snapshot-test-case) [](http://cocoadocs.org/docsets/FBSnapshotTestCase/)
|
|
||||||
|
|
||||||
What it does
|
|
||||||
------------
|
|
||||||
|
|
||||||
A "snapshot test case" takes a configured `UIView` or `CALayer` and uses the
|
|
||||||
`renderInContext:` method to get an image snapshot of its contents. It
|
|
||||||
compares this snapshot to a "reference image" stored in your source code
|
|
||||||
repository and fails the test if the two images don't match.
|
|
||||||
|
|
||||||
Why?
|
|
||||||
----
|
|
||||||
|
|
||||||
At Facebook we write a lot of UI code. As you might imagine, each type of
|
|
||||||
feed story is rendered using a subclass of `UIView`. There are a lot of edge
|
|
||||||
cases that we want to handle correctly:
|
|
||||||
|
|
||||||
- What if there is more text than can fit in the space available?
|
|
||||||
- What if an image doesn't match the size of an image view?
|
|
||||||
- What should the highlighted state look like?
|
|
||||||
|
|
||||||
It's straightforward to test logic code, but less obvious how you should test
|
|
||||||
views. You can do a lot of rectangle asserts, but these are hard to understand
|
|
||||||
or visualize. Looking at an image diff shows you exactly what changed and how
|
|
||||||
it will look to users.
|
|
||||||
|
|
||||||
We developed `FBSnapshotTestCase` to make snapshot tests easy.
|
|
||||||
|
|
||||||
Installation with CocoaPods
|
|
||||||
---------------------------
|
|
||||||
|
|
||||||
1. Add the following lines to your Podfile:
|
|
||||||
|
|
||||||
```
|
|
||||||
target "Tests" do
|
|
||||||
pod 'FBSnapshotTestCase'
|
|
||||||
end
|
|
||||||
```
|
|
||||||
|
|
||||||
If you support iOS 7 use `FBSnapshotTestCase/Core` instead, which doesn't contain Swift support.
|
|
||||||
|
|
||||||
Replace "Tests" with the name of your test project.
|
|
||||||
|
|
||||||
2. There are [three ways](https://github.com/facebook/ios-snapshot-test-case/blob/master/FBSnapshotTestCase/FBSnapshotTestCase.h#L19-L29) of setting reference image directories, the recommended one is to define `FB_REFERENCE_IMAGE_DIR` in your scheme. This should point to the directory where you want reference images to be stored. At Facebook, we normally use this:
|
|
||||||
|
|
||||||
|Name|Value|
|
|
||||||
|:---|:----|
|
|
||||||
|`FB_REFERENCE_IMAGE_DIR`|`$(SOURCE_ROOT)/$(PROJECT_NAME)Tests/ReferenceImages`|
|
|
||||||
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
Creating a snapshot test
|
|
||||||
------------------------
|
|
||||||
|
|
||||||
1. Subclass `FBSnapshotTestCase` instead of `XCTestCase`.
|
|
||||||
2. From within your test, use `FBSnapshotVerifyView`.
|
|
||||||
3. Run the test once with `self.recordMode = YES;` in the test's `-setUp`
|
|
||||||
method. (This creates the reference images on disk.)
|
|
||||||
4. Remove the line enabling record mode and run the test.
|
|
||||||
|
|
||||||
Features
|
|
||||||
--------
|
|
||||||
|
|
||||||
- Automatically names reference images on disk according to test class and
|
|
||||||
selector.
|
|
||||||
- Prints a descriptive error message to the console on failure. (Bonus:
|
|
||||||
failure message includes a one-line command to see an image diff if
|
|
||||||
you have [Kaleidoscope](http://www.kaleidoscopeapp.com) installed.)
|
|
||||||
- Supply an optional "identifier" if you want to perform multiple snapshots
|
|
||||||
in a single test method.
|
|
||||||
- Support for `CALayer` via `FBSnapshotVerifyLayer`.
|
|
||||||
- `usesDrawViewHierarchyInRect` to handle cases like `UIVisualEffect`, `UIAppearance` and Size Classes.
|
|
||||||
- `isDeviceAgnostic` to allow appending the device model (`iPhone`, `iPad`, `iPod Touch`, etc), OS version and screen size to the images (allowing to have multiple tests for the same «snapshot» for different `OS`s and devices).
|
|
||||||
|
|
||||||
Notes
|
|
||||||
-----
|
|
||||||
|
|
||||||
Your unit test must be an "application test", not a "logic test." (That is, it
|
|
||||||
must be run within the Simulator so that it has access to UIKit.) In Xcode 5
|
|
||||||
and later new projects only offer application tests, but older projects will
|
|
||||||
have separate targets for the two types.
|
|
||||||
|
|
||||||
Authors
|
|
||||||
-------
|
|
||||||
|
|
||||||
`FBSnapshotTestCase` was written at Facebook by
|
|
||||||
[Jonathan Dann](https://facebook.com/j.p.dann) with significant contributions by
|
|
||||||
[Todd Krabach](https://facebook.com/toddkrabach).
|
|
||||||
|
|
||||||
License
|
|
||||||
-------
|
|
||||||
|
|
||||||
`FBSnapshotTestCase` is BSD-licensed. See `LICENSE`.
|
|
||||||
17
Example/Pods/Local Podspecs/PNObject.podspec.json
generated
@ -1,21 +1,23 @@
|
|||||||
{
|
{
|
||||||
"name": "PNObject",
|
"name": "PNObject",
|
||||||
"version": "0.9.0",
|
"version": "1.0.0",
|
||||||
"summary": "PNObject is a simple replica of the more complex ParseObject",
|
"summary": "PNObject is a simple replica of the more complex ParseObject",
|
||||||
"homepage": "https://git.giuseppenucifora.com/giuseppenucifora/PNObject",
|
"homepage": "https://git.giuseppenucifora.com/giuseppenucifora/PNObject",
|
||||||
"license": "MIT",
|
"license": {
|
||||||
|
"type": "MIT",
|
||||||
|
"file": "LICENSE"
|
||||||
|
},
|
||||||
"authors": {
|
"authors": {
|
||||||
"Giuseppe Nucifora": "me@giuseppenucifora.com"
|
"Giuseppe Nucifora": "me@giuseppenucifora.com"
|
||||||
},
|
},
|
||||||
"source": {
|
"source": {
|
||||||
"git": "https://git.giuseppenucifora.com/giuseppenucifora/PNObject.git",
|
"git": "https://git.giuseppenucifora.com/giuseppenucifora/PNObject.git",
|
||||||
"tag": "0.9.0"
|
"tag": "1.0.0"
|
||||||
},
|
},
|
||||||
"platforms": {
|
"platforms": {
|
||||||
"ios": "8.0"
|
"ios": "8.0"
|
||||||
},
|
},
|
||||||
"requires_arc": true,
|
"source_files": "PNObject/Classes/**/*",
|
||||||
"source_files": "Pod/Classes/**/*",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"AFNetworking": [
|
"AFNetworking": [
|
||||||
|
|
||||||
@ -50,7 +52,10 @@
|
|||||||
"FBSDKLoginKit": [
|
"FBSDKLoginKit": [
|
||||||
|
|
||||||
],
|
],
|
||||||
"NACrypto": [
|
"NAChloride": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"DDDKeychainWrapper": [
|
||||||
|
|
||||||
],
|
],
|
||||||
"NSUserDefaults-AESEncryptor": [
|
"NSUserDefaults-AESEncryptor": [
|
||||||
|
|||||||
46
Example/Pods/Manifest.lock
generated
@ -22,40 +22,35 @@ PODS:
|
|||||||
- Bolts/Tasks (1.8.4)
|
- Bolts/Tasks (1.8.4)
|
||||||
- CocoaSecurity (1.2.4)
|
- CocoaSecurity (1.2.4)
|
||||||
- CodFis-Helper (0.1.3)
|
- CodFis-Helper (0.1.3)
|
||||||
|
- DDDKeychainWrapper (1.0.0)
|
||||||
- DJLocalization (1.2.2):
|
- DJLocalization (1.2.2):
|
||||||
- DJLocalization/Core (= 1.2.2)
|
- DJLocalization/Core (= 1.2.2)
|
||||||
- DJLocalization/Core (1.2.2)
|
- DJLocalization/Core (1.2.2)
|
||||||
- Expecta (1.0.5)
|
- Expecta (1.0.5)
|
||||||
- Expecta+Snapshots (3.0.0):
|
|
||||||
- Expecta (~> 1.0)
|
|
||||||
- FBSnapshotTestCase/Core (~> 2.0)
|
|
||||||
- Specta (~> 1.0)
|
|
||||||
- FBSDKCoreKit (4.18.0):
|
- FBSDKCoreKit (4.18.0):
|
||||||
- Bolts (~> 1.7)
|
- Bolts (~> 1.7)
|
||||||
- FBSDKLoginKit (4.18.0):
|
- FBSDKLoginKit (4.18.0):
|
||||||
- FBSDKCoreKit
|
- FBSDKCoreKit
|
||||||
- FBSDKShareKit (4.18.0):
|
- FBSDKShareKit (4.18.0):
|
||||||
- FBSDKCoreKit
|
- FBSDKCoreKit
|
||||||
- FBSnapshotTestCase (2.1.4):
|
- libsodium (1.0.11)
|
||||||
- FBSnapshotTestCase/SwiftSupport (= 2.1.4)
|
- NAChloride (2.2.1):
|
||||||
- FBSnapshotTestCase/Core (2.1.4)
|
- libsodium
|
||||||
- FBSnapshotTestCase/SwiftSupport (2.1.4):
|
- NSDate_Utils (1.0.0)
|
||||||
- FBSnapshotTestCase/Core
|
|
||||||
- NACrypto (1.0.6)
|
|
||||||
- NSDate_Utils (0.1.3)
|
|
||||||
- NSString-Helper (1.0.5)
|
- NSString-Helper (1.0.5)
|
||||||
- NSUserDefaults-AESEncryptor (0.0.4):
|
- NSUserDefaults-AESEncryptor (0.0.4):
|
||||||
- CocoaSecurity (~> 1.2.2)
|
- CocoaSecurity (~> 1.2.2)
|
||||||
- nv-ios-http-status (0.0.1)
|
- nv-ios-http-status (0.0.1)
|
||||||
- PEAR-FileManager-iOS (1.3.1)
|
- PEAR-FileManager-iOS (1.3.1)
|
||||||
- PNObject (0.9.0):
|
- PNObject (1.0.0):
|
||||||
- AFNetworking
|
- AFNetworking
|
||||||
- CodFis-Helper
|
- CodFis-Helper
|
||||||
|
- DDDKeychainWrapper
|
||||||
- DJLocalization
|
- DJLocalization
|
||||||
- FBSDKCoreKit
|
- FBSDKCoreKit
|
||||||
- FBSDKLoginKit
|
- FBSDKLoginKit
|
||||||
- FBSDKShareKit
|
- FBSDKShareKit
|
||||||
- NACrypto
|
- NAChloride
|
||||||
- NSDate_Utils
|
- NSDate_Utils
|
||||||
- NSString-Helper
|
- NSString-Helper
|
||||||
- NSUserDefaults-AESEncryptor
|
- NSUserDefaults-AESEncryptor
|
||||||
@ -71,23 +66,10 @@ PODS:
|
|||||||
- UIDevice-Utils (0.1.6)
|
- UIDevice-Utils (0.1.6)
|
||||||
|
|
||||||
DEPENDENCIES:
|
DEPENDENCIES:
|
||||||
- AFNetworking
|
|
||||||
- CodFis-Helper
|
|
||||||
- Expecta
|
- Expecta
|
||||||
- Expecta+Snapshots
|
|
||||||
- FBSDKCoreKit
|
|
||||||
- FBSDKLoginKit
|
|
||||||
- FBSDKShareKit
|
|
||||||
- FBSnapshotTestCase
|
|
||||||
- NSDate_Utils
|
|
||||||
- NSString-Helper
|
|
||||||
- nv-ios-http-status
|
|
||||||
- PEAR-FileManager-iOS
|
|
||||||
- PNObject (from `../`)
|
- PNObject (from `../`)
|
||||||
- PureLayout
|
- PureLayout
|
||||||
- Specta
|
- Specta
|
||||||
- StrongestPasswordValidator
|
|
||||||
- UIDevice-Utils
|
|
||||||
|
|
||||||
EXTERNAL SOURCES:
|
EXTERNAL SOURCES:
|
||||||
PNObject:
|
PNObject:
|
||||||
@ -98,26 +80,26 @@ SPEC CHECKSUMS:
|
|||||||
Bolts: 8a7995239dbe724f9cba2248b766d48b7ebdd322
|
Bolts: 8a7995239dbe724f9cba2248b766d48b7ebdd322
|
||||||
CocoaSecurity: d288a6f87e0f363823d2cb83e753814a6944f71a
|
CocoaSecurity: d288a6f87e0f363823d2cb83e753814a6944f71a
|
||||||
CodFis-Helper: 28be4c74d7202542459d72354f59b1215871de87
|
CodFis-Helper: 28be4c74d7202542459d72354f59b1215871de87
|
||||||
|
DDDKeychainWrapper: e681a4daba6448786fa83b4941f58102a33b1897
|
||||||
DJLocalization: 0c84029af375647d4104a42ae36be87194c46c47
|
DJLocalization: 0c84029af375647d4104a42ae36be87194c46c47
|
||||||
Expecta: e1c022fcd33910b6be89c291d2775b3fe27a89fe
|
Expecta: e1c022fcd33910b6be89c291d2775b3fe27a89fe
|
||||||
Expecta+Snapshots: c343f410c7a6392f3e22e78f94c44b6c0749a516
|
|
||||||
FBSDKCoreKit: 15fef8804a4629f98c6f4e55e81a76c9d725d85e
|
FBSDKCoreKit: 15fef8804a4629f98c6f4e55e81a76c9d725d85e
|
||||||
FBSDKLoginKit: 6773073e970b2b15fb12e451ce7f11da0532b880
|
FBSDKLoginKit: 6773073e970b2b15fb12e451ce7f11da0532b880
|
||||||
FBSDKShareKit: 0b8d6cc3f103c75297eb3c62caec284a2ccf1b9e
|
FBSDKShareKit: 0b8d6cc3f103c75297eb3c62caec284a2ccf1b9e
|
||||||
FBSnapshotTestCase: '094f9f314decbabe373b87cc339bea235a63e07a'
|
libsodium: 9aba161d2ee096977ecbdcce1ada69ffe511970c
|
||||||
NACrypto: ce3900f1775f1b0cc27ce7c4953b94c598a74149
|
NAChloride: 8f3d4f9a20df6b68840789a22a70aa4fcc437b0c
|
||||||
NSDate_Utils: 68669d2c81f310ee13026c791f4f0ed227b94c65
|
NSDate_Utils: 45d47afab329001ccafe056308d0cc05460e5298
|
||||||
NSString-Helper: 459e1b6a62b3bf7db10f01b0d102548608e945c4
|
NSString-Helper: 459e1b6a62b3bf7db10f01b0d102548608e945c4
|
||||||
NSUserDefaults-AESEncryptor: da02cfef056f1e18ebe2748767915f08b274c9c5
|
NSUserDefaults-AESEncryptor: da02cfef056f1e18ebe2748767915f08b274c9c5
|
||||||
nv-ios-http-status: b6c2b5fc8656cc19e0d3000dadce2080b99d0e2f
|
nv-ios-http-status: b6c2b5fc8656cc19e0d3000dadce2080b99d0e2f
|
||||||
PEAR-FileManager-iOS: 3bc403f68a53483f5629aa822f4649e40275c4d3
|
PEAR-FileManager-iOS: 3bc403f68a53483f5629aa822f4649e40275c4d3
|
||||||
PNObject: f8d8116d0f72252552bddcbc3703d6d1e4719354
|
PNObject: 34839792d6fcc437b3123d0770b4d45e845bf2c9
|
||||||
PureLayout: 4d550abe49a94f24c2808b9b95db9131685fe4cd
|
PureLayout: 4d550abe49a94f24c2808b9b95db9131685fe4cd
|
||||||
RZDataBinding: 6981e90ddaae2f5e02028323b1043f8c31013109
|
RZDataBinding: 6981e90ddaae2f5e02028323b1043f8c31013109
|
||||||
Specta: ac94d110b865115fe60ff2c6d7281053c6f8e8a2
|
Specta: ac94d110b865115fe60ff2c6d7281053c6f8e8a2
|
||||||
StrongestPasswordValidator: 921e42615bdf353513c6f925bffd4fc29865dbd7
|
StrongestPasswordValidator: 921e42615bdf353513c6f925bffd4fc29865dbd7
|
||||||
UIDevice-Utils: 11c10b18d3c6489b45a97436e5ae6064a3622820
|
UIDevice-Utils: 11c10b18d3c6489b45a97436e5ae6064a3622820
|
||||||
|
|
||||||
PODFILE CHECKSUM: 7c7096ec3fa75c9e7a1d2b538e5719592b9f5e60
|
PODFILE CHECKSUM: 57090c7ea88a91b49ca8dd73d9e7c6b866e772ba
|
||||||
|
|
||||||
COCOAPODS: 1.2.0.beta.1
|
COCOAPODS: 1.2.0.beta.1
|
||||||
|
|||||||
20
Example/Pods/NAChloride/LICENSE
generated
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2014 Gabriel Handford
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
19
Example/Pods/NAChloride/NAChloride/NAAEAD.h
generated
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
//
|
||||||
|
// NAAEAD.h
|
||||||
|
// NAChloride
|
||||||
|
//
|
||||||
|
// Created by Gabriel on 6/18/15.
|
||||||
|
// Copyright (c) 2015 Gabriel Handford. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
@interface NAAEAD : NSObject
|
||||||
|
|
||||||
|
@property (getter=isSecureDataEnabled) BOOL secureDataEnabled;
|
||||||
|
|
||||||
|
- (NSData *)encryptChaCha20Poly1305:(NSData *)data nonce:(NSData *)nonce key:(NSData *)key additionalData:(NSData *)additionalData error:(NSError **)error;
|
||||||
|
|
||||||
|
- (NSData *)decryptChaCha20Poly1305:(NSData *)data nonce:(NSData *)nonce key:(NSData *)key additionalData:(NSData *)additionalData error:(NSError **)error;
|
||||||
|
|
||||||
|
@end
|
||||||
98
Example/Pods/NAChloride/NAChloride/NAAEAD.m
generated
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
//
|
||||||
|
// NAAEAD.m
|
||||||
|
// NAChloride
|
||||||
|
//
|
||||||
|
// Created by Gabriel on 6/18/15.
|
||||||
|
// Copyright (c) 2015 Gabriel Handford. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "NAAEAD.h"
|
||||||
|
|
||||||
|
#import "NAInterface.h"
|
||||||
|
#import "NASecureData.h"
|
||||||
|
|
||||||
|
#import "sodium.h"
|
||||||
|
|
||||||
|
@implementation NAAEAD
|
||||||
|
|
||||||
|
+ (void)initialize { NAChlorideInit(); }
|
||||||
|
|
||||||
|
- (NSData *)encryptChaCha20Poly1305:(NSData *)data nonce:(NSData *)nonce key:(NSData *)key additionalData:(NSData *)additionalData error:(NSError **)error {
|
||||||
|
if (!nonce || [nonce length] != NAAEADNonceSize) {
|
||||||
|
if (error) *error = NAError(NAErrorCodeInvalidNonce, @"Invalid nonce");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
if (error) *error = NAError(NAErrorCodeInvalidData, @"Invalid data");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!additionalData) {
|
||||||
|
if (error) *error = NAError(NAErrorCodeInvalidAdditionalData, @"Invalid additional data");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!key || [key length] != NAAEADKeySize) {
|
||||||
|
if (error) *error = NAError(NAErrorCodeInvalidKey, @"Invalid key");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSMutableData *outData = [NSMutableData dataWithLength:[data length] + NAAEADASize];
|
||||||
|
|
||||||
|
unsigned long long outLength;
|
||||||
|
int retval = crypto_aead_chacha20poly1305_encrypt([outData mutableBytes], &outLength,
|
||||||
|
[data bytes], [data length],
|
||||||
|
[additionalData bytes], [additionalData length],
|
||||||
|
NULL,
|
||||||
|
[nonce bytes],
|
||||||
|
[key bytes]);
|
||||||
|
|
||||||
|
if (retval != 0) {
|
||||||
|
if (error) *error = NAError(NAErrorCodeFailure, @"AEAD encrypt failed");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
return outData;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSData *)decryptChaCha20Poly1305:(NSData *)data nonce:(NSData *)nonce key:(NSData *)key additionalData:(NSData *)additionalData error:(NSError **)error {
|
||||||
|
if (!nonce || [nonce length] != NAAEADNonceSize) {
|
||||||
|
if (error) *error = NAError(NAErrorCodeInvalidNonce, @"Invalid nonce");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
if (error) *error = NAError(NAErrorCodeInvalidData, @"Invalid data");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!additionalData) {
|
||||||
|
if (error) *error = NAError(NAErrorCodeInvalidAdditionalData, @"Invalid additional data");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!key || [key length] != NAAEADKeySize) {
|
||||||
|
if (error) *error = NAError(NAErrorCodeInvalidKey, @"Invalid key");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
__block unsigned long long outLength;
|
||||||
|
__block int retval = -1;
|
||||||
|
NSMutableData *outData = NAData(self.secureDataEnabled, data.length, ^(void *bytes, NSUInteger length) {
|
||||||
|
retval = crypto_aead_chacha20poly1305_decrypt(bytes, &outLength,
|
||||||
|
NULL,
|
||||||
|
[data bytes], [data length],
|
||||||
|
[additionalData bytes], [additionalData length],
|
||||||
|
[nonce bytes],
|
||||||
|
[key bytes]);
|
||||||
|
});
|
||||||
|
if (retval != 0) {
|
||||||
|
if (error) *error = NAError(NAErrorCodeVerificationFailed, @"Verification failed");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [outData na_truncate:outData.length - (NSUInteger)outLength];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
24
Example/Pods/NAChloride/NAChloride/NAAuth.h
generated
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
//
|
||||||
|
// NAAuth.h
|
||||||
|
// NAChloride
|
||||||
|
//
|
||||||
|
// Created by Gabriel on 6/16/15.
|
||||||
|
// Copyright (c) 2015 Gabriel Handford. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Computes an authentication tag for a message and a secret key, and provides a way to verify that a given tag is valid for a given message and a key.
|
||||||
|
*/
|
||||||
|
@interface NAAuth : NSObject
|
||||||
|
|
||||||
|
- (NSData *)auth:(NSData *)data key:(NSData *)key error:(NSError **)error;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns YES if verifies OK.
|
||||||
|
*/
|
||||||
|
- (BOOL)verify:(NSData *)auth data:(NSData *)data key:(NSData *)key error:(NSError **)error;
|
||||||
|
|
||||||
|
|
||||||
|
@end
|
||||||
50
Example/Pods/NAChloride/NAChloride/NAAuth.m
generated
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
//
|
||||||
|
// NAAuth.m
|
||||||
|
// NAChloride
|
||||||
|
//
|
||||||
|
// Created by Gabriel on 6/16/15.
|
||||||
|
// Copyright (c) 2015 Gabriel Handford. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "NAAuth.h"
|
||||||
|
|
||||||
|
#import "NAInterface.h"
|
||||||
|
|
||||||
|
#import "sodium.h"
|
||||||
|
|
||||||
|
@implementation NAAuth
|
||||||
|
|
||||||
|
+ (void)initialize { NAChlorideInit(); }
|
||||||
|
|
||||||
|
- (NSData *)auth:(NSData *)data key:(NSData *)key error:(NSError **)error {
|
||||||
|
if (!key || [key length] != NAAuthKeySize) {
|
||||||
|
if (error) *error = NAError(NAErrorCodeInvalidKey, @"Invalid key");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSMutableData *outData = [NSMutableData dataWithLength:NAAuthSize];
|
||||||
|
|
||||||
|
crypto_auth([outData mutableBytes], [data bytes], [data length], [key bytes]);
|
||||||
|
return outData;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)verify:(NSData *)auth data:(NSData *)data key:(NSData *)key error:(NSError **)error {
|
||||||
|
if (!key || [key length] != NAAuthKeySize) {
|
||||||
|
if (error) *error = NAError(NAErrorCodeInvalidKey, @"Invalid key");
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!auth || [auth length] != NAAuthSize) {
|
||||||
|
if (error) *error = NAError(NAErrorCodeInvalidData, @"Invalid data");
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (crypto_auth_verify([auth bytes], [data bytes], [data length], [key bytes]) != 0) {
|
||||||
|
if (error) *error = NAError(NAErrorCodeVerificationFailed, @"Verification failed");
|
||||||
|
return NO; // Message forged!
|
||||||
|
}
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
21
Example/Pods/NAChloride/NAChloride/NABox.h
generated
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
//
|
||||||
|
// NABox.h
|
||||||
|
// NAChloride
|
||||||
|
//
|
||||||
|
// Created by Gabriel on 6/18/15.
|
||||||
|
// Copyright (c) 2015 Gabriel Handford. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
#import "NABoxKeypair.h"
|
||||||
|
|
||||||
|
@interface NABox : NSObject
|
||||||
|
|
||||||
|
@property (getter=isSecureDataEnabled) BOOL secureDataEnabled;
|
||||||
|
|
||||||
|
- (NSData *)encrypt:(NSData *)data nonce:(NSData *)nonce keypair:(NABoxKeypair *)keypair error:(NSError **)error;
|
||||||
|
|
||||||
|
- (NSData *)decrypt:(NSData *)data nonce:(NSData *)nonce keypair:(NABoxKeypair *)keypair error:(NSError **)error;
|
||||||
|
|
||||||
|
@end
|
||||||
78
Example/Pods/NAChloride/NAChloride/NABox.m
generated
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
//
|
||||||
|
// NABox.m
|
||||||
|
// NAChloride
|
||||||
|
//
|
||||||
|
// Created by Gabriel on 6/18/15.
|
||||||
|
// Copyright (c) 2015 Gabriel Handford. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "NABox.h"
|
||||||
|
|
||||||
|
#import "NAInterface.h"
|
||||||
|
|
||||||
|
#import "sodium.h"
|
||||||
|
|
||||||
|
@implementation NABox
|
||||||
|
|
||||||
|
+ (void)initialize { NAChlorideInit(); }
|
||||||
|
|
||||||
|
- (NSData *)encrypt:(NSData *)data nonce:(NSData *)nonce keypair:(NABoxKeypair *)keypair error:(NSError **)error {
|
||||||
|
if (!nonce || [nonce length] != NABoxNonceSize) {
|
||||||
|
if (error) *error = NAError(NAErrorCodeInvalidNonce, @"Invalid nonce");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
if (error) *error = NAError(NAErrorCodeInvalidData, @"Invalid data");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!keypair) {
|
||||||
|
if (error) *error = NAError(NAErrorCodeInvalidKey, @"Invalid keypair");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSMutableData *outData = [NSMutableData dataWithLength:[data length] + NABoxMACSize];
|
||||||
|
|
||||||
|
int retval = crypto_box_easy([outData mutableBytes],
|
||||||
|
[data bytes], [data length],
|
||||||
|
[nonce bytes],
|
||||||
|
[keypair.publicKey bytes],
|
||||||
|
[keypair.secretKey bytes]);
|
||||||
|
|
||||||
|
if (retval != 0) {
|
||||||
|
if (error) *error = NAError(NAErrorCodeFailure, @"Encrypt (box) failed");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
return outData;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSData *)decrypt:(NSData *)data nonce:(NSData *)nonce keypair:(NABoxKeypair *)keypair error:(NSError **)error {
|
||||||
|
if (!nonce || [nonce length] != NABoxNonceSize) {
|
||||||
|
if (error) *error = NAError(NAErrorCodeInvalidNonce, @"Invalid nonce");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
if (error) *error = NAError(NAErrorCodeInvalidData, @"Invalid data");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
__block int retval = -1;
|
||||||
|
NSMutableData *outData = NAData(self.secureDataEnabled, data.length, ^(void *bytes, NSUInteger length) {
|
||||||
|
retval = crypto_box_open_easy(bytes,
|
||||||
|
[data bytes], [data length],
|
||||||
|
[nonce bytes],
|
||||||
|
[keypair.publicKey bytes],
|
||||||
|
[keypair.secretKey bytes]);
|
||||||
|
});
|
||||||
|
if (retval != 0) {
|
||||||
|
if (error) *error = NAError(NAErrorCodeVerificationFailed, @"Verification failed");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [outData na_truncate:NABoxMACSize];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
22
Example/Pods/NAChloride/NAChloride/NABoxKeypair.h
generated
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
//
|
||||||
|
// NABoxKeypair.h
|
||||||
|
// NAChloride
|
||||||
|
//
|
||||||
|
// Created by Gabriel on 6/18/15.
|
||||||
|
// Copyright (c) 2015 Gabriel Handford. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
#import "NASecureData.h"
|
||||||
|
|
||||||
|
@interface NABoxKeypair : NSObject
|
||||||
|
|
||||||
|
@property (readonly) NSData *publicKey;
|
||||||
|
@property (readonly) NASecureData *secretKey;
|
||||||
|
|
||||||
|
- (instancetype)initWithPublicKey:(NSData *)publicKey secretKey:(NASecureData *)secretKey error:(NSError **)error;
|
||||||
|
|
||||||
|
+ (instancetype)generate:(NSError **)error;
|
||||||
|
|
||||||
|
@end
|
||||||
57
Example/Pods/NAChloride/NAChloride/NABoxKeypair.m
generated
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
//
|
||||||
|
// NABoxKeypair.m
|
||||||
|
// NAChloride
|
||||||
|
//
|
||||||
|
// Created by Gabriel on 6/18/15.
|
||||||
|
// Copyright (c) 2015 Gabriel Handford. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "NABoxKeypair.h"
|
||||||
|
|
||||||
|
#import "NAInterface.h"
|
||||||
|
#import "NASecureData.h"
|
||||||
|
|
||||||
|
#import "sodium.h"
|
||||||
|
|
||||||
|
@interface NABoxKeypair ()
|
||||||
|
@property NSData *publicKey;
|
||||||
|
@property NASecureData *secretKey;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation NABoxKeypair
|
||||||
|
|
||||||
|
+ (void)initialize { NAChlorideInit(); }
|
||||||
|
|
||||||
|
- (instancetype)initWithPublicKey:(NSData *)publicKey secretKey:(NASecureData *)secretKey error:(NSError **)error {
|
||||||
|
if ((self = [super init])) {
|
||||||
|
|
||||||
|
if (!publicKey || [publicKey length] != NABoxPublicKeySize) {
|
||||||
|
if (error) *error = NAError(NAErrorCodeInvalidKey, @"Invalid public key");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!secretKey || [secretKey length] != NABoxPublicKeySize) {
|
||||||
|
if (error) *error = NAError(NAErrorCodeInvalidKey, @"Invalid secret key");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
_publicKey = publicKey;
|
||||||
|
_secretKey = secretKey;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (instancetype)generate:(NSError **)error {
|
||||||
|
NSMutableData *publicKey = [NSMutableData dataWithLength:NABoxPublicKeySize];
|
||||||
|
__block int retval = -1;
|
||||||
|
NASecureData *secretKey = [NASecureData secureReadOnlyDataWithLength:NABoxSecretKeySize completion:^(void *bytes, NSUInteger length) {
|
||||||
|
retval = crypto_box_keypair([publicKey mutableBytes], bytes);
|
||||||
|
}];
|
||||||
|
if (retval != 0) {
|
||||||
|
if (error) *error = NAError(NAErrorCodeFailure, @"Keypair generate failed");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
return [[NABoxKeypair alloc] initWithPublicKey:publicKey secretKey:secretKey error:error];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
30
Example/Pods/NAChloride/NAChloride/NAChloride.h
generated
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
//
|
||||||
|
// NAChloride.h
|
||||||
|
// NAChloride
|
||||||
|
//
|
||||||
|
// Created by Gabriel Handford on 1/16/14.
|
||||||
|
// Copyright (c) 2014 Gabriel Handford. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
//! Project version number for NAChloride.
|
||||||
|
FOUNDATION_EXPORT double NAChlorideVersionNumber;
|
||||||
|
|
||||||
|
//! Project version string for NAChloride.
|
||||||
|
FOUNDATION_EXPORT const unsigned char NAChlorideVersionString[];
|
||||||
|
|
||||||
|
// In this header, you should import all the public headers of your framework using statements like #import <NAChloride/PublicHeader.h>
|
||||||
|
|
||||||
|
#import <NAChloride/NAInterface.h>
|
||||||
|
|
||||||
|
#import <NAChloride/NASecretBox.h>
|
||||||
|
#import <NAChloride/NABox.h>
|
||||||
|
#import <NAChloride/NABoxKeypair.h>
|
||||||
|
#import <NAChloride/NAAuth.h>
|
||||||
|
#import <NAChloride/NAAEAD.h>
|
||||||
|
#import <NAChloride/NAOneTimeAuth.h>
|
||||||
|
#import <NAChloride/NAScrypt.h>
|
||||||
|
#import <NAChloride/NAStream.h>
|
||||||
|
#import <NAChloride/NARandom.h>
|
||||||
|
#import <NAChloride/NASecureData.h>
|
||||||
64
Example/Pods/NAChloride/NAChloride/NAInterface.h
generated
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
//
|
||||||
|
// NAInterface.h
|
||||||
|
// NAChloride
|
||||||
|
//
|
||||||
|
// Created by Gabriel on 6/25/14.
|
||||||
|
// Copyright (c) 2014 Gabriel Handford. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
typedef NS_ENUM (NSInteger, NAErrorCode) {
|
||||||
|
NAErrorCodeFailure = 1, // Generic failure
|
||||||
|
|
||||||
|
NAErrorCodeInvalidNonce = 100,
|
||||||
|
NAErrorCodeInvalidKey = 101,
|
||||||
|
NAErrorCodeInvalidData = 102,
|
||||||
|
NAErrorCodeInvalidSalt = 103,
|
||||||
|
NAErrorCodeInvalidAdditionalData = 104, // For AEAD
|
||||||
|
|
||||||
|
NAErrorCodeVerificationFailed = 205, // Verification failed
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const size_t NASecretBoxKeySize;
|
||||||
|
extern const size_t NASecretBoxNonceSize;
|
||||||
|
extern const size_t NASecretBoxMACSize;
|
||||||
|
|
||||||
|
extern const size_t NABoxPublicKeySize;
|
||||||
|
extern const size_t NABoxSecretKeySize;
|
||||||
|
extern const size_t NABoxNonceSize;
|
||||||
|
extern const size_t NABoxMACSize;
|
||||||
|
|
||||||
|
extern const size_t NAAuthKeySize;
|
||||||
|
extern const size_t NAAuthSize;
|
||||||
|
|
||||||
|
extern const size_t NAOneTimeAuthKeySize;
|
||||||
|
extern const size_t NAOneTimeAuthSize;
|
||||||
|
|
||||||
|
extern const size_t NAScryptSaltSize;
|
||||||
|
|
||||||
|
extern const size_t NAStreamKeySize;
|
||||||
|
extern const size_t NAStreamNonceSize;
|
||||||
|
|
||||||
|
extern const size_t NAXSalsaKeySize;
|
||||||
|
extern const size_t NAXSalsaNonceSize;
|
||||||
|
|
||||||
|
extern const size_t NAAEADKeySize;
|
||||||
|
extern const size_t NAAEADNonceSize;
|
||||||
|
extern const size_t NAAEADASize;
|
||||||
|
|
||||||
|
|
||||||
|
// Thread safe libsodium init
|
||||||
|
void NAChlorideInit(void);
|
||||||
|
|
||||||
|
// Don't call this directly (use NAChlorideInit). This is made accessible for testing.
|
||||||
|
int NASodiumInit(void);
|
||||||
|
|
||||||
|
|
||||||
|
typedef id (^NAWork)(NSError **error);
|
||||||
|
typedef void (^NACompletion)(NSError *error, id output);
|
||||||
|
void NADispatch(dispatch_queue_t queue, NAWork work, NACompletion completion);
|
||||||
|
|
||||||
|
#define NAError(CODE, DESC) [NSError errorWithDomain:@"NAChloride" code:CODE userInfo:@{NSLocalizedDescriptionKey: DESC}];
|
||||||
|
|
||||||
|
typedef void (^NADataCompletion)(void *bytes, NSUInteger length);
|
||||||
60
Example/Pods/NAChloride/NAChloride/NAInterface.m
generated
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
//
|
||||||
|
// NAInterface.m
|
||||||
|
// NACL
|
||||||
|
//
|
||||||
|
// Created by Gabriel Handford on 1/16/14.
|
||||||
|
// Copyright (c) 2014 Gabriel Handford. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "NAInterface.h"
|
||||||
|
|
||||||
|
#import "sodium.h"
|
||||||
|
|
||||||
|
const size_t NASecretBoxKeySize = crypto_secretbox_KEYBYTES;
|
||||||
|
const size_t NASecretBoxNonceSize = crypto_secretbox_NONCEBYTES;
|
||||||
|
const size_t NASecretBoxMACSize = crypto_secretbox_MACBYTES;
|
||||||
|
|
||||||
|
const size_t NABoxPublicKeySize = crypto_box_PUBLICKEYBYTES;
|
||||||
|
const size_t NABoxSecretKeySize = crypto_box_SECRETKEYBYTES;
|
||||||
|
const size_t NABoxNonceSize = crypto_box_NONCEBYTES;
|
||||||
|
const size_t NABoxMACSize = crypto_box_MACBYTES;
|
||||||
|
|
||||||
|
const size_t NAAuthKeySize = crypto_auth_KEYBYTES;
|
||||||
|
const size_t NAAuthSize = crypto_auth_BYTES;
|
||||||
|
|
||||||
|
const size_t NAOneTimeAuthKeySize = crypto_onetimeauth_KEYBYTES;
|
||||||
|
const size_t NAOneTimeAuthSize = crypto_onetimeauth_BYTES;
|
||||||
|
|
||||||
|
const size_t NAScryptSaltSize = crypto_pwhash_scryptsalsa208sha256_SALTBYTES;
|
||||||
|
|
||||||
|
const size_t NAStreamKeySize = crypto_stream_KEYBYTES;
|
||||||
|
const size_t NAStreamNonceSize = crypto_stream_NONCEBYTES;
|
||||||
|
|
||||||
|
const size_t NAXSalsaKeySize = crypto_stream_xsalsa20_KEYBYTES;
|
||||||
|
const size_t NAXSalsaNonceSize = crypto_stream_xsalsa20_NONCEBYTES;
|
||||||
|
|
||||||
|
const size_t NAAEADKeySize = crypto_aead_chacha20poly1305_KEYBYTES;
|
||||||
|
const size_t NAAEADNonceSize = crypto_aead_chacha20poly1305_NPUBBYTES;
|
||||||
|
const size_t NAAEADASize = crypto_aead_chacha20poly1305_ABYTES;
|
||||||
|
|
||||||
|
|
||||||
|
void NAChlorideInit(void) {
|
||||||
|
static dispatch_once_t sodiumInit;
|
||||||
|
dispatch_once(&sodiumInit, ^{ NASodiumInit(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
int NASodiumInit(void) {
|
||||||
|
return sodium_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NADispatch(dispatch_queue_t queue, NAWork work, NACompletion completion) {
|
||||||
|
dispatch_async(queue, ^{
|
||||||
|
|
||||||
|
NSError *error = nil;
|
||||||
|
id output = work(&error);
|
||||||
|
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
completion(error, output);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
24
Example/Pods/NAChloride/NAChloride/NAOneTimeAuth.h
generated
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
//
|
||||||
|
// NAOneTimeAuth.h
|
||||||
|
// NAChloride
|
||||||
|
//
|
||||||
|
// Created by Gabriel on 9/24/14.
|
||||||
|
// Copyright (c) 2014 Gabriel Handford. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Generates a MAC for a given message and shared key using Poly1305 algorithm
|
||||||
|
(key may NOT be reused across messages).
|
||||||
|
*/
|
||||||
|
@interface NAOneTimeAuth : NSObject
|
||||||
|
|
||||||
|
- (NSData *)auth:(NSData *)data key:(NSData *)key error:(NSError **)error;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns YES if verifies OK.
|
||||||
|
*/
|
||||||
|
- (BOOL)verify:(NSData *)auth data:(NSData *)data key:(NSData *)key error:(NSError **)error;
|
||||||
|
|
||||||
|
@end
|
||||||
49
Example/Pods/NAChloride/NAChloride/NAOneTimeAuth.m
generated
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
//
|
||||||
|
// NAOneTimeAuth.m
|
||||||
|
// NAChloride
|
||||||
|
//
|
||||||
|
// Created by Gabriel on 9/24/14.
|
||||||
|
// Copyright (c) 2014 Gabriel Handford. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "NAOneTimeAuth.h"
|
||||||
|
|
||||||
|
#import "NAInterface.h"
|
||||||
|
|
||||||
|
#import "sodium.h"
|
||||||
|
|
||||||
|
@implementation NAOneTimeAuth
|
||||||
|
|
||||||
|
+ (void)initialize { NAChlorideInit(); }
|
||||||
|
|
||||||
|
- (NSData *)auth:(NSData *)data key:(NSData *)key error:(NSError **)error {
|
||||||
|
if (!key || [key length] != NAOneTimeAuthKeySize) {
|
||||||
|
if (error) *error = NAError(NAErrorCodeInvalidKey, @"Invalid key");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSMutableData *outData = [NSMutableData dataWithLength:NAOneTimeAuthSize];
|
||||||
|
|
||||||
|
crypto_onetimeauth([outData mutableBytes], [data bytes], [data length], [key bytes]);
|
||||||
|
return outData;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)verify:(NSData *)auth data:(NSData *)data key:(NSData *)key error:(NSError **)error {
|
||||||
|
if (!key || [key length] != NAOneTimeAuthKeySize) {
|
||||||
|
if (error) *error = NAError(NAErrorCodeInvalidKey, @"Invalid key");
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!auth || [auth length] != NAOneTimeAuthSize) {
|
||||||
|
if (error) *error = NAError(NAErrorCodeInvalidData, @"Invalid data");
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (crypto_onetimeauth_verify([auth bytes], [data bytes], [data length], [key bytes]) != 0) {
|
||||||
|
if (error) *error = NAError(NAErrorCodeVerificationFailed, @"Verification failed");
|
||||||
|
return NO; // Message forged!
|
||||||
|
}
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
25
Example/Pods/NAChloride/NAChloride/NARandom.h
generated
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
//
|
||||||
|
// NARandom.h
|
||||||
|
// NAChloride
|
||||||
|
//
|
||||||
|
// Created by Gabriel on 6/16/15.
|
||||||
|
// Copyright (c) 2015 Gabriel Handford. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
#import "NASecureData.h"
|
||||||
|
|
||||||
|
@interface NARandom : NSObject
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Random data of length bytes.
|
||||||
|
*/
|
||||||
|
+ (NSData *)randomData:(NSUInteger)length;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Random & secure data of length bytes.
|
||||||
|
*/
|
||||||
|
+ (NASecureData *)randomSecureReadOnlyData:(NSUInteger)length;
|
||||||
|
|
||||||
|
@end
|
||||||
32
Example/Pods/NAChloride/NAChloride/NARandom.m
generated
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
//
|
||||||
|
// NARandom.m
|
||||||
|
// NAChloride
|
||||||
|
//
|
||||||
|
// Created by Gabriel on 6/16/15.
|
||||||
|
// Copyright (c) 2015 Gabriel Handford. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "NARandom.h"
|
||||||
|
|
||||||
|
#import "NAInterface.h"
|
||||||
|
|
||||||
|
#import "sodium.h"
|
||||||
|
|
||||||
|
@implementation NARandom
|
||||||
|
|
||||||
|
+ (void)initialize { NAChlorideInit(); }
|
||||||
|
|
||||||
|
+ (NSData *)randomData:(NSUInteger)length {
|
||||||
|
NSMutableData *outData = [NSMutableData dataWithLength:length];
|
||||||
|
randombytes_buf([outData mutableBytes], length);
|
||||||
|
return outData;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NASecureData *)randomSecureReadOnlyData:(NSUInteger)length {
|
||||||
|
NASecureData *secureData = [NASecureData secureReadOnlyDataWithLength:length completion:^(void *bytes, NSUInteger length) {
|
||||||
|
randombytes_buf(bytes, length);
|
||||||
|
}];
|
||||||
|
return secureData;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
29
Example/Pods/NAChloride/NAChloride/NAScrypt.h
generated
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
//
|
||||||
|
// NAScrypt.h
|
||||||
|
// NAChloride
|
||||||
|
//
|
||||||
|
// Created by Gabriel on 6/19/14.
|
||||||
|
// Copyright (c) 2014 Gabriel Handford. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
@interface NAScrypt : NSObject
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Key derivation.
|
||||||
|
|
||||||
|
@param password Password
|
||||||
|
@param salt Must be NAScryptSaltSize
|
||||||
|
|
||||||
|
Default opslimit is crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE.
|
||||||
|
Default memlimit is crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE.
|
||||||
|
*/
|
||||||
|
+ (NSData *)scrypt:(NSData *)password salt:(NSData *)salt error:(NSError **)error;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Use the default scrypt. This is for advanced use only.
|
||||||
|
*/
|
||||||
|
+ (NSData *)scrypt:(NSData *)password salt:(NSData *)salt N:(uint64_t)N r:(uint32_t)r p:(uint32_t)p length:(size_t)length error:(NSError **)error;
|
||||||
|
|
||||||
|
@end
|
||||||
51
Example/Pods/NAChloride/NAChloride/NAScrypt.m
generated
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
//
|
||||||
|
// NAScrypt.m
|
||||||
|
// NAChloride
|
||||||
|
//
|
||||||
|
// Created by Gabriel on 6/19/14.
|
||||||
|
// Copyright (c) 2014 Gabriel Handford. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "NAScrypt.h"
|
||||||
|
#import "NAInterface.h"
|
||||||
|
|
||||||
|
#import "sodium.h"
|
||||||
|
|
||||||
|
@implementation NAScrypt
|
||||||
|
|
||||||
|
+ (void)initialize { NAChlorideInit(); }
|
||||||
|
|
||||||
|
+ (NSData *)scrypt:(NSData *)password salt:(NSData *)salt error:(NSError **)error {
|
||||||
|
if (!salt || [salt length] != NAScryptSaltSize) {
|
||||||
|
if (error) *error = NAError(NAErrorCodeInvalidSalt, @"Invalid salt")
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSMutableData *key = [NSMutableData dataWithLength:crypto_box_SEEDBYTES];
|
||||||
|
|
||||||
|
int retval = crypto_pwhash_scryptsalsa208sha256([key mutableBytes], key.length, password.bytes, password.length, salt.bytes, crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE, crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE);
|
||||||
|
|
||||||
|
if (retval != 0) {
|
||||||
|
if (error) *error = NAError(NAErrorCodeFailure, @"Scrypt failed");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSData *)scrypt:(NSData *)password salt:(NSData *)salt N:(uint64_t)N r:(uint32_t)r p:(uint32_t)p length:(size_t)length error:(NSError **)error {
|
||||||
|
NSMutableData *outData = [NSMutableData dataWithLength:length];
|
||||||
|
|
||||||
|
int retval = crypto_pwhash_scryptsalsa208sha256_ll((uint8_t *)password.bytes, password.length, (uint8_t *)salt.bytes, salt.length, N, r, p, [outData mutableBytes], outData.length);
|
||||||
|
|
||||||
|
if (retval != 0) {
|
||||||
|
if (error) *error = NAError(NAErrorCodeFailure, @"Scrypt failed");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSAssert([outData length] == length, @"Mismatched output length");
|
||||||
|
|
||||||
|
return outData;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@ -1,14 +1,19 @@
|
|||||||
//
|
//
|
||||||
// NATwoFish.h
|
// NASecretBox.h
|
||||||
// NACrypto
|
// NACL
|
||||||
//
|
//
|
||||||
// Created by Gabriel on 6/20/14.
|
// Created by Gabriel Handford on 1/16/14.
|
||||||
// Copyright (c) 2014 Gabriel Handford. All rights reserved.
|
// Copyright (c) 2014 Gabriel Handford. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
@interface NATwoFish : NSObject
|
/*!
|
||||||
|
Encrypts and authenticates a message using a shared key and nonce.
|
||||||
|
*/
|
||||||
|
@interface NASecretBox : NSObject
|
||||||
|
|
||||||
|
@property (getter=isSecureDataEnabled) BOOL secureDataEnabled;
|
||||||
|
|
||||||
- (NSData *)encrypt:(NSData *)data nonce:(NSData *)nonce key:(NSData *)key error:(NSError **)error;
|
- (NSData *)encrypt:(NSData *)data nonce:(NSData *)nonce key:(NSData *)key error:(NSError **)error;
|
||||||
|
|
||||||
84
Example/Pods/NAChloride/NAChloride/NASecretBox.m
generated
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
//
|
||||||
|
// NASecretBox.m
|
||||||
|
// NACL
|
||||||
|
//
|
||||||
|
// Created by Gabriel Handford on 1/16/14.
|
||||||
|
// Copyright (c) 2014 Gabriel Handford. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "NASecretBox.h"
|
||||||
|
|
||||||
|
#import "NAInterface.h"
|
||||||
|
#import "NASecureData.h"
|
||||||
|
|
||||||
|
#import "sodium.h"
|
||||||
|
|
||||||
|
@implementation NASecretBox
|
||||||
|
|
||||||
|
+ (void)initialize { NAChlorideInit(); }
|
||||||
|
|
||||||
|
- (NSData *)encrypt:(NSData *)data nonce:(NSData *)nonce key:(NSData *)key error:(NSError **)error {
|
||||||
|
if (!nonce || [nonce length] != NASecretBoxNonceSize) {
|
||||||
|
if (error) *error = NAError(NAErrorCodeInvalidNonce, @"Invalid nonce");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
if (error) *error = NAError(NAErrorCodeInvalidData, @"Invalid data");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!key || [key length] != NASecretBoxKeySize) {
|
||||||
|
if (error) *error = NAError(NAErrorCodeInvalidKey, @"Invalid key");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add space for authentication tag of size MACBYTES
|
||||||
|
NSMutableData *outData = [NSMutableData dataWithLength:[data length] + NASecretBoxMACSize];
|
||||||
|
|
||||||
|
int retval = crypto_secretbox_easy([outData mutableBytes],
|
||||||
|
[data bytes], [data length],
|
||||||
|
[nonce bytes],
|
||||||
|
[key bytes]);
|
||||||
|
|
||||||
|
if (retval != 0) {
|
||||||
|
if (error) *error = NAError(NAErrorCodeFailure, @"Encrypt (secret box) failed");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
return outData;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSData *)decrypt:(NSData *)data nonce:(NSData *)nonce key:(NSData *)key error:(NSError **)error {
|
||||||
|
if (!nonce || [nonce length] != NASecretBoxNonceSize) {
|
||||||
|
if (error) *error = NAError(NAErrorCodeInvalidNonce, @"Invalid nonce");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
if (error) *error = NAError(NAErrorCodeInvalidData, @"Invalid data");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!key || [key length] != NASecretBoxKeySize) {
|
||||||
|
if (error) *error = NAError(NAErrorCodeInvalidKey, @"Invalid key");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
__block int retval = -1;
|
||||||
|
NSMutableData *outData = NAData(self.secureDataEnabled, data.length, ^(void *bytes, NSUInteger length) {
|
||||||
|
retval = crypto_secretbox_open_easy(bytes,
|
||||||
|
[data bytes], [data length],
|
||||||
|
[nonce bytes], [key bytes]);
|
||||||
|
});
|
||||||
|
if (retval != 0) {
|
||||||
|
if (error) *error = NAError(NAErrorCodeVerificationFailed, @"Verification failed");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove MAC bytes from data
|
||||||
|
return [outData na_truncate:NASecretBoxMACSize];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@end
|
||||||
52
Example/Pods/NAChloride/NAChloride/NASecureData.h
generated
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
//
|
||||||
|
// NASecureData.h
|
||||||
|
// NAChloride
|
||||||
|
//
|
||||||
|
// Created by Gabriel on 6/19/15.
|
||||||
|
// Copyright (c) 2015 Gabriel Handford. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
#import "NAInterface.h"
|
||||||
|
|
||||||
|
typedef NS_ENUM (NSInteger, NASecureDataProtection) {
|
||||||
|
NASecureDataProtectionReadWrite = 0, // Default no protection
|
||||||
|
NASecureDataProtectionReadOnly,
|
||||||
|
NASecureDataProtectionNoAccess,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Secure memory using libsodium.
|
||||||
|
*/
|
||||||
|
@interface NASecureData : NSMutableData // Subclassing for convienience
|
||||||
|
|
||||||
|
@property (nonatomic) NASecureDataProtection protection;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Secure and read only data.
|
||||||
|
*/
|
||||||
|
+ (instancetype)secureReadOnlyDataWithLength:(NSUInteger)length completion:(NADataCompletion)completion;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Secure data is has read/write protection in this block.
|
||||||
|
*/
|
||||||
|
- (void)readWrite:(void (^)(NASecureData *secureData))completion;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Truncate.
|
||||||
|
*/
|
||||||
|
- (NASecureData *)truncate:(NSUInteger)length;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
// Optional building of secure NSData
|
||||||
|
NSMutableData *NAData(BOOL secure, NSUInteger length, NADataCompletion completion);
|
||||||
|
|
||||||
|
|
||||||
|
@interface NSMutableData (NASecureData)
|
||||||
|
|
||||||
|
- (NSData *)na_truncate:(NSUInteger)length;
|
||||||
|
|
||||||
|
@end
|
||||||
100
Example/Pods/NAChloride/NAChloride/NASecureData.m
generated
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
//
|
||||||
|
// NASecureData.m
|
||||||
|
// NAChloride
|
||||||
|
//
|
||||||
|
// Created by Gabriel on 6/19/15.
|
||||||
|
// Copyright (c) 2015 Gabriel Handford. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "NASecureData.h"
|
||||||
|
|
||||||
|
#import "NAInterface.h"
|
||||||
|
|
||||||
|
#import "sodium.h"
|
||||||
|
|
||||||
|
@interface NASecureData ()
|
||||||
|
@property void *secureBytes;
|
||||||
|
@property NSUInteger secureLength;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation NASecureData
|
||||||
|
|
||||||
|
+ (void)initialize { NAChlorideInit(); }
|
||||||
|
|
||||||
|
- (instancetype)initWithLength:(NSUInteger)length {
|
||||||
|
if ((self = [super init])) {
|
||||||
|
NAChlorideInit(); // It's already init'ed, but just to be safe
|
||||||
|
_secureLength = length;
|
||||||
|
_secureBytes = sodium_malloc(length);
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (instancetype)secureReadOnlyDataWithLength:(NSUInteger)length completion:(NADataCompletion)completion {
|
||||||
|
NASecureData *secureData = [[NASecureData alloc] initWithLength:length];
|
||||||
|
completion(secureData.secureBytes, secureData.length);
|
||||||
|
secureData.protection = NASecureDataProtectionReadOnly;
|
||||||
|
return secureData;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)dealloc {
|
||||||
|
sodium_free(_secureBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setProtection:(NASecureDataProtection)protection {
|
||||||
|
switch (protection) {
|
||||||
|
// Keep these case statements order from most secure to least secure in case some jerk removes a break;
|
||||||
|
case NASecureDataProtectionReadWrite: sodium_mprotect_readwrite(_secureBytes); break;
|
||||||
|
case NASecureDataProtectionReadOnly: sodium_mprotect_readonly(_secureBytes); break;
|
||||||
|
case NASecureDataProtectionNoAccess: sodium_mprotect_noaccess(_secureBytes); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSUInteger)length {
|
||||||
|
return _secureLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (const void *)bytes {
|
||||||
|
return _secureBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void *)mutableBytes {
|
||||||
|
return _secureBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)readWrite:(void (^)(NASecureData *secureData))completion {
|
||||||
|
NASecureDataProtection protection = self.protection;
|
||||||
|
self.protection = NASecureDataProtectionReadWrite;
|
||||||
|
completion(self);
|
||||||
|
self.protection = protection;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NASecureData *)truncate:(NSUInteger)length {
|
||||||
|
if (length == 0) return self;
|
||||||
|
return [NASecureData secureReadOnlyDataWithLength:(self.length - length) completion:^(void *bytes, NSUInteger length) {
|
||||||
|
memcpy(bytes, self.bytes, length);
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSData *)na_truncate:(NSUInteger)length { return [self truncate:length]; }
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NSMutableData *NAData(BOOL secure, NSUInteger length, NADataCompletion completion) {
|
||||||
|
if (!secure) {
|
||||||
|
NSMutableData *data = [NSMutableData dataWithLength:length];
|
||||||
|
completion([data mutableBytes], length);
|
||||||
|
return data;
|
||||||
|
} else {
|
||||||
|
return [NASecureData secureReadOnlyDataWithLength:length completion:completion];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@implementation NSMutableData (NASecureData)
|
||||||
|
|
||||||
|
- (NSData *)na_truncate:(NSUInteger)length {
|
||||||
|
if (length == 0) return self;
|
||||||
|
return [NSData dataWithBytes:self.bytes length:self.length - length];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
15
Example/Pods/NAChloride/NAChloride/NAStream.h
generated
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
//
|
||||||
|
// NAStream.h
|
||||||
|
// NAChloride
|
||||||
|
//
|
||||||
|
// Created by Gabriel on 6/18/15.
|
||||||
|
// Copyright (c) 2015 Gabriel Handford. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
@interface NAStream : NSObject
|
||||||
|
|
||||||
|
- (NSData *)xor:(NSData *)data nonce:(NSData *)nonce key:(NSData *)key error:(NSError **)error;
|
||||||
|
|
||||||
|
@end
|
||||||
41
Example/Pods/NAChloride/NAChloride/NAStream.m
generated
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
//
|
||||||
|
// NAStream.m
|
||||||
|
// NAChloride
|
||||||
|
//
|
||||||
|
// Created by Gabriel on 6/18/15.
|
||||||
|
// Copyright (c) 2015 Gabriel Handford. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "NAStream.h"
|
||||||
|
|
||||||
|
#import "NAInterface.h"
|
||||||
|
|
||||||
|
#import "sodium.h"
|
||||||
|
|
||||||
|
@implementation NAStream
|
||||||
|
|
||||||
|
+ (void)initialize { NAChlorideInit(); }
|
||||||
|
|
||||||
|
- (NSData *)xor:(NSData *)data nonce:(NSData *)nonce key:(NSData *)key error:(NSError **)error {
|
||||||
|
if (!nonce || [nonce length] < NAStreamNonceSize) {
|
||||||
|
if (error) *error = NAError(NAErrorCodeInvalidNonce, @"Invalid stream nonce");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!key || [key length] != NAStreamKeySize) {
|
||||||
|
if (error) *error = NAError(NAErrorCodeInvalidKey, @"Invalid stream key");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSMutableData *outData = [NSMutableData dataWithLength:[data length]];
|
||||||
|
|
||||||
|
int retval = crypto_stream_xor([outData mutableBytes], [data bytes], [data length], [nonce bytes], [key bytes]);
|
||||||
|
if (retval != 0) {
|
||||||
|
if (error) *error = NAError(NAErrorCodeFailure, @"Stream failed");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
return outData;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||