mirror of
https://github.com/gimenete/iOS-boilerplate.git
synced 2026-01-10 06:58:12 -05:00
First commit
This commit is contained in:
12
.gitignore
vendored
Normal file
12
.gitignore
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
.DS_Store
|
||||
*.swp
|
||||
*~.nib
|
||||
|
||||
build/
|
||||
|
||||
*.pbxuser
|
||||
*.perspective
|
||||
*.perspectivev3
|
||||
*.mode1v3
|
||||
*.mode2v3
|
||||
xcuserdata
|
||||
@@ -23,6 +23,33 @@
|
||||
09885EC11418F2E600CCE17A /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 09885EBF1418F2E600CCE17A /* InfoPlist.strings */; };
|
||||
09885EC31418F2E600CCE17A /* IOSBoilerplateTests.h in Resources */ = {isa = PBXBuildFile; fileRef = 09885EC21418F2E600CCE17A /* IOSBoilerplateTests.h */; };
|
||||
09885EC51418F2E600CCE17A /* IOSBoilerplateTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 09885EC41418F2E600CCE17A /* IOSBoilerplateTests.m */; };
|
||||
09885EE11418F3B700CCE17A /* ASIAuthenticationDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 09885ED01418F3B700CCE17A /* ASIAuthenticationDialog.m */; };
|
||||
09885EE21418F3B700CCE17A /* ASIDataCompressor.m in Sources */ = {isa = PBXBuildFile; fileRef = 09885ED31418F3B700CCE17A /* ASIDataCompressor.m */; };
|
||||
09885EE31418F3B700CCE17A /* ASIDataDecompressor.m in Sources */ = {isa = PBXBuildFile; fileRef = 09885ED51418F3B700CCE17A /* ASIDataDecompressor.m */; };
|
||||
09885EE41418F3B700CCE17A /* ASIDownloadCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 09885ED71418F3B700CCE17A /* ASIDownloadCache.m */; };
|
||||
09885EE51418F3B700CCE17A /* ASIFormDataRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 09885ED91418F3B700CCE17A /* ASIFormDataRequest.m */; };
|
||||
09885EE61418F3B700CCE17A /* ASIHTTPRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 09885EDB1418F3B700CCE17A /* ASIHTTPRequest.m */; };
|
||||
09885EE71418F3B700CCE17A /* ASIInputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 09885EDF1418F3B700CCE17A /* ASIInputStream.m */; };
|
||||
09885EEB1418F3DA00CCE17A /* Reachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 09885EEA1418F3DA00CCE17A /* Reachability.m */; };
|
||||
09885EED1418F3F900CCE17A /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09885EEC1418F3F900CCE17A /* CFNetwork.framework */; };
|
||||
09885EEF1418F40200CCE17A /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09885EEE1418F40200CCE17A /* SystemConfiguration.framework */; };
|
||||
09885EF21418F44200CCE17A /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09885EF11418F44200CCE17A /* MobileCoreServices.framework */; };
|
||||
09885EF41418F46700CCE17A /* libz.1.2.3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 09885EF31418F46700CCE17A /* libz.1.2.3.dylib */; };
|
||||
09885EF91418F4AB00CCE17A /* BaseViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 09885EF81418F4AB00CCE17A /* BaseViewController.m */; };
|
||||
09885F381418F73A00CCE17A /* ImageManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 09885F371418F73A00CCE17A /* ImageManager.m */; };
|
||||
09885F3C1418FC6F00CCE17A /* HTTPHUDExample.m in Sources */ = {isa = PBXBuildFile; fileRef = 09885F3A1418FC6E00CCE17A /* HTTPHUDExample.m */; };
|
||||
09885F3D1418FC6F00CCE17A /* HTTPHUDExample.xib in Resources */ = {isa = PBXBuildFile; fileRef = 09885F3B1418FC6E00CCE17A /* HTTPHUDExample.xib */; };
|
||||
09885F421418FFE000CCE17A /* SVProgressHUD.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 09885F3F1418FFE000CCE17A /* SVProgressHUD.bundle */; };
|
||||
09885F431418FFE000CCE17A /* SVProgressHUD.m in Sources */ = {isa = PBXBuildFile; fileRef = 09885F411418FFE000CCE17A /* SVProgressHUD.m */; };
|
||||
09885F451419009200CCE17A /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09885F441419009200CCE17A /* QuartzCore.framework */; };
|
||||
09885F48141901E700CCE17A /* DictionaryHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 09885F47141901E700CCE17A /* DictionaryHelper.m */; };
|
||||
09885F4C1419028D00CCE17A /* JSONKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 09885F4B1419028D00CCE17A /* JSONKit.m */; };
|
||||
09885F50141903DA00CCE17A /* AsyncImageExample.m in Sources */ = {isa = PBXBuildFile; fileRef = 09885F4E141903DA00CCE17A /* AsyncImageExample.m */; };
|
||||
09885F51141903DA00CCE17A /* AsyncImageExample.xib in Resources */ = {isa = PBXBuildFile; fileRef = 09885F4F141903DA00CCE17A /* AsyncImageExample.xib */; };
|
||||
09885F55141909E600CCE17A /* AsyncCellImagesExample.m in Sources */ = {isa = PBXBuildFile; fileRef = 09885F53141909E500CCE17A /* AsyncCellImagesExample.m */; };
|
||||
09885F56141909E600CCE17A /* AsyncCellImagesExample.xib in Resources */ = {isa = PBXBuildFile; fileRef = 09885F54141909E500CCE17A /* AsyncCellImagesExample.xib */; };
|
||||
09885F5914190D7900CCE17A /* FastCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 09885F5814190D7900CCE17A /* FastCell.m */; };
|
||||
09D8BDF31419125000B25D67 /* AsyncCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 09D8BDF21419125000B25D67 /* AsyncCell.m */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@@ -40,22 +67,72 @@
|
||||
09885E941418F2E500CCE17A /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
|
||||
09885E961418F2E500CCE17A /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
||||
09885E981418F2E600CCE17A /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
|
||||
09885E9C1418F2E600CCE17A /* IOSBoilerplate-Info.plist */ = {isa = PBXFileReference; path = "IOSBoilerplate-Info.plist"; sourceTree = "<group>"; };
|
||||
09885E9C1418F2E600CCE17A /* IOSBoilerplate-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "IOSBoilerplate-Info.plist"; sourceTree = "<group>"; };
|
||||
09885E9E1418F2E600CCE17A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
09885EA01418F2E600CCE17A /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||
09885EA21418F2E600CCE17A /* IOSBoilerplate-Prefix.pch */ = {isa = PBXFileReference; path = "IOSBoilerplate-Prefix.pch"; sourceTree = "<group>"; };
|
||||
09885EA31418F2E600CCE17A /* IOSBoilerplateAppDelegate.h */ = {isa = PBXFileReference; path = IOSBoilerplateAppDelegate.h; sourceTree = "<group>"; };
|
||||
09885EA21418F2E600CCE17A /* IOSBoilerplate-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "IOSBoilerplate-Prefix.pch"; sourceTree = "<group>"; };
|
||||
09885EA31418F2E600CCE17A /* IOSBoilerplateAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IOSBoilerplateAppDelegate.h; sourceTree = "<group>"; };
|
||||
09885EA41418F2E600CCE17A /* IOSBoilerplateAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IOSBoilerplateAppDelegate.m; sourceTree = "<group>"; };
|
||||
09885EA71418F2E600CCE17A /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainWindow.xib; sourceTree = "<group>"; };
|
||||
09885EA91418F2E600CCE17A /* RootViewController.h */ = {isa = PBXFileReference; path = RootViewController.h; sourceTree = "<group>"; };
|
||||
09885EA91418F2E600CCE17A /* RootViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RootViewController.h; sourceTree = "<group>"; };
|
||||
09885EAA1418F2E600CCE17A /* RootViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RootViewController.m; sourceTree = "<group>"; };
|
||||
09885EAD1418F2E600CCE17A /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/RootViewController.xib; sourceTree = "<group>"; };
|
||||
09885EB41418F2E600CCE17A /* IOSBoilerplateTests.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = IOSBoilerplateTests.octest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
09885EB51418F2E600CCE17A /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = Library/Frameworks/SenTestingKit.framework; sourceTree = DEVELOPER_DIR; };
|
||||
09885EBE1418F2E600CCE17A /* IOSBoilerplateTests-Info.plist */ = {isa = PBXFileReference; path = "IOSBoilerplateTests-Info.plist"; sourceTree = "<group>"; };
|
||||
09885EBE1418F2E600CCE17A /* IOSBoilerplateTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "IOSBoilerplateTests-Info.plist"; sourceTree = "<group>"; };
|
||||
09885EC01418F2E600CCE17A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
09885EC21418F2E600CCE17A /* IOSBoilerplateTests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IOSBoilerplateTests.h; sourceTree = "<group>"; };
|
||||
09885EC41418F2E600CCE17A /* IOSBoilerplateTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IOSBoilerplateTests.m; sourceTree = "<group>"; };
|
||||
09885ECF1418F3B700CCE17A /* ASIAuthenticationDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIAuthenticationDialog.h; sourceTree = "<group>"; };
|
||||
09885ED01418F3B700CCE17A /* ASIAuthenticationDialog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASIAuthenticationDialog.m; sourceTree = "<group>"; };
|
||||
09885ED11418F3B700CCE17A /* ASICacheDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASICacheDelegate.h; sourceTree = "<group>"; };
|
||||
09885ED21418F3B700CCE17A /* ASIDataCompressor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIDataCompressor.h; sourceTree = "<group>"; };
|
||||
09885ED31418F3B700CCE17A /* ASIDataCompressor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASIDataCompressor.m; sourceTree = "<group>"; };
|
||||
09885ED41418F3B700CCE17A /* ASIDataDecompressor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIDataDecompressor.h; sourceTree = "<group>"; };
|
||||
09885ED51418F3B700CCE17A /* ASIDataDecompressor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASIDataDecompressor.m; sourceTree = "<group>"; };
|
||||
09885ED61418F3B700CCE17A /* ASIDownloadCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIDownloadCache.h; sourceTree = "<group>"; };
|
||||
09885ED71418F3B700CCE17A /* ASIDownloadCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASIDownloadCache.m; sourceTree = "<group>"; };
|
||||
09885ED81418F3B700CCE17A /* ASIFormDataRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIFormDataRequest.h; sourceTree = "<group>"; };
|
||||
09885ED91418F3B700CCE17A /* ASIFormDataRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASIFormDataRequest.m; sourceTree = "<group>"; };
|
||||
09885EDA1418F3B700CCE17A /* ASIHTTPRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIHTTPRequest.h; sourceTree = "<group>"; };
|
||||
09885EDB1418F3B700CCE17A /* ASIHTTPRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASIHTTPRequest.m; sourceTree = "<group>"; };
|
||||
09885EDC1418F3B700CCE17A /* ASIHTTPRequestConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIHTTPRequestConfig.h; sourceTree = "<group>"; };
|
||||
09885EDD1418F3B700CCE17A /* ASIHTTPRequestDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIHTTPRequestDelegate.h; sourceTree = "<group>"; };
|
||||
09885EDE1418F3B700CCE17A /* ASIInputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIInputStream.h; sourceTree = "<group>"; };
|
||||
09885EDF1418F3B700CCE17A /* ASIInputStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASIInputStream.m; sourceTree = "<group>"; };
|
||||
09885EE01418F3B700CCE17A /* ASIProgressDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIProgressDelegate.h; sourceTree = "<group>"; };
|
||||
09885EE91418F3DA00CCE17A /* Reachability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Reachability.h; sourceTree = "<group>"; };
|
||||
09885EEA1418F3DA00CCE17A /* Reachability.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Reachability.m; sourceTree = "<group>"; };
|
||||
09885EEC1418F3F900CCE17A /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; };
|
||||
09885EEE1418F40200CCE17A /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
|
||||
09885EF01418F43700CCE17A /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
|
||||
09885EF11418F44200CCE17A /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; };
|
||||
09885EF31418F46700CCE17A /* libz.1.2.3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.1.2.3.dylib; path = usr/lib/libz.1.2.3.dylib; sourceTree = SDKROOT; };
|
||||
09885EF71418F4AB00CCE17A /* BaseViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BaseViewController.h; sourceTree = "<group>"; };
|
||||
09885EF81418F4AB00CCE17A /* BaseViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BaseViewController.m; sourceTree = "<group>"; };
|
||||
09885F361418F73A00CCE17A /* ImageManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageManager.h; sourceTree = "<group>"; };
|
||||
09885F371418F73A00CCE17A /* ImageManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ImageManager.m; sourceTree = "<group>"; };
|
||||
09885F391418FC6E00CCE17A /* HTTPHUDExample.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPHUDExample.h; sourceTree = "<group>"; };
|
||||
09885F3A1418FC6E00CCE17A /* HTTPHUDExample.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTTPHUDExample.m; sourceTree = "<group>"; };
|
||||
09885F3B1418FC6E00CCE17A /* HTTPHUDExample.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = HTTPHUDExample.xib; sourceTree = "<group>"; };
|
||||
09885F3F1418FFE000CCE17A /* SVProgressHUD.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = SVProgressHUD.bundle; sourceTree = "<group>"; };
|
||||
09885F401418FFE000CCE17A /* SVProgressHUD.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SVProgressHUD.h; sourceTree = "<group>"; };
|
||||
09885F411418FFE000CCE17A /* SVProgressHUD.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SVProgressHUD.m; sourceTree = "<group>"; };
|
||||
09885F441419009200CCE17A /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
|
||||
09885F46141901E700CCE17A /* DictionaryHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DictionaryHelper.h; sourceTree = "<group>"; };
|
||||
09885F47141901E700CCE17A /* DictionaryHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DictionaryHelper.m; sourceTree = "<group>"; };
|
||||
09885F4A1419028D00CCE17A /* JSONKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSONKit.h; sourceTree = "<group>"; };
|
||||
09885F4B1419028D00CCE17A /* JSONKit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSONKit.m; sourceTree = "<group>"; };
|
||||
09885F4D141903DA00CCE17A /* AsyncImageExample.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AsyncImageExample.h; sourceTree = "<group>"; };
|
||||
09885F4E141903DA00CCE17A /* AsyncImageExample.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AsyncImageExample.m; sourceTree = "<group>"; };
|
||||
09885F4F141903DA00CCE17A /* AsyncImageExample.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = AsyncImageExample.xib; sourceTree = "<group>"; };
|
||||
09885F52141909E500CCE17A /* AsyncCellImagesExample.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AsyncCellImagesExample.h; sourceTree = "<group>"; };
|
||||
09885F53141909E500CCE17A /* AsyncCellImagesExample.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AsyncCellImagesExample.m; sourceTree = "<group>"; };
|
||||
09885F54141909E500CCE17A /* AsyncCellImagesExample.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = AsyncCellImagesExample.xib; sourceTree = "<group>"; };
|
||||
09885F5714190D7900CCE17A /* FastCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FastCell.h; sourceTree = "<group>"; };
|
||||
09885F5814190D7900CCE17A /* FastCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FastCell.m; sourceTree = "<group>"; };
|
||||
09D8BDF11419125000B25D67 /* AsyncCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AsyncCell.h; sourceTree = "<group>"; };
|
||||
09D8BDF21419125000B25D67 /* AsyncCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AsyncCell.m; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -63,9 +140,14 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
09885F451419009200CCE17A /* QuartzCore.framework in Frameworks */,
|
||||
09885EF41418F46700CCE17A /* libz.1.2.3.dylib in Frameworks */,
|
||||
09885EF21418F44200CCE17A /* MobileCoreServices.framework in Frameworks */,
|
||||
09885E991418F2E600CCE17A /* CoreGraphics.framework in Frameworks */,
|
||||
09885EEF1418F40200CCE17A /* SystemConfiguration.framework in Frameworks */,
|
||||
09885EED1418F3F900CCE17A /* CFNetwork.framework in Frameworks */,
|
||||
09885E951418F2E500CCE17A /* UIKit.framework in Frameworks */,
|
||||
09885E971418F2E500CCE17A /* Foundation.framework in Frameworks */,
|
||||
09885E991418F2E600CCE17A /* CoreGraphics.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -86,6 +168,12 @@
|
||||
09885E851418F2E500CCE17A = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
09885F441419009200CCE17A /* QuartzCore.framework */,
|
||||
09885EF31418F46700CCE17A /* libz.1.2.3.dylib */,
|
||||
09885EF11418F44200CCE17A /* MobileCoreServices.framework */,
|
||||
09885EF01418F43700CCE17A /* CoreGraphics.framework */,
|
||||
09885EEE1418F40200CCE17A /* SystemConfiguration.framework */,
|
||||
09885EEC1418F3F900CCE17A /* CFNetwork.framework */,
|
||||
09885E9A1418F2E600CCE17A /* IOSBoilerplate */,
|
||||
09885EBC1418F2E600CCE17A /* IOSBoilerplateTests */,
|
||||
09885E931418F2E500CCE17A /* Frameworks */,
|
||||
@@ -116,6 +204,12 @@
|
||||
09885E9A1418F2E600CCE17A /* IOSBoilerplate */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
09885F491419027D00CCE17A /* JSONKit */,
|
||||
09885F3E1418FFE000CCE17A /* SVProgressHUD */,
|
||||
09885EF61418F48F00CCE17A /* Helpers */,
|
||||
09885EF51418F48300CCE17A /* Examples */,
|
||||
09885EE81418F3DA00CCE17A /* Reachability */,
|
||||
09885ECE1418F33F00CCE17A /* ASIHTTPRequest */,
|
||||
09885EA31418F2E600CCE17A /* IOSBoilerplateAppDelegate.h */,
|
||||
09885EA41418F2E600CCE17A /* IOSBoilerplateAppDelegate.m */,
|
||||
09885EA61418F2E600CCE17A /* MainWindow.xib */,
|
||||
@@ -157,6 +251,92 @@
|
||||
name = "Supporting Files";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
09885ECE1418F33F00CCE17A /* ASIHTTPRequest */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
09885ECF1418F3B700CCE17A /* ASIAuthenticationDialog.h */,
|
||||
09885ED01418F3B700CCE17A /* ASIAuthenticationDialog.m */,
|
||||
09885ED11418F3B700CCE17A /* ASICacheDelegate.h */,
|
||||
09885ED21418F3B700CCE17A /* ASIDataCompressor.h */,
|
||||
09885ED31418F3B700CCE17A /* ASIDataCompressor.m */,
|
||||
09885ED41418F3B700CCE17A /* ASIDataDecompressor.h */,
|
||||
09885ED51418F3B700CCE17A /* ASIDataDecompressor.m */,
|
||||
09885ED61418F3B700CCE17A /* ASIDownloadCache.h */,
|
||||
09885ED71418F3B700CCE17A /* ASIDownloadCache.m */,
|
||||
09885ED81418F3B700CCE17A /* ASIFormDataRequest.h */,
|
||||
09885ED91418F3B700CCE17A /* ASIFormDataRequest.m */,
|
||||
09885EDA1418F3B700CCE17A /* ASIHTTPRequest.h */,
|
||||
09885EDB1418F3B700CCE17A /* ASIHTTPRequest.m */,
|
||||
09885EDC1418F3B700CCE17A /* ASIHTTPRequestConfig.h */,
|
||||
09885EDD1418F3B700CCE17A /* ASIHTTPRequestDelegate.h */,
|
||||
09885EDE1418F3B700CCE17A /* ASIInputStream.h */,
|
||||
09885EDF1418F3B700CCE17A /* ASIInputStream.m */,
|
||||
09885EE01418F3B700CCE17A /* ASIProgressDelegate.h */,
|
||||
);
|
||||
name = ASIHTTPRequest;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
09885EE81418F3DA00CCE17A /* Reachability */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
09885EE91418F3DA00CCE17A /* Reachability.h */,
|
||||
09885EEA1418F3DA00CCE17A /* Reachability.m */,
|
||||
);
|
||||
path = Reachability;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
09885EF51418F48300CCE17A /* Examples */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
09885F391418FC6E00CCE17A /* HTTPHUDExample.h */,
|
||||
09885F3A1418FC6E00CCE17A /* HTTPHUDExample.m */,
|
||||
09885F3B1418FC6E00CCE17A /* HTTPHUDExample.xib */,
|
||||
09885F4D141903DA00CCE17A /* AsyncImageExample.h */,
|
||||
09885F4E141903DA00CCE17A /* AsyncImageExample.m */,
|
||||
09885F4F141903DA00CCE17A /* AsyncImageExample.xib */,
|
||||
09885F52141909E500CCE17A /* AsyncCellImagesExample.h */,
|
||||
09885F53141909E500CCE17A /* AsyncCellImagesExample.m */,
|
||||
09885F54141909E500CCE17A /* AsyncCellImagesExample.xib */,
|
||||
09D8BDF11419125000B25D67 /* AsyncCell.h */,
|
||||
09D8BDF21419125000B25D67 /* AsyncCell.m */,
|
||||
);
|
||||
name = Examples;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
09885EF61418F48F00CCE17A /* Helpers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
09885EF71418F4AB00CCE17A /* BaseViewController.h */,
|
||||
09885EF81418F4AB00CCE17A /* BaseViewController.m */,
|
||||
09885F361418F73A00CCE17A /* ImageManager.h */,
|
||||
09885F371418F73A00CCE17A /* ImageManager.m */,
|
||||
09885F46141901E700CCE17A /* DictionaryHelper.h */,
|
||||
09885F47141901E700CCE17A /* DictionaryHelper.m */,
|
||||
09885F5714190D7900CCE17A /* FastCell.h */,
|
||||
09885F5814190D7900CCE17A /* FastCell.m */,
|
||||
);
|
||||
name = Helpers;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
09885F3E1418FFE000CCE17A /* SVProgressHUD */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
09885F3F1418FFE000CCE17A /* SVProgressHUD.bundle */,
|
||||
09885F401418FFE000CCE17A /* SVProgressHUD.h */,
|
||||
09885F411418FFE000CCE17A /* SVProgressHUD.m */,
|
||||
);
|
||||
path = SVProgressHUD;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
09885F491419027D00CCE17A /* JSONKit */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
09885F4A1419028D00CCE17A /* JSONKit.h */,
|
||||
09885F4B1419028D00CCE17A /* JSONKit.m */,
|
||||
);
|
||||
name = JSONKit;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
@@ -227,6 +407,10 @@
|
||||
09885E9F1418F2E600CCE17A /* InfoPlist.strings in Resources */,
|
||||
09885EA81418F2E600CCE17A /* MainWindow.xib in Resources */,
|
||||
09885EAE1418F2E600CCE17A /* RootViewController.xib in Resources */,
|
||||
09885F3D1418FC6F00CCE17A /* HTTPHUDExample.xib in Resources */,
|
||||
09885F421418FFE000CCE17A /* SVProgressHUD.bundle in Resources */,
|
||||
09885F51141903DA00CCE17A /* AsyncImageExample.xib in Resources */,
|
||||
09885F56141909E600CCE17A /* AsyncCellImagesExample.xib in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -265,6 +449,24 @@
|
||||
09885EA11418F2E600CCE17A /* main.m in Sources */,
|
||||
09885EA51418F2E600CCE17A /* IOSBoilerplateAppDelegate.m in Sources */,
|
||||
09885EAB1418F2E600CCE17A /* RootViewController.m in Sources */,
|
||||
09885EE11418F3B700CCE17A /* ASIAuthenticationDialog.m in Sources */,
|
||||
09885EE21418F3B700CCE17A /* ASIDataCompressor.m in Sources */,
|
||||
09885EE31418F3B700CCE17A /* ASIDataDecompressor.m in Sources */,
|
||||
09885EE41418F3B700CCE17A /* ASIDownloadCache.m in Sources */,
|
||||
09885EE51418F3B700CCE17A /* ASIFormDataRequest.m in Sources */,
|
||||
09885EE61418F3B700CCE17A /* ASIHTTPRequest.m in Sources */,
|
||||
09885EE71418F3B700CCE17A /* ASIInputStream.m in Sources */,
|
||||
09885EEB1418F3DA00CCE17A /* Reachability.m in Sources */,
|
||||
09885EF91418F4AB00CCE17A /* BaseViewController.m in Sources */,
|
||||
09885F381418F73A00CCE17A /* ImageManager.m in Sources */,
|
||||
09885F3C1418FC6F00CCE17A /* HTTPHUDExample.m in Sources */,
|
||||
09885F431418FFE000CCE17A /* SVProgressHUD.m in Sources */,
|
||||
09885F48141901E700CCE17A /* DictionaryHelper.m in Sources */,
|
||||
09885F4C1419028D00CCE17A /* JSONKit.m in Sources */,
|
||||
09885F50141903DA00CCE17A /* AsyncImageExample.m in Sources */,
|
||||
09885F55141909E600CCE17A /* AsyncCellImagesExample.m in Sources */,
|
||||
09885F5914190D7900CCE17A /* FastCell.m in Sources */,
|
||||
09D8BDF31419125000B25D67 /* AsyncCell.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -371,6 +573,7 @@
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = "IOSBoilerplate/IOSBoilerplate-Prefix.pch";
|
||||
INFOPLIST_FILE = "IOSBoilerplate/IOSBoilerplate-Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 4.0;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
WRAPPER_EXTENSION = app;
|
||||
};
|
||||
@@ -382,6 +585,7 @@
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = "IOSBoilerplate/IOSBoilerplate-Prefix.pch";
|
||||
INFOPLIST_FILE = "IOSBoilerplate/IOSBoilerplate-Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 4.0;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
WRAPPER_EXTENSION = app;
|
||||
};
|
||||
@@ -440,6 +644,7 @@
|
||||
09885ECA1418F2E600CCE17A /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
09885ECB1418F2E600CCE17A /* Build configuration list for PBXNativeTarget "IOSBoilerplateTests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
@@ -448,6 +653,7 @@
|
||||
09885ECD1418F2E600CCE17A /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
|
||||
7
IOSBoilerplate.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
7
IOSBoilerplate.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:IOSBoilerplate.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
35
IOSBoilerplate/ASIAuthenticationDialog.h
Normal file
35
IOSBoilerplate/ASIAuthenticationDialog.h
Normal file
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// ASIAuthenticationDialog.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 21/08/2009.
|
||||
// Copyright 2009 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
@class ASIHTTPRequest;
|
||||
|
||||
typedef enum _ASIAuthenticationType {
|
||||
ASIStandardAuthenticationType = 0,
|
||||
ASIProxyAuthenticationType = 1
|
||||
} ASIAuthenticationType;
|
||||
|
||||
@interface ASIAutorotatingViewController : UIViewController
|
||||
@end
|
||||
|
||||
@interface ASIAuthenticationDialog : ASIAutorotatingViewController <UIActionSheetDelegate, UITableViewDelegate, UITableViewDataSource> {
|
||||
ASIHTTPRequest *request;
|
||||
ASIAuthenticationType type;
|
||||
UITableView *tableView;
|
||||
UIViewController *presentingController;
|
||||
BOOL didEnableRotationNotifications;
|
||||
}
|
||||
+ (void)presentAuthenticationDialogForRequest:(ASIHTTPRequest *)request;
|
||||
+ (void)dismiss;
|
||||
|
||||
@property (retain) ASIHTTPRequest *request;
|
||||
@property (assign) ASIAuthenticationType type;
|
||||
@property (assign) BOOL didEnableRotationNotifications;
|
||||
@property (retain, nonatomic) UIViewController *presentingController;
|
||||
@end
|
||||
487
IOSBoilerplate/ASIAuthenticationDialog.m
Normal file
487
IOSBoilerplate/ASIAuthenticationDialog.m
Normal file
@@ -0,0 +1,487 @@
|
||||
//
|
||||
// ASIAuthenticationDialog.m
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 21/08/2009.
|
||||
// Copyright 2009 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ASIAuthenticationDialog.h"
|
||||
#import "ASIHTTPRequest.h"
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
|
||||
static ASIAuthenticationDialog *sharedDialog = nil;
|
||||
BOOL isDismissing = NO;
|
||||
static NSMutableArray *requestsNeedingAuthentication = nil;
|
||||
|
||||
static const NSUInteger kUsernameRow = 0;
|
||||
static const NSUInteger kUsernameSection = 0;
|
||||
static const NSUInteger kPasswordRow = 1;
|
||||
static const NSUInteger kPasswordSection = 0;
|
||||
static const NSUInteger kDomainRow = 0;
|
||||
static const NSUInteger kDomainSection = 1;
|
||||
|
||||
|
||||
@implementation ASIAutorotatingViewController
|
||||
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface ASIAuthenticationDialog ()
|
||||
- (void)showTitle;
|
||||
- (void)show;
|
||||
- (NSArray *)requestsRequiringTheseCredentials;
|
||||
- (void)presentNextDialog;
|
||||
- (void)keyboardWillShow:(NSNotification *)notification;
|
||||
- (void)orientationChanged:(NSNotification *)notification;
|
||||
- (void)cancelAuthenticationFromDialog:(id)sender;
|
||||
- (void)loginWithCredentialsFromDialog:(id)sender;
|
||||
@property (retain) UITableView *tableView;
|
||||
@end
|
||||
|
||||
@implementation ASIAuthenticationDialog
|
||||
|
||||
#pragma mark init / dealloc
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self == [ASIAuthenticationDialog class]) {
|
||||
requestsNeedingAuthentication = [[NSMutableArray array] retain];
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)presentAuthenticationDialogForRequest:(ASIHTTPRequest *)theRequest
|
||||
{
|
||||
// No need for a lock here, this will always be called on the main thread
|
||||
if (!sharedDialog) {
|
||||
sharedDialog = [[self alloc] init];
|
||||
[sharedDialog setRequest:theRequest];
|
||||
if ([theRequest authenticationNeeded] == ASIProxyAuthenticationNeeded) {
|
||||
[sharedDialog setType:ASIProxyAuthenticationType];
|
||||
} else {
|
||||
[sharedDialog setType:ASIStandardAuthenticationType];
|
||||
}
|
||||
[sharedDialog show];
|
||||
} else {
|
||||
[requestsNeedingAuthentication addObject:theRequest];
|
||||
}
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if ((self = [self initWithNibName:nil bundle:nil])) {
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
|
||||
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2
|
||||
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
|
||||
#endif
|
||||
if (![UIDevice currentDevice].generatesDeviceOrientationNotifications) {
|
||||
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
|
||||
[self setDidEnableRotationNotifications:YES];
|
||||
}
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:nil];
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
if ([self didEnableRotationNotifications]) {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];
|
||||
}
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
|
||||
|
||||
[request release];
|
||||
[tableView release];
|
||||
[presentingController.view removeFromSuperview];
|
||||
[presentingController release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
#pragma mark keyboard notifications
|
||||
|
||||
- (void)keyboardWillShow:(NSNotification *)notification
|
||||
{
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2
|
||||
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
|
||||
#endif
|
||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_3_2
|
||||
NSValue *keyboardBoundsValue = [[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey];
|
||||
#else
|
||||
NSValue *keyboardBoundsValue = [[notification userInfo] objectForKey:UIKeyboardBoundsUserInfoKey];
|
||||
#endif
|
||||
CGRect keyboardBounds;
|
||||
[keyboardBoundsValue getValue:&keyboardBounds];
|
||||
UIEdgeInsets e = UIEdgeInsetsMake(0, 0, keyboardBounds.size.height, 0);
|
||||
[[self tableView] setScrollIndicatorInsets:e];
|
||||
[[self tableView] setContentInset:e];
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Manually handles orientation changes on iPhone
|
||||
- (void)orientationChanged:(NSNotification *)notification
|
||||
{
|
||||
[self showTitle];
|
||||
|
||||
UIInterfaceOrientation o = (UIInterfaceOrientation)[[UIApplication sharedApplication] statusBarOrientation];
|
||||
CGFloat angle = 0;
|
||||
switch (o) {
|
||||
case UIDeviceOrientationLandscapeLeft: angle = 90; break;
|
||||
case UIDeviceOrientationLandscapeRight: angle = -90; break;
|
||||
case UIDeviceOrientationPortraitUpsideDown: angle = 180; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
CGRect f = [[UIScreen mainScreen] applicationFrame];
|
||||
|
||||
// Swap the frame height and width if necessary
|
||||
if (UIDeviceOrientationIsLandscape(o)) {
|
||||
CGFloat t;
|
||||
t = f.size.width;
|
||||
f.size.width = f.size.height;
|
||||
f.size.height = t;
|
||||
}
|
||||
|
||||
CGAffineTransform previousTransform = self.view.layer.affineTransform;
|
||||
CGAffineTransform newTransform = CGAffineTransformMakeRotation((CGFloat)(angle * M_PI / 180.0));
|
||||
|
||||
// Reset the transform so we can set the size
|
||||
self.view.layer.affineTransform = CGAffineTransformIdentity;
|
||||
self.view.frame = (CGRect){ { 0, 0 }, f.size};
|
||||
|
||||
// Revert to the previous transform for correct animation
|
||||
self.view.layer.affineTransform = previousTransform;
|
||||
|
||||
[UIView beginAnimations:nil context:NULL];
|
||||
[UIView setAnimationDuration:0.3];
|
||||
|
||||
// Set the new transform
|
||||
self.view.layer.affineTransform = newTransform;
|
||||
|
||||
// Fix the view origin
|
||||
self.view.frame = (CGRect){ { f.origin.x, f.origin.y },self.view.frame.size};
|
||||
[UIView commitAnimations];
|
||||
}
|
||||
|
||||
#pragma mark utilities
|
||||
|
||||
- (UIViewController *)presentingController
|
||||
{
|
||||
if (!presentingController) {
|
||||
presentingController = [[ASIAutorotatingViewController alloc] initWithNibName:nil bundle:nil];
|
||||
|
||||
// Attach to the window, but don't interfere.
|
||||
UIWindow *window = [[[UIApplication sharedApplication] windows] objectAtIndex:0];
|
||||
[window addSubview:[presentingController view]];
|
||||
[[presentingController view] setFrame:CGRectZero];
|
||||
[[presentingController view] setUserInteractionEnabled:NO];
|
||||
}
|
||||
|
||||
return presentingController;
|
||||
}
|
||||
|
||||
- (UITextField *)textFieldInRow:(NSUInteger)row section:(NSUInteger)section
|
||||
{
|
||||
return [[[[[self tableView] cellForRowAtIndexPath:
|
||||
[NSIndexPath indexPathForRow:row inSection:section]]
|
||||
contentView] subviews] objectAtIndex:0];
|
||||
}
|
||||
|
||||
- (UITextField *)usernameField
|
||||
{
|
||||
return [self textFieldInRow:kUsernameRow section:kUsernameSection];
|
||||
}
|
||||
|
||||
- (UITextField *)passwordField
|
||||
{
|
||||
return [self textFieldInRow:kPasswordRow section:kPasswordSection];
|
||||
}
|
||||
|
||||
- (UITextField *)domainField
|
||||
{
|
||||
return [self textFieldInRow:kDomainRow section:kDomainSection];
|
||||
}
|
||||
|
||||
#pragma mark show / dismiss
|
||||
|
||||
+ (void)dismiss
|
||||
{
|
||||
[[sharedDialog parentViewController] dismissModalViewControllerAnimated:YES];
|
||||
}
|
||||
|
||||
- (void)viewDidDisappear:(BOOL)animated
|
||||
{
|
||||
[self retain];
|
||||
[sharedDialog release];
|
||||
sharedDialog = nil;
|
||||
[self performSelector:@selector(presentNextDialog) withObject:nil afterDelay:0];
|
||||
[self release];
|
||||
}
|
||||
|
||||
- (void)dismiss
|
||||
{
|
||||
if (self == sharedDialog) {
|
||||
[[self class] dismiss];
|
||||
} else {
|
||||
[[self parentViewController] dismissModalViewControllerAnimated:YES];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)showTitle
|
||||
{
|
||||
UINavigationBar *navigationBar = [[[self view] subviews] objectAtIndex:0];
|
||||
UINavigationItem *navItem = [[navigationBar items] objectAtIndex:0];
|
||||
if (UIInterfaceOrientationIsPortrait([[UIDevice currentDevice] orientation])) {
|
||||
// Setup the title
|
||||
if ([self type] == ASIProxyAuthenticationType) {
|
||||
[navItem setPrompt:@"Login to this secure proxy server."];
|
||||
} else {
|
||||
[navItem setPrompt:@"Login to this secure server."];
|
||||
}
|
||||
} else {
|
||||
[navItem setPrompt:nil];
|
||||
}
|
||||
[navigationBar sizeToFit];
|
||||
CGRect f = [[self view] bounds];
|
||||
f.origin.y = [navigationBar frame].size.height;
|
||||
f.size.height -= f.origin.y;
|
||||
[[self tableView] setFrame:f];
|
||||
}
|
||||
|
||||
- (void)show
|
||||
{
|
||||
// Remove all subviews
|
||||
UIView *v;
|
||||
while ((v = [[[self view] subviews] lastObject])) {
|
||||
[v removeFromSuperview];
|
||||
}
|
||||
|
||||
// Setup toolbar
|
||||
UINavigationBar *bar = [[[UINavigationBar alloc] init] autorelease];
|
||||
[bar setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
|
||||
|
||||
UINavigationItem *navItem = [[[UINavigationItem alloc] init] autorelease];
|
||||
bar.items = [NSArray arrayWithObject:navItem];
|
||||
|
||||
[[self view] addSubview:bar];
|
||||
|
||||
[self showTitle];
|
||||
|
||||
// Setup toolbar buttons
|
||||
if ([self type] == ASIProxyAuthenticationType) {
|
||||
[navItem setTitle:[[self request] proxyHost]];
|
||||
} else {
|
||||
[navItem setTitle:[[[self request] url] host]];
|
||||
}
|
||||
|
||||
[navItem setLeftBarButtonItem:[[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancelAuthenticationFromDialog:)] autorelease]];
|
||||
[navItem setRightBarButtonItem:[[[UIBarButtonItem alloc] initWithTitle:@"Login" style:UIBarButtonItemStyleDone target:self action:@selector(loginWithCredentialsFromDialog:)] autorelease]];
|
||||
|
||||
// We show the login form in a table view, similar to Safari's authentication dialog
|
||||
[bar sizeToFit];
|
||||
CGRect f = [[self view] bounds];
|
||||
f.origin.y = [bar frame].size.height;
|
||||
f.size.height -= f.origin.y;
|
||||
|
||||
[self setTableView:[[[UITableView alloc] initWithFrame:f style:UITableViewStyleGrouped] autorelease]];
|
||||
[[self tableView] setDelegate:self];
|
||||
[[self tableView] setDataSource:self];
|
||||
[[self tableView] setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
|
||||
[[self view] addSubview:[self tableView]];
|
||||
|
||||
// Force reload the table content, and focus the first field to show the keyboard
|
||||
[[self tableView] reloadData];
|
||||
[[[[[self tableView] cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]].contentView subviews] objectAtIndex:0] becomeFirstResponder];
|
||||
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2
|
||||
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
|
||||
[self setModalPresentationStyle:UIModalPresentationFormSheet];
|
||||
}
|
||||
#endif
|
||||
|
||||
[[self presentingController] presentModalViewController:self animated:YES];
|
||||
}
|
||||
|
||||
#pragma mark button callbacks
|
||||
|
||||
- (void)cancelAuthenticationFromDialog:(id)sender
|
||||
{
|
||||
for (ASIHTTPRequest *theRequest in [self requestsRequiringTheseCredentials]) {
|
||||
[theRequest cancelAuthentication];
|
||||
[requestsNeedingAuthentication removeObject:theRequest];
|
||||
}
|
||||
[self dismiss];
|
||||
}
|
||||
|
||||
- (NSArray *)requestsRequiringTheseCredentials
|
||||
{
|
||||
NSMutableArray *requestsRequiringTheseCredentials = [NSMutableArray array];
|
||||
NSURL *requestURL = [[self request] url];
|
||||
for (ASIHTTPRequest *otherRequest in requestsNeedingAuthentication) {
|
||||
NSURL *theURL = [otherRequest url];
|
||||
if (([otherRequest authenticationNeeded] == [[self request] authenticationNeeded]) && [[theURL host] isEqualToString:[requestURL host]] && ([theURL port] == [requestURL port] || ([requestURL port] && [[theURL port] isEqualToNumber:[requestURL port]])) && [[theURL scheme] isEqualToString:[requestURL scheme]] && ((![otherRequest authenticationRealm] && ![[self request] authenticationRealm]) || ([otherRequest authenticationRealm] && [[self request] authenticationRealm] && [[[self request] authenticationRealm] isEqualToString:[otherRequest authenticationRealm]]))) {
|
||||
[requestsRequiringTheseCredentials addObject:otherRequest];
|
||||
}
|
||||
}
|
||||
[requestsRequiringTheseCredentials addObject:[self request]];
|
||||
return requestsRequiringTheseCredentials;
|
||||
}
|
||||
|
||||
- (void)presentNextDialog
|
||||
{
|
||||
if ([requestsNeedingAuthentication count]) {
|
||||
ASIHTTPRequest *nextRequest = [requestsNeedingAuthentication objectAtIndex:0];
|
||||
[requestsNeedingAuthentication removeObjectAtIndex:0];
|
||||
[[self class] presentAuthenticationDialogForRequest:nextRequest];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void)loginWithCredentialsFromDialog:(id)sender
|
||||
{
|
||||
for (ASIHTTPRequest *theRequest in [self requestsRequiringTheseCredentials]) {
|
||||
|
||||
NSString *username = [[self usernameField] text];
|
||||
NSString *password = [[self passwordField] text];
|
||||
|
||||
if (username == nil) { username = @""; }
|
||||
if (password == nil) { password = @""; }
|
||||
|
||||
if ([self type] == ASIProxyAuthenticationType) {
|
||||
[theRequest setProxyUsername:username];
|
||||
[theRequest setProxyPassword:password];
|
||||
} else {
|
||||
[theRequest setUsername:username];
|
||||
[theRequest setPassword:password];
|
||||
}
|
||||
|
||||
// Handle NTLM domains
|
||||
NSString *scheme = ([self type] == ASIStandardAuthenticationType) ? [[self request] authenticationScheme] : [[self request] proxyAuthenticationScheme];
|
||||
if ([scheme isEqualToString:(NSString *)kCFHTTPAuthenticationSchemeNTLM]) {
|
||||
NSString *domain = [[self domainField] text];
|
||||
if ([self type] == ASIProxyAuthenticationType) {
|
||||
[theRequest setProxyDomain:domain];
|
||||
} else {
|
||||
[theRequest setDomain:domain];
|
||||
}
|
||||
}
|
||||
|
||||
[theRequest retryUsingSuppliedCredentials];
|
||||
[requestsNeedingAuthentication removeObject:theRequest];
|
||||
}
|
||||
[self dismiss];
|
||||
}
|
||||
|
||||
#pragma mark table view data source
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)aTableView
|
||||
{
|
||||
NSString *scheme = ([self type] == ASIStandardAuthenticationType) ? [[self request] authenticationScheme] : [[self request] proxyAuthenticationScheme];
|
||||
if ([scheme isEqualToString:(NSString *)kCFHTTPAuthenticationSchemeNTLM]) {
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)aTableView heightForFooterInSection:(NSInteger)section
|
||||
{
|
||||
if (section == [self numberOfSectionsInTableView:aTableView]-1) {
|
||||
return 30;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)aTableView heightForHeaderInSection:(NSInteger)section
|
||||
{
|
||||
if (section == 0) {
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2
|
||||
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
|
||||
return 54;
|
||||
}
|
||||
#endif
|
||||
return 30;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
|
||||
{
|
||||
if (section == 0) {
|
||||
return [[self request] authenticationRealm];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_3_0
|
||||
UITableViewCell *cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil] autorelease];
|
||||
#else
|
||||
UITableViewCell *cell = [[[UITableViewCell alloc] initWithFrame:CGRectMake(0,0,0,0) reuseIdentifier:nil] autorelease];
|
||||
#endif
|
||||
|
||||
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
|
||||
|
||||
CGRect f = CGRectInset([cell bounds], 10, 10);
|
||||
UITextField *textField = [[[UITextField alloc] initWithFrame:f] autorelease];
|
||||
[textField setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
|
||||
[textField setAutocapitalizationType:UITextAutocapitalizationTypeNone];
|
||||
[textField setAutocorrectionType:UITextAutocorrectionTypeNo];
|
||||
|
||||
NSUInteger s = [indexPath section];
|
||||
NSUInteger r = [indexPath row];
|
||||
|
||||
if (s == kUsernameSection && r == kUsernameRow) {
|
||||
[textField setPlaceholder:@"User"];
|
||||
} else if (s == kPasswordSection && r == kPasswordRow) {
|
||||
[textField setPlaceholder:@"Password"];
|
||||
[textField setSecureTextEntry:YES];
|
||||
} else if (s == kDomainSection && r == kDomainRow) {
|
||||
[textField setPlaceholder:@"Domain"];
|
||||
}
|
||||
[cell.contentView addSubview:textField];
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)aTableView numberOfRowsInSection:(NSInteger)section
|
||||
{
|
||||
if (section == 0) {
|
||||
return 2;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)tableView:(UITableView *)aTableView titleForFooterInSection:(NSInteger)section
|
||||
{
|
||||
if (section == [self numberOfSectionsInTableView:aTableView]-1) {
|
||||
// If we're using Basic authentication and the connection is not using SSL, we'll show the plain text message
|
||||
if ([[[self request] authenticationScheme] isEqualToString:(NSString *)kCFHTTPAuthenticationSchemeBasic] && ![[[[self request] url] scheme] isEqualToString:@"https"]) {
|
||||
return @"Password will be sent in the clear.";
|
||||
// We are using Digest, NTLM, or any scheme over SSL
|
||||
} else {
|
||||
return @"Password will be sent securely.";
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@synthesize request;
|
||||
@synthesize type;
|
||||
@synthesize tableView;
|
||||
@synthesize didEnableRotationNotifications;
|
||||
@synthesize presentingController;
|
||||
@end
|
||||
103
IOSBoilerplate/ASICacheDelegate.h
Normal file
103
IOSBoilerplate/ASICacheDelegate.h
Normal file
@@ -0,0 +1,103 @@
|
||||
//
|
||||
// ASICacheDelegate.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 01/05/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
@class ASIHTTPRequest;
|
||||
|
||||
// Cache policies control the behaviour of a cache and how requests use the cache
|
||||
// When setting a cache policy, you can use a combination of these values as a bitmask
|
||||
// For example: [request setCachePolicy:ASIAskServerIfModifiedCachePolicy|ASIFallbackToCacheIfLoadFailsCachePolicy|ASIDoNotWriteToCacheCachePolicy];
|
||||
// Note that some of the behaviours below are mutally exclusive - you cannot combine ASIAskServerIfModifiedWhenStaleCachePolicy and ASIAskServerIfModifiedCachePolicy, for example.
|
||||
typedef enum _ASICachePolicy {
|
||||
|
||||
// The default cache policy. When you set a request to use this, it will use the cache's defaultCachePolicy
|
||||
// ASIDownloadCache's default cache policy is 'ASIAskServerIfModifiedWhenStaleCachePolicy'
|
||||
ASIUseDefaultCachePolicy = 0,
|
||||
|
||||
// Tell the request not to read from the cache
|
||||
ASIDoNotReadFromCacheCachePolicy = 1,
|
||||
|
||||
// The the request not to write to the cache
|
||||
ASIDoNotWriteToCacheCachePolicy = 2,
|
||||
|
||||
// Ask the server if there is an updated version of this resource (using a conditional GET) ONLY when the cached data is stale
|
||||
ASIAskServerIfModifiedWhenStaleCachePolicy = 4,
|
||||
|
||||
// Always ask the server if there is an updated version of this resource (using a conditional GET)
|
||||
ASIAskServerIfModifiedCachePolicy = 8,
|
||||
|
||||
// If cached data exists, use it even if it is stale. This means requests will not talk to the server unless the resource they are requesting is not in the cache
|
||||
ASIOnlyLoadIfNotCachedCachePolicy = 16,
|
||||
|
||||
// If cached data exists, use it even if it is stale. If cached data does not exist, stop (will not set an error on the request)
|
||||
ASIDontLoadCachePolicy = 32,
|
||||
|
||||
// Specifies that cached data may be used if the request fails. If cached data is used, the request will succeed without error. Usually used in combination with other options above.
|
||||
ASIFallbackToCacheIfLoadFailsCachePolicy = 64
|
||||
} ASICachePolicy;
|
||||
|
||||
// Cache storage policies control whether cached data persists between application launches (ASICachePermanentlyCacheStoragePolicy) or not (ASICacheForSessionDurationCacheStoragePolicy)
|
||||
// Calling [ASIHTTPRequest clearSession] will remove any data stored using ASICacheForSessionDurationCacheStoragePolicy
|
||||
typedef enum _ASICacheStoragePolicy {
|
||||
ASICacheForSessionDurationCacheStoragePolicy = 0,
|
||||
ASICachePermanentlyCacheStoragePolicy = 1
|
||||
} ASICacheStoragePolicy;
|
||||
|
||||
|
||||
@protocol ASICacheDelegate <NSObject>
|
||||
|
||||
@required
|
||||
|
||||
// Should return the cache policy that will be used when requests have their cache policy set to ASIUseDefaultCachePolicy
|
||||
- (ASICachePolicy)defaultCachePolicy;
|
||||
|
||||
// Returns the date a cached response should expire on. Pass a non-zero max age to specify a custom date.
|
||||
- (NSDate *)expiryDateForRequest:(ASIHTTPRequest *)request maxAge:(NSTimeInterval)maxAge;
|
||||
|
||||
// Updates cached response headers with a new expiry date. Pass a non-zero max age to specify a custom date.
|
||||
- (void)updateExpiryForRequest:(ASIHTTPRequest *)request maxAge:(NSTimeInterval)maxAge;
|
||||
|
||||
// Looks at the request's cache policy and any cached headers to determine if the cache data is still valid
|
||||
- (BOOL)canUseCachedDataForRequest:(ASIHTTPRequest *)request;
|
||||
|
||||
// Removes cached data for a particular request
|
||||
- (void)removeCachedDataForRequest:(ASIHTTPRequest *)request;
|
||||
|
||||
// Should return YES if the cache considers its cached response current for the request
|
||||
// Should return NO is the data is not cached, or (for example) if the cached headers state the request should have expired
|
||||
- (BOOL)isCachedDataCurrentForRequest:(ASIHTTPRequest *)request;
|
||||
|
||||
// Should store the response for the passed request in the cache
|
||||
// When a non-zero maxAge is passed, it should be used as the expiry time for the cached response
|
||||
- (void)storeResponseForRequest:(ASIHTTPRequest *)request maxAge:(NSTimeInterval)maxAge;
|
||||
|
||||
// Removes cached data for a particular url
|
||||
- (void)removeCachedDataForURL:(NSURL *)url;
|
||||
|
||||
// Should return an NSDictionary of cached headers for the passed URL, if it is stored in the cache
|
||||
- (NSDictionary *)cachedResponseHeadersForURL:(NSURL *)url;
|
||||
|
||||
// Should return the cached body of a response for the passed URL, if it is stored in the cache
|
||||
- (NSData *)cachedResponseDataForURL:(NSURL *)url;
|
||||
|
||||
// Returns a path to the cached response data, if it exists
|
||||
- (NSString *)pathToCachedResponseDataForURL:(NSURL *)url;
|
||||
|
||||
// Returns a path to the cached response headers, if they url
|
||||
- (NSString *)pathToCachedResponseHeadersForURL:(NSURL *)url;
|
||||
|
||||
// Returns the location to use to store cached response headers for a particular request
|
||||
- (NSString *)pathToStoreCachedResponseHeadersForRequest:(ASIHTTPRequest *)request;
|
||||
|
||||
// Returns the location to use to store a cached response body for a particular request
|
||||
- (NSString *)pathToStoreCachedResponseDataForRequest:(ASIHTTPRequest *)request;
|
||||
|
||||
// Clear cached data stored for the passed storage policy
|
||||
- (void)clearCachedResponsesForStoragePolicy:(ASICacheStoragePolicy)cachePolicy;
|
||||
|
||||
@end
|
||||
42
IOSBoilerplate/ASIDataCompressor.h
Normal file
42
IOSBoilerplate/ASIDataCompressor.h
Normal file
@@ -0,0 +1,42 @@
|
||||
//
|
||||
// ASIDataCompressor.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 17/08/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
// This is a helper class used by ASIHTTPRequest to handle deflating (compressing) data in memory and on disk
|
||||
// You may also find it helpful if you need to deflate data and files yourself - see the class methods below
|
||||
// Most of the zlib stuff is based on the sample code by Mark Adler available at http://zlib.net
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <zlib.h>
|
||||
|
||||
@interface ASIDataCompressor : NSObject {
|
||||
BOOL streamReady;
|
||||
z_stream zStream;
|
||||
}
|
||||
|
||||
// Convenience constructor will call setupStream for you
|
||||
+ (id)compressor;
|
||||
|
||||
// Compress the passed chunk of data
|
||||
// Passing YES for shouldFinish will finalize the deflated data - you must pass YES when you are on the last chunk of data
|
||||
- (NSData *)compressBytes:(Bytef *)bytes length:(NSUInteger)length error:(NSError **)err shouldFinish:(BOOL)shouldFinish;
|
||||
|
||||
// Convenience method - pass it some data, and you'll get deflated data back
|
||||
+ (NSData *)compressData:(NSData*)uncompressedData error:(NSError **)err;
|
||||
|
||||
// Convenience method - pass it a file containing the data to compress in sourcePath, and it will write deflated data to destinationPath
|
||||
+ (BOOL)compressDataFromFile:(NSString *)sourcePath toFile:(NSString *)destinationPath error:(NSError **)err;
|
||||
|
||||
// Sets up zlib to handle the inflating. You only need to call this yourself if you aren't using the convenience constructor 'compressor'
|
||||
- (NSError *)setupStream;
|
||||
|
||||
// Tells zlib to clean up. You need to call this if you need to cancel deflating part way through
|
||||
// If deflating finishes or fails, this method will be called automatically
|
||||
- (NSError *)closeStream;
|
||||
|
||||
@property (assign, readonly) BOOL streamReady;
|
||||
@end
|
||||
219
IOSBoilerplate/ASIDataCompressor.m
Normal file
219
IOSBoilerplate/ASIDataCompressor.m
Normal file
@@ -0,0 +1,219 @@
|
||||
//
|
||||
// ASIDataCompressor.m
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 17/08/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ASIDataCompressor.h"
|
||||
#import "ASIHTTPRequest.h"
|
||||
|
||||
#define DATA_CHUNK_SIZE 262144 // Deal with gzipped data in 256KB chunks
|
||||
#define COMPRESSION_AMOUNT Z_DEFAULT_COMPRESSION
|
||||
|
||||
@interface ASIDataCompressor ()
|
||||
+ (NSError *)deflateErrorWithCode:(int)code;
|
||||
@end
|
||||
|
||||
@implementation ASIDataCompressor
|
||||
|
||||
+ (id)compressor
|
||||
{
|
||||
ASIDataCompressor *compressor = [[[self alloc] init] autorelease];
|
||||
[compressor setupStream];
|
||||
return compressor;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
if (streamReady) {
|
||||
[self closeStream];
|
||||
}
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (NSError *)setupStream
|
||||
{
|
||||
if (streamReady) {
|
||||
return nil;
|
||||
}
|
||||
// Setup the inflate stream
|
||||
zStream.zalloc = Z_NULL;
|
||||
zStream.zfree = Z_NULL;
|
||||
zStream.opaque = Z_NULL;
|
||||
zStream.avail_in = 0;
|
||||
zStream.next_in = 0;
|
||||
int status = deflateInit2(&zStream, COMPRESSION_AMOUNT, Z_DEFLATED, (15+16), 8, Z_DEFAULT_STRATEGY);
|
||||
if (status != Z_OK) {
|
||||
return [[self class] deflateErrorWithCode:status];
|
||||
}
|
||||
streamReady = YES;
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSError *)closeStream
|
||||
{
|
||||
if (!streamReady) {
|
||||
return nil;
|
||||
}
|
||||
// Close the deflate stream
|
||||
streamReady = NO;
|
||||
int status = deflateEnd(&zStream);
|
||||
if (status != Z_OK) {
|
||||
return [[self class] deflateErrorWithCode:status];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSData *)compressBytes:(Bytef *)bytes length:(NSUInteger)length error:(NSError **)err shouldFinish:(BOOL)shouldFinish
|
||||
{
|
||||
if (length == 0) return nil;
|
||||
|
||||
NSUInteger halfLength = length/2;
|
||||
|
||||
// We'll take a guess that the compressed data will fit in half the size of the original (ie the max to compress at once is half DATA_CHUNK_SIZE), if not, we'll increase it below
|
||||
NSMutableData *outputData = [NSMutableData dataWithLength:length/2];
|
||||
|
||||
int status;
|
||||
|
||||
zStream.next_in = bytes;
|
||||
zStream.avail_in = (unsigned int)length;
|
||||
zStream.avail_out = 0;
|
||||
|
||||
NSInteger bytesProcessedAlready = zStream.total_out;
|
||||
while (zStream.avail_out == 0) {
|
||||
|
||||
if (zStream.total_out-bytesProcessedAlready >= [outputData length]) {
|
||||
[outputData increaseLengthBy:halfLength];
|
||||
}
|
||||
|
||||
zStream.next_out = [outputData mutableBytes] + zStream.total_out-bytesProcessedAlready;
|
||||
zStream.avail_out = (unsigned int)([outputData length] - (zStream.total_out-bytesProcessedAlready));
|
||||
status = deflate(&zStream, shouldFinish ? Z_FINISH : Z_NO_FLUSH);
|
||||
|
||||
if (status == Z_STREAM_END) {
|
||||
break;
|
||||
} else if (status != Z_OK) {
|
||||
if (err) {
|
||||
*err = [[self class] deflateErrorWithCode:status];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
// Set real length
|
||||
[outputData setLength: zStream.total_out-bytesProcessedAlready];
|
||||
return outputData;
|
||||
}
|
||||
|
||||
|
||||
+ (NSData *)compressData:(NSData*)uncompressedData error:(NSError **)err
|
||||
{
|
||||
NSError *theError = nil;
|
||||
NSData *outputData = [[ASIDataCompressor compressor] compressBytes:(Bytef *)[uncompressedData bytes] length:[uncompressedData length] error:&theError shouldFinish:YES];
|
||||
if (theError) {
|
||||
if (err) {
|
||||
*err = theError;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
return outputData;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+ (BOOL)compressDataFromFile:(NSString *)sourcePath toFile:(NSString *)destinationPath error:(NSError **)err
|
||||
{
|
||||
NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease];
|
||||
|
||||
// Create an empty file at the destination path
|
||||
if (![fileManager createFileAtPath:destinationPath contents:[NSData data] attributes:nil]) {
|
||||
if (err) {
|
||||
*err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Compression of %@ failed because we were to create a file at %@",sourcePath,destinationPath],NSLocalizedDescriptionKey,nil]];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Ensure the source file exists
|
||||
if (![fileManager fileExistsAtPath:sourcePath]) {
|
||||
if (err) {
|
||||
*err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Compression of %@ failed the file does not exist",sourcePath],NSLocalizedDescriptionKey,nil]];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
UInt8 inputData[DATA_CHUNK_SIZE];
|
||||
NSData *outputData;
|
||||
NSInteger readLength;
|
||||
NSError *theError = nil;
|
||||
|
||||
ASIDataCompressor *compressor = [ASIDataCompressor compressor];
|
||||
|
||||
NSInputStream *inputStream = [NSInputStream inputStreamWithFileAtPath:sourcePath];
|
||||
[inputStream open];
|
||||
NSOutputStream *outputStream = [NSOutputStream outputStreamToFileAtPath:destinationPath append:NO];
|
||||
[outputStream open];
|
||||
|
||||
while ([compressor streamReady]) {
|
||||
|
||||
// Read some data from the file
|
||||
readLength = [inputStream read:inputData maxLength:DATA_CHUNK_SIZE];
|
||||
|
||||
// Make sure nothing went wrong
|
||||
if ([inputStream streamStatus] == NSStreamEventErrorOccurred) {
|
||||
if (err) {
|
||||
*err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Compression of %@ failed because we were unable to read from the source data file",sourcePath],NSLocalizedDescriptionKey,[inputStream streamError],NSUnderlyingErrorKey,nil]];
|
||||
}
|
||||
[compressor closeStream];
|
||||
return NO;
|
||||
}
|
||||
// Have we reached the end of the input data?
|
||||
if (!readLength) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Attempt to deflate the chunk of data
|
||||
outputData = [compressor compressBytes:inputData length:readLength error:&theError shouldFinish:readLength < DATA_CHUNK_SIZE ];
|
||||
if (theError) {
|
||||
if (err) {
|
||||
*err = theError;
|
||||
}
|
||||
[compressor closeStream];
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Write the deflated data out to the destination file
|
||||
[outputStream write:[outputData bytes] maxLength:[outputData length]];
|
||||
|
||||
// Make sure nothing went wrong
|
||||
if ([inputStream streamStatus] == NSStreamEventErrorOccurred) {
|
||||
if (err) {
|
||||
*err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Compression of %@ failed because we were unable to write to the destination data file at &@",sourcePath,destinationPath],NSLocalizedDescriptionKey,[outputStream streamError],NSUnderlyingErrorKey,nil]];
|
||||
}
|
||||
[compressor closeStream];
|
||||
return NO;
|
||||
}
|
||||
|
||||
}
|
||||
[inputStream close];
|
||||
[outputStream close];
|
||||
|
||||
NSError *error = [compressor closeStream];
|
||||
if (error) {
|
||||
if (err) {
|
||||
*err = error;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (NSError *)deflateErrorWithCode:(int)code
|
||||
{
|
||||
return [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Compression of data failed with code %hi",code],NSLocalizedDescriptionKey,nil]];
|
||||
}
|
||||
|
||||
@synthesize streamReady;
|
||||
@end
|
||||
41
IOSBoilerplate/ASIDataDecompressor.h
Normal file
41
IOSBoilerplate/ASIDataDecompressor.h
Normal file
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// ASIDataDecompressor.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 17/08/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
// This is a helper class used by ASIHTTPRequest to handle inflating (decompressing) data in memory and on disk
|
||||
// You may also find it helpful if you need to inflate data and files yourself - see the class methods below
|
||||
// Most of the zlib stuff is based on the sample code by Mark Adler available at http://zlib.net
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <zlib.h>
|
||||
|
||||
@interface ASIDataDecompressor : NSObject {
|
||||
BOOL streamReady;
|
||||
z_stream zStream;
|
||||
}
|
||||
|
||||
// Convenience constructor will call setupStream for you
|
||||
+ (id)decompressor;
|
||||
|
||||
// Uncompress the passed chunk of data
|
||||
- (NSData *)uncompressBytes:(Bytef *)bytes length:(NSUInteger)length error:(NSError **)err;
|
||||
|
||||
// Convenience method - pass it some deflated data, and you'll get inflated data back
|
||||
+ (NSData *)uncompressData:(NSData*)compressedData error:(NSError **)err;
|
||||
|
||||
// Convenience method - pass it a file containing deflated data in sourcePath, and it will write inflated data to destinationPath
|
||||
+ (BOOL)uncompressDataFromFile:(NSString *)sourcePath toFile:(NSString *)destinationPath error:(NSError **)err;
|
||||
|
||||
// Sets up zlib to handle the inflating. You only need to call this yourself if you aren't using the convenience constructor 'decompressor'
|
||||
- (NSError *)setupStream;
|
||||
|
||||
// Tells zlib to clean up. You need to call this if you need to cancel inflating part way through
|
||||
// If inflating finishes or fails, this method will be called automatically
|
||||
- (NSError *)closeStream;
|
||||
|
||||
@property (assign, readonly) BOOL streamReady;
|
||||
@end
|
||||
218
IOSBoilerplate/ASIDataDecompressor.m
Normal file
218
IOSBoilerplate/ASIDataDecompressor.m
Normal file
@@ -0,0 +1,218 @@
|
||||
//
|
||||
// ASIDataDecompressor.m
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 17/08/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ASIDataDecompressor.h"
|
||||
#import "ASIHTTPRequest.h"
|
||||
|
||||
#define DATA_CHUNK_SIZE 262144 // Deal with gzipped data in 256KB chunks
|
||||
|
||||
@interface ASIDataDecompressor ()
|
||||
+ (NSError *)inflateErrorWithCode:(int)code;
|
||||
@end;
|
||||
|
||||
@implementation ASIDataDecompressor
|
||||
|
||||
+ (id)decompressor
|
||||
{
|
||||
ASIDataDecompressor *decompressor = [[[self alloc] init] autorelease];
|
||||
[decompressor setupStream];
|
||||
return decompressor;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
if (streamReady) {
|
||||
[self closeStream];
|
||||
}
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (NSError *)setupStream
|
||||
{
|
||||
if (streamReady) {
|
||||
return nil;
|
||||
}
|
||||
// Setup the inflate stream
|
||||
zStream.zalloc = Z_NULL;
|
||||
zStream.zfree = Z_NULL;
|
||||
zStream.opaque = Z_NULL;
|
||||
zStream.avail_in = 0;
|
||||
zStream.next_in = 0;
|
||||
int status = inflateInit2(&zStream, (15+32));
|
||||
if (status != Z_OK) {
|
||||
return [[self class] inflateErrorWithCode:status];
|
||||
}
|
||||
streamReady = YES;
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSError *)closeStream
|
||||
{
|
||||
if (!streamReady) {
|
||||
return nil;
|
||||
}
|
||||
// Close the inflate stream
|
||||
streamReady = NO;
|
||||
int status = inflateEnd(&zStream);
|
||||
if (status != Z_OK) {
|
||||
return [[self class] inflateErrorWithCode:status];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSData *)uncompressBytes:(Bytef *)bytes length:(NSUInteger)length error:(NSError **)err
|
||||
{
|
||||
if (length == 0) return nil;
|
||||
|
||||
NSUInteger halfLength = length/2;
|
||||
NSMutableData *outputData = [NSMutableData dataWithLength:length+halfLength];
|
||||
|
||||
int status;
|
||||
|
||||
zStream.next_in = bytes;
|
||||
zStream.avail_in = (unsigned int)length;
|
||||
zStream.avail_out = 0;
|
||||
|
||||
NSInteger bytesProcessedAlready = zStream.total_out;
|
||||
while (zStream.avail_in != 0) {
|
||||
|
||||
if (zStream.total_out-bytesProcessedAlready >= [outputData length]) {
|
||||
[outputData increaseLengthBy:halfLength];
|
||||
}
|
||||
|
||||
zStream.next_out = [outputData mutableBytes] + zStream.total_out-bytesProcessedAlready;
|
||||
zStream.avail_out = (unsigned int)([outputData length] - (zStream.total_out-bytesProcessedAlready));
|
||||
|
||||
status = inflate(&zStream, Z_NO_FLUSH);
|
||||
|
||||
if (status == Z_STREAM_END) {
|
||||
break;
|
||||
} else if (status != Z_OK) {
|
||||
if (err) {
|
||||
*err = [[self class] inflateErrorWithCode:status];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
// Set real length
|
||||
[outputData setLength: zStream.total_out-bytesProcessedAlready];
|
||||
return outputData;
|
||||
}
|
||||
|
||||
|
||||
+ (NSData *)uncompressData:(NSData*)compressedData error:(NSError **)err
|
||||
{
|
||||
NSError *theError = nil;
|
||||
NSData *outputData = [[ASIDataDecompressor decompressor] uncompressBytes:(Bytef *)[compressedData bytes] length:[compressedData length] error:&theError];
|
||||
if (theError) {
|
||||
if (err) {
|
||||
*err = theError;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
return outputData;
|
||||
}
|
||||
|
||||
+ (BOOL)uncompressDataFromFile:(NSString *)sourcePath toFile:(NSString *)destinationPath error:(NSError **)err
|
||||
{
|
||||
NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease];
|
||||
|
||||
// Create an empty file at the destination path
|
||||
if (![fileManager createFileAtPath:destinationPath contents:[NSData data] attributes:nil]) {
|
||||
if (err) {
|
||||
*err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Decompression of %@ failed because we were to create a file at %@",sourcePath,destinationPath],NSLocalizedDescriptionKey,nil]];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Ensure the source file exists
|
||||
if (![fileManager fileExistsAtPath:sourcePath]) {
|
||||
if (err) {
|
||||
*err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Decompression of %@ failed the file does not exist",sourcePath],NSLocalizedDescriptionKey,nil]];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
UInt8 inputData[DATA_CHUNK_SIZE];
|
||||
NSData *outputData;
|
||||
NSInteger readLength;
|
||||
NSError *theError = nil;
|
||||
|
||||
|
||||
ASIDataDecompressor *decompressor = [ASIDataDecompressor decompressor];
|
||||
|
||||
NSInputStream *inputStream = [NSInputStream inputStreamWithFileAtPath:sourcePath];
|
||||
[inputStream open];
|
||||
NSOutputStream *outputStream = [NSOutputStream outputStreamToFileAtPath:destinationPath append:NO];
|
||||
[outputStream open];
|
||||
|
||||
while ([decompressor streamReady]) {
|
||||
|
||||
// Read some data from the file
|
||||
readLength = [inputStream read:inputData maxLength:DATA_CHUNK_SIZE];
|
||||
|
||||
// Make sure nothing went wrong
|
||||
if ([inputStream streamStatus] == NSStreamEventErrorOccurred) {
|
||||
if (err) {
|
||||
*err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Decompression of %@ failed because we were unable to read from the source data file",sourcePath],NSLocalizedDescriptionKey,[inputStream streamError],NSUnderlyingErrorKey,nil]];
|
||||
}
|
||||
[decompressor closeStream];
|
||||
return NO;
|
||||
}
|
||||
// Have we reached the end of the input data?
|
||||
if (!readLength) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Attempt to inflate the chunk of data
|
||||
outputData = [decompressor uncompressBytes:inputData length:readLength error:&theError];
|
||||
if (theError) {
|
||||
if (err) {
|
||||
*err = theError;
|
||||
}
|
||||
[decompressor closeStream];
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Write the inflated data out to the destination file
|
||||
[outputStream write:[outputData bytes] maxLength:[outputData length]];
|
||||
|
||||
// Make sure nothing went wrong
|
||||
if ([inputStream streamStatus] == NSStreamEventErrorOccurred) {
|
||||
if (err) {
|
||||
*err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Decompression of %@ failed because we were unable to write to the destination data file at &@",sourcePath,destinationPath],NSLocalizedDescriptionKey,[outputStream streamError],NSUnderlyingErrorKey,nil]];
|
||||
}
|
||||
[decompressor closeStream];
|
||||
return NO;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[inputStream close];
|
||||
[outputStream close];
|
||||
|
||||
NSError *error = [decompressor closeStream];
|
||||
if (error) {
|
||||
if (err) {
|
||||
*err = error;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
+ (NSError *)inflateErrorWithCode:(int)code
|
||||
{
|
||||
return [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Decompression of data failed with code %hi",code],NSLocalizedDescriptionKey,nil]];
|
||||
}
|
||||
|
||||
@synthesize streamReady;
|
||||
@end
|
||||
46
IOSBoilerplate/ASIDownloadCache.h
Normal file
46
IOSBoilerplate/ASIDownloadCache.h
Normal file
@@ -0,0 +1,46 @@
|
||||
//
|
||||
// ASIDownloadCache.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 01/05/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "ASICacheDelegate.h"
|
||||
|
||||
@interface ASIDownloadCache : NSObject <ASICacheDelegate> {
|
||||
|
||||
// The default cache policy for this cache
|
||||
// Requests that store data in the cache will use this cache policy if their cache policy is set to ASIUseDefaultCachePolicy
|
||||
// Defaults to ASIAskServerIfModifiedWhenStaleCachePolicy
|
||||
ASICachePolicy defaultCachePolicy;
|
||||
|
||||
// The directory in which cached data will be stored
|
||||
// Defaults to a directory called 'ASIHTTPRequestCache' in the temporary directory
|
||||
NSString *storagePath;
|
||||
|
||||
// Mediates access to the cache
|
||||
NSRecursiveLock *accessLock;
|
||||
|
||||
// When YES, the cache will look for cache-control / pragma: no-cache headers, and won't reuse store responses if it finds them
|
||||
BOOL shouldRespectCacheControlHeaders;
|
||||
}
|
||||
|
||||
// Returns a static instance of an ASIDownloadCache
|
||||
// In most circumstances, it will make sense to use this as a global cache, rather than creating your own cache
|
||||
// To make ASIHTTPRequests use it automatically, use [ASIHTTPRequest setDefaultCache:[ASIDownloadCache sharedCache]];
|
||||
+ (id)sharedCache;
|
||||
|
||||
// A helper function that determines if the server has requested data should not be cached by looking at the request's response headers
|
||||
+ (BOOL)serverAllowsResponseCachingForRequest:(ASIHTTPRequest *)request;
|
||||
|
||||
// A list of file extensions that we know won't be readable by a webview when accessed locally
|
||||
// If we're asking for a path to cache a particular url and it has one of these extensions, we change it to '.html'
|
||||
+ (NSArray *)fileExtensionsToHandleAsHTML;
|
||||
|
||||
@property (assign, nonatomic) ASICachePolicy defaultCachePolicy;
|
||||
@property (retain, nonatomic) NSString *storagePath;
|
||||
@property (retain) NSRecursiveLock *accessLock;
|
||||
@property (assign) BOOL shouldRespectCacheControlHeaders;
|
||||
@end
|
||||
514
IOSBoilerplate/ASIDownloadCache.m
Normal file
514
IOSBoilerplate/ASIDownloadCache.m
Normal file
@@ -0,0 +1,514 @@
|
||||
//
|
||||
// ASIDownloadCache.m
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 01/05/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ASIDownloadCache.h"
|
||||
#import "ASIHTTPRequest.h"
|
||||
#import <CommonCrypto/CommonHMAC.h>
|
||||
|
||||
static ASIDownloadCache *sharedCache = nil;
|
||||
|
||||
static NSString *sessionCacheFolder = @"SessionStore";
|
||||
static NSString *permanentCacheFolder = @"PermanentStore";
|
||||
static NSArray *fileExtensionsToHandleAsHTML = nil;
|
||||
|
||||
@interface ASIDownloadCache ()
|
||||
+ (NSString *)keyForURL:(NSURL *)url;
|
||||
- (NSString *)pathToFile:(NSString *)file;
|
||||
@end
|
||||
|
||||
@implementation ASIDownloadCache
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self == [ASIDownloadCache class]) {
|
||||
// Obviously this is not an exhaustive list, but hopefully these are the most commonly used and this will 'just work' for the widest range of people
|
||||
// I imagine many web developers probably use url rewriting anyway
|
||||
fileExtensionsToHandleAsHTML = [[NSArray alloc] initWithObjects:@"asp",@"aspx",@"jsp",@"php",@"rb",@"py",@"pl",@"cgi", nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
[self setShouldRespectCacheControlHeaders:YES];
|
||||
[self setDefaultCachePolicy:ASIUseDefaultCachePolicy];
|
||||
[self setAccessLock:[[[NSRecursiveLock alloc] init] autorelease]];
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (id)sharedCache
|
||||
{
|
||||
if (!sharedCache) {
|
||||
@synchronized(self) {
|
||||
if (!sharedCache) {
|
||||
sharedCache = [[self alloc] init];
|
||||
[sharedCache setStoragePath:[[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:@"ASIHTTPRequestCache"]];
|
||||
}
|
||||
}
|
||||
}
|
||||
return sharedCache;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[storagePath release];
|
||||
[accessLock release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (NSString *)storagePath
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
NSString *p = [[storagePath retain] autorelease];
|
||||
[[self accessLock] unlock];
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
- (void)setStoragePath:(NSString *)path
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
[self clearCachedResponsesForStoragePolicy:ASICacheForSessionDurationCacheStoragePolicy];
|
||||
[storagePath release];
|
||||
storagePath = [path retain];
|
||||
|
||||
NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease];
|
||||
|
||||
BOOL isDirectory = NO;
|
||||
NSArray *directories = [NSArray arrayWithObjects:path,[path stringByAppendingPathComponent:sessionCacheFolder],[path stringByAppendingPathComponent:permanentCacheFolder],nil];
|
||||
for (NSString *directory in directories) {
|
||||
BOOL exists = [fileManager fileExistsAtPath:directory isDirectory:&isDirectory];
|
||||
if (exists && !isDirectory) {
|
||||
[[self accessLock] unlock];
|
||||
[NSException raise:@"FileExistsAtCachePath" format:@"Cannot create a directory for the cache at '%@', because a file already exists",directory];
|
||||
} else if (!exists) {
|
||||
[fileManager createDirectoryAtPath:directory withIntermediateDirectories:NO attributes:nil error:nil];
|
||||
if (![fileManager fileExistsAtPath:directory]) {
|
||||
[[self accessLock] unlock];
|
||||
[NSException raise:@"FailedToCreateCacheDirectory" format:@"Failed to create a directory for the cache at '%@'",directory];
|
||||
}
|
||||
}
|
||||
}
|
||||
[self clearCachedResponsesForStoragePolicy:ASICacheForSessionDurationCacheStoragePolicy];
|
||||
[[self accessLock] unlock];
|
||||
}
|
||||
|
||||
- (void)updateExpiryForRequest:(ASIHTTPRequest *)request maxAge:(NSTimeInterval)maxAge
|
||||
{
|
||||
NSString *headerPath = [self pathToStoreCachedResponseHeadersForRequest:request];
|
||||
NSMutableDictionary *cachedHeaders = [NSMutableDictionary dictionaryWithContentsOfFile:headerPath];
|
||||
if (!cachedHeaders) {
|
||||
return;
|
||||
}
|
||||
NSDate *expires = [self expiryDateForRequest:request maxAge:maxAge];
|
||||
if (!expires) {
|
||||
return;
|
||||
}
|
||||
[cachedHeaders setObject:[NSNumber numberWithDouble:[expires timeIntervalSince1970]] forKey:@"X-ASIHTTPRequest-Expires"];
|
||||
[cachedHeaders writeToFile:headerPath atomically:NO];
|
||||
}
|
||||
|
||||
- (NSDate *)expiryDateForRequest:(ASIHTTPRequest *)request maxAge:(NSTimeInterval)maxAge
|
||||
{
|
||||
return [ASIHTTPRequest expiryDateForRequest:request maxAge:maxAge];
|
||||
}
|
||||
|
||||
- (void)storeResponseForRequest:(ASIHTTPRequest *)request maxAge:(NSTimeInterval)maxAge
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
|
||||
if ([request error] || ![request responseHeaders] || ([request cachePolicy] & ASIDoNotWriteToCacheCachePolicy)) {
|
||||
[[self accessLock] unlock];
|
||||
return;
|
||||
}
|
||||
|
||||
// We only cache 200/OK or redirect reponses (redirect responses are cached so the cache works better with no internet connection)
|
||||
int responseCode = [request responseStatusCode];
|
||||
if (responseCode != 200 && responseCode != 301 && responseCode != 302 && responseCode != 303 && responseCode != 307) {
|
||||
[[self accessLock] unlock];
|
||||
return;
|
||||
}
|
||||
|
||||
if ([self shouldRespectCacheControlHeaders] && ![[self class] serverAllowsResponseCachingForRequest:request]) {
|
||||
[[self accessLock] unlock];
|
||||
return;
|
||||
}
|
||||
|
||||
NSString *headerPath = [self pathToStoreCachedResponseHeadersForRequest:request];
|
||||
NSString *dataPath = [self pathToStoreCachedResponseDataForRequest:request];
|
||||
|
||||
NSMutableDictionary *responseHeaders = [NSMutableDictionary dictionaryWithDictionary:[request responseHeaders]];
|
||||
if ([request isResponseCompressed]) {
|
||||
[responseHeaders removeObjectForKey:@"Content-Encoding"];
|
||||
}
|
||||
|
||||
// Create a special 'X-ASIHTTPRequest-Expires' header
|
||||
// This is what we use for deciding if cached data is current, rather than parsing the expires / max-age headers individually each time
|
||||
// We store this as a timestamp to make reading it easier as NSDateFormatter is quite expensive
|
||||
|
||||
NSDate *expires = [self expiryDateForRequest:request maxAge:maxAge];
|
||||
if (expires) {
|
||||
[responseHeaders setObject:[NSNumber numberWithDouble:[expires timeIntervalSince1970]] forKey:@"X-ASIHTTPRequest-Expires"];
|
||||
}
|
||||
|
||||
// Store the response code in a custom header so we can reuse it later
|
||||
|
||||
// We'll change 304/Not Modified to 200/OK because this is likely to be us updating the cached headers with a conditional GET
|
||||
int statusCode = [request responseStatusCode];
|
||||
if (statusCode == 304) {
|
||||
statusCode = 200;
|
||||
}
|
||||
[responseHeaders setObject:[NSNumber numberWithInt:statusCode] forKey:@"X-ASIHTTPRequest-Response-Status-Code"];
|
||||
|
||||
[responseHeaders writeToFile:headerPath atomically:NO];
|
||||
|
||||
if ([request responseData]) {
|
||||
[[request responseData] writeToFile:dataPath atomically:NO];
|
||||
} else if ([request downloadDestinationPath] && ![[request downloadDestinationPath] isEqualToString:dataPath]) {
|
||||
NSError *error = nil;
|
||||
NSFileManager* manager = [[NSFileManager alloc] init];
|
||||
if ([manager fileExistsAtPath:dataPath]) {
|
||||
[manager removeItemAtPath:dataPath error:&error];
|
||||
}
|
||||
[manager copyItemAtPath:[request downloadDestinationPath] toPath:dataPath error:&error];
|
||||
[manager release];
|
||||
}
|
||||
[[self accessLock] unlock];
|
||||
}
|
||||
|
||||
- (NSDictionary *)cachedResponseHeadersForURL:(NSURL *)url
|
||||
{
|
||||
NSString *path = [self pathToCachedResponseHeadersForURL:url];
|
||||
if (path) {
|
||||
return [NSDictionary dictionaryWithContentsOfFile:path];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSData *)cachedResponseDataForURL:(NSURL *)url
|
||||
{
|
||||
NSString *path = [self pathToCachedResponseDataForURL:url];
|
||||
if (path) {
|
||||
return [NSData dataWithContentsOfFile:path];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSString *)pathToCachedResponseDataForURL:(NSURL *)url
|
||||
{
|
||||
// Grab the file extension, if there is one. We do this so we can save the cached response with the same file extension - this is important if you want to display locally cached data in a web view
|
||||
NSString *extension = [[url path] pathExtension];
|
||||
|
||||
// If the url doesn't have an extension, we'll add one so a webview can read it when locally cached
|
||||
// If the url has the extension of a common web scripting language, we'll change the extension on the cached path to html for the same reason
|
||||
if (![extension length] || [[[self class] fileExtensionsToHandleAsHTML] containsObject:[extension lowercaseString]]) {
|
||||
extension = @"html";
|
||||
}
|
||||
return [self pathToFile:[[[self class] keyForURL:url] stringByAppendingPathExtension:extension]];
|
||||
}
|
||||
|
||||
+ (NSArray *)fileExtensionsToHandleAsHTML
|
||||
{
|
||||
return fileExtensionsToHandleAsHTML;
|
||||
}
|
||||
|
||||
|
||||
- (NSString *)pathToCachedResponseHeadersForURL:(NSURL *)url
|
||||
{
|
||||
return [self pathToFile:[[[self class] keyForURL:url] stringByAppendingPathExtension:@"cachedheaders"]];
|
||||
}
|
||||
|
||||
- (NSString *)pathToFile:(NSString *)file
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
if (![self storagePath]) {
|
||||
[[self accessLock] unlock];
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease];
|
||||
|
||||
// Look in the session store
|
||||
NSString *dataPath = [[[self storagePath] stringByAppendingPathComponent:sessionCacheFolder] stringByAppendingPathComponent:file];
|
||||
if ([fileManager fileExistsAtPath:dataPath]) {
|
||||
[[self accessLock] unlock];
|
||||
return dataPath;
|
||||
}
|
||||
// Look in the permanent store
|
||||
dataPath = [[[self storagePath] stringByAppendingPathComponent:permanentCacheFolder] stringByAppendingPathComponent:file];
|
||||
if ([fileManager fileExistsAtPath:dataPath]) {
|
||||
[[self accessLock] unlock];
|
||||
return dataPath;
|
||||
}
|
||||
[[self accessLock] unlock];
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
- (NSString *)pathToStoreCachedResponseDataForRequest:(ASIHTTPRequest *)request
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
if (![self storagePath]) {
|
||||
[[self accessLock] unlock];
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSString *path = [[self storagePath] stringByAppendingPathComponent:([request cacheStoragePolicy] == ASICacheForSessionDurationCacheStoragePolicy ? sessionCacheFolder : permanentCacheFolder)];
|
||||
|
||||
// Grab the file extension, if there is one. We do this so we can save the cached response with the same file extension - this is important if you want to display locally cached data in a web view
|
||||
NSString *extension = [[[request url] path] pathExtension];
|
||||
|
||||
// If the url doesn't have an extension, we'll add one so a webview can read it when locally cached
|
||||
// If the url has the extension of a common web scripting language, we'll change the extension on the cached path to html for the same reason
|
||||
if (![extension length] || [[[self class] fileExtensionsToHandleAsHTML] containsObject:[extension lowercaseString]]) {
|
||||
extension = @"html";
|
||||
}
|
||||
path = [path stringByAppendingPathComponent:[[[self class] keyForURL:[request url]] stringByAppendingPathExtension:extension]];
|
||||
[[self accessLock] unlock];
|
||||
return path;
|
||||
}
|
||||
|
||||
- (NSString *)pathToStoreCachedResponseHeadersForRequest:(ASIHTTPRequest *)request
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
if (![self storagePath]) {
|
||||
[[self accessLock] unlock];
|
||||
return nil;
|
||||
}
|
||||
NSString *path = [[self storagePath] stringByAppendingPathComponent:([request cacheStoragePolicy] == ASICacheForSessionDurationCacheStoragePolicy ? sessionCacheFolder : permanentCacheFolder)];
|
||||
path = [path stringByAppendingPathComponent:[[[self class] keyForURL:[request url]] stringByAppendingPathExtension:@"cachedheaders"]];
|
||||
[[self accessLock] unlock];
|
||||
return path;
|
||||
}
|
||||
|
||||
- (void)removeCachedDataForURL:(NSURL *)url
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
if (![self storagePath]) {
|
||||
[[self accessLock] unlock];
|
||||
return;
|
||||
}
|
||||
NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease];
|
||||
|
||||
NSString *path = [self pathToCachedResponseHeadersForURL:url];
|
||||
if (path) {
|
||||
[fileManager removeItemAtPath:path error:NULL];
|
||||
}
|
||||
|
||||
path = [self pathToCachedResponseDataForURL:url];
|
||||
if (path) {
|
||||
[fileManager removeItemAtPath:path error:NULL];
|
||||
}
|
||||
[[self accessLock] unlock];
|
||||
}
|
||||
|
||||
- (void)removeCachedDataForRequest:(ASIHTTPRequest *)request
|
||||
{
|
||||
[self removeCachedDataForURL:[request url]];
|
||||
}
|
||||
|
||||
- (BOOL)isCachedDataCurrentForRequest:(ASIHTTPRequest *)request
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
if (![self storagePath]) {
|
||||
[[self accessLock] unlock];
|
||||
return NO;
|
||||
}
|
||||
NSDictionary *cachedHeaders = [self cachedResponseHeadersForURL:[request url]];
|
||||
if (!cachedHeaders) {
|
||||
[[self accessLock] unlock];
|
||||
return NO;
|
||||
}
|
||||
NSString *dataPath = [self pathToCachedResponseDataForURL:[request url]];
|
||||
if (!dataPath) {
|
||||
[[self accessLock] unlock];
|
||||
return NO;
|
||||
}
|
||||
|
||||
// New content is not different
|
||||
if ([request responseStatusCode] == 304) {
|
||||
[[self accessLock] unlock];
|
||||
return YES;
|
||||
}
|
||||
|
||||
// If we already have response headers for this request, check to see if the new content is different
|
||||
// We check [request complete] so that we don't end up comparing response headers from a redirection with these
|
||||
if ([request responseHeaders] && [request complete]) {
|
||||
|
||||
// If the Etag or Last-Modified date are different from the one we have, we'll have to fetch this resource again
|
||||
NSArray *headersToCompare = [NSArray arrayWithObjects:@"Etag",@"Last-Modified",nil];
|
||||
for (NSString *header in headersToCompare) {
|
||||
if (![[[request responseHeaders] objectForKey:header] isEqualToString:[cachedHeaders objectForKey:header]]) {
|
||||
[[self accessLock] unlock];
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ([self shouldRespectCacheControlHeaders]) {
|
||||
|
||||
// Look for X-ASIHTTPRequest-Expires header to see if the content is out of date
|
||||
NSNumber *expires = [cachedHeaders objectForKey:@"X-ASIHTTPRequest-Expires"];
|
||||
if (expires) {
|
||||
if ([[NSDate dateWithTimeIntervalSince1970:[expires doubleValue]] timeIntervalSinceNow] >= 0) {
|
||||
[[self accessLock] unlock];
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
// No explicit expiration time sent by the server
|
||||
[[self accessLock] unlock];
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
[[self accessLock] unlock];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (ASICachePolicy)defaultCachePolicy
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
ASICachePolicy cp = defaultCachePolicy;
|
||||
[[self accessLock] unlock];
|
||||
return cp;
|
||||
}
|
||||
|
||||
|
||||
- (void)setDefaultCachePolicy:(ASICachePolicy)cachePolicy
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
if (!cachePolicy) {
|
||||
defaultCachePolicy = ASIAskServerIfModifiedWhenStaleCachePolicy;
|
||||
} else {
|
||||
defaultCachePolicy = cachePolicy;
|
||||
}
|
||||
[[self accessLock] unlock];
|
||||
}
|
||||
|
||||
- (void)clearCachedResponsesForStoragePolicy:(ASICacheStoragePolicy)storagePolicy
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
if (![self storagePath]) {
|
||||
[[self accessLock] unlock];
|
||||
return;
|
||||
}
|
||||
NSString *path = [[self storagePath] stringByAppendingPathComponent:(storagePolicy == ASICacheForSessionDurationCacheStoragePolicy ? sessionCacheFolder : permanentCacheFolder)];
|
||||
|
||||
NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease];
|
||||
|
||||
BOOL isDirectory = NO;
|
||||
BOOL exists = [fileManager fileExistsAtPath:path isDirectory:&isDirectory];
|
||||
if (!exists || !isDirectory) {
|
||||
[[self accessLock] unlock];
|
||||
return;
|
||||
}
|
||||
NSError *error = nil;
|
||||
NSArray *cacheFiles = [fileManager contentsOfDirectoryAtPath:path error:&error];
|
||||
if (error) {
|
||||
[[self accessLock] unlock];
|
||||
[NSException raise:@"FailedToTraverseCacheDirectory" format:@"Listing cache directory failed at path '%@'",path];
|
||||
}
|
||||
for (NSString *file in cacheFiles) {
|
||||
[fileManager removeItemAtPath:[path stringByAppendingPathComponent:file] error:&error];
|
||||
if (error) {
|
||||
[[self accessLock] unlock];
|
||||
[NSException raise:@"FailedToRemoveCacheFile" format:@"Failed to remove cached data at path '%@'",path];
|
||||
}
|
||||
}
|
||||
[[self accessLock] unlock];
|
||||
}
|
||||
|
||||
+ (BOOL)serverAllowsResponseCachingForRequest:(ASIHTTPRequest *)request
|
||||
{
|
||||
NSString *cacheControl = [[[request responseHeaders] objectForKey:@"Cache-Control"] lowercaseString];
|
||||
if (cacheControl) {
|
||||
if ([cacheControl isEqualToString:@"no-cache"] || [cacheControl isEqualToString:@"no-store"]) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
NSString *pragma = [[[request responseHeaders] objectForKey:@"Pragma"] lowercaseString];
|
||||
if (pragma) {
|
||||
if ([pragma isEqualToString:@"no-cache"]) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (NSString *)keyForURL:(NSURL *)url
|
||||
{
|
||||
NSString *urlString = [url absoluteString];
|
||||
if ([urlString length] == 0) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Strip trailing slashes so http://allseeing-i.com/ASIHTTPRequest/ is cached the same as http://allseeing-i.com/ASIHTTPRequest
|
||||
if ([[urlString substringFromIndex:[urlString length]-1] isEqualToString:@"/"]) {
|
||||
urlString = [urlString substringToIndex:[urlString length]-1];
|
||||
}
|
||||
|
||||
// Borrowed from: http://stackoverflow.com/questions/652300/using-md5-hash-on-a-string-in-cocoa
|
||||
const char *cStr = [urlString UTF8String];
|
||||
unsigned char result[16];
|
||||
CC_MD5(cStr, (CC_LONG)strlen(cStr), result);
|
||||
return [NSString stringWithFormat:@"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",result[0], result[1], result[2], result[3], result[4], result[5], result[6], result[7],result[8], result[9], result[10], result[11],result[12], result[13], result[14], result[15]];
|
||||
}
|
||||
|
||||
- (BOOL)canUseCachedDataForRequest:(ASIHTTPRequest *)request
|
||||
{
|
||||
// Ensure the request is allowed to read from the cache
|
||||
if ([request cachePolicy] & ASIDoNotReadFromCacheCachePolicy) {
|
||||
return NO;
|
||||
|
||||
// If we don't want to load the request whatever happens, always pretend we have cached data even if we don't
|
||||
} else if ([request cachePolicy] & ASIDontLoadCachePolicy) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
NSDictionary *headers = [self cachedResponseHeadersForURL:[request url]];
|
||||
if (!headers) {
|
||||
return NO;
|
||||
}
|
||||
NSString *dataPath = [self pathToCachedResponseDataForURL:[request url]];
|
||||
if (!dataPath) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
// If we get here, we have cached data
|
||||
|
||||
// If we have cached data, we can use it
|
||||
if ([request cachePolicy] & ASIOnlyLoadIfNotCachedCachePolicy) {
|
||||
return YES;
|
||||
|
||||
// If we want to fallback to the cache after an error
|
||||
} else if ([request complete] && [request cachePolicy] & ASIFallbackToCacheIfLoadFailsCachePolicy) {
|
||||
return YES;
|
||||
|
||||
// If we have cached data that is current, we can use it
|
||||
} else if ([request cachePolicy] & ASIAskServerIfModifiedWhenStaleCachePolicy) {
|
||||
if ([self isCachedDataCurrentForRequest:request]) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
// If we've got headers from a conditional GET and the cached data is still current, we can use it
|
||||
} else if ([request cachePolicy] & ASIAskServerIfModifiedCachePolicy) {
|
||||
if (![request responseHeaders]) {
|
||||
return NO;
|
||||
} else if ([self isCachedDataCurrentForRequest:request]) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
@synthesize storagePath;
|
||||
@synthesize defaultCachePolicy;
|
||||
@synthesize accessLock;
|
||||
@synthesize shouldRespectCacheControlHeaders;
|
||||
@end
|
||||
76
IOSBoilerplate/ASIFormDataRequest.h
Normal file
76
IOSBoilerplate/ASIFormDataRequest.h
Normal file
@@ -0,0 +1,76 @@
|
||||
//
|
||||
// ASIFormDataRequest.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 07/11/2008.
|
||||
// Copyright 2008-2009 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "ASIHTTPRequest.h"
|
||||
#import "ASIHTTPRequestConfig.h"
|
||||
|
||||
typedef enum _ASIPostFormat {
|
||||
ASIMultipartFormDataPostFormat = 0,
|
||||
ASIURLEncodedPostFormat = 1
|
||||
|
||||
} ASIPostFormat;
|
||||
|
||||
@interface ASIFormDataRequest : ASIHTTPRequest <NSCopying> {
|
||||
|
||||
// Parameters that will be POSTed to the url
|
||||
NSMutableArray *postData;
|
||||
|
||||
// Files that will be POSTed to the url
|
||||
NSMutableArray *fileData;
|
||||
|
||||
ASIPostFormat postFormat;
|
||||
|
||||
NSStringEncoding stringEncoding;
|
||||
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
// Will store a string version of the request body that will be printed to the console when ASIHTTPREQUEST_DEBUG is set in GCC_PREPROCESSOR_DEFINITIONS
|
||||
NSString *debugBodyString;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#pragma mark utilities
|
||||
- (NSString*)encodeURL:(NSString *)string;
|
||||
|
||||
#pragma mark setup request
|
||||
|
||||
// Add a POST variable to the request
|
||||
- (void)addPostValue:(id <NSObject>)value forKey:(NSString *)key;
|
||||
|
||||
// Set a POST variable for this request, clearing any others with the same key
|
||||
- (void)setPostValue:(id <NSObject>)value forKey:(NSString *)key;
|
||||
|
||||
// Add the contents of a local file to the request
|
||||
- (void)addFile:(NSString *)filePath forKey:(NSString *)key;
|
||||
|
||||
// Same as above, but you can specify the content-type and file name
|
||||
- (void)addFile:(NSString *)filePath withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key;
|
||||
|
||||
// Add the contents of a local file to the request, clearing any others with the same key
|
||||
- (void)setFile:(NSString *)filePath forKey:(NSString *)key;
|
||||
|
||||
// Same as above, but you can specify the content-type and file name
|
||||
- (void)setFile:(NSString *)filePath withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key;
|
||||
|
||||
// Add the contents of an NSData object to the request
|
||||
- (void)addData:(NSData *)data forKey:(NSString *)key;
|
||||
|
||||
// Same as above, but you can specify the content-type and file name
|
||||
- (void)addData:(id)data withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key;
|
||||
|
||||
// Add the contents of an NSData object to the request, clearing any others with the same key
|
||||
- (void)setData:(NSData *)data forKey:(NSString *)key;
|
||||
|
||||
// Same as above, but you can specify the content-type and file name
|
||||
- (void)setData:(id)data withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key;
|
||||
|
||||
|
||||
@property (assign) ASIPostFormat postFormat;
|
||||
@property (assign) NSStringEncoding stringEncoding;
|
||||
@end
|
||||
361
IOSBoilerplate/ASIFormDataRequest.m
Normal file
361
IOSBoilerplate/ASIFormDataRequest.m
Normal file
@@ -0,0 +1,361 @@
|
||||
//
|
||||
// ASIFormDataRequest.m
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 07/11/2008.
|
||||
// Copyright 2008-2009 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ASIFormDataRequest.h"
|
||||
|
||||
|
||||
// Private stuff
|
||||
@interface ASIFormDataRequest ()
|
||||
- (void)buildMultipartFormDataPostBody;
|
||||
- (void)buildURLEncodedPostBody;
|
||||
- (void)appendPostString:(NSString *)string;
|
||||
|
||||
@property (retain) NSMutableArray *postData;
|
||||
@property (retain) NSMutableArray *fileData;
|
||||
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
- (void)addToDebugBody:(NSString *)string;
|
||||
@property (retain, nonatomic) NSString *debugBodyString;
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
@implementation ASIFormDataRequest
|
||||
|
||||
#pragma mark utilities
|
||||
- (NSString*)encodeURL:(NSString *)string
|
||||
{
|
||||
NSString *newString = [NSMakeCollectable(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)string, NULL, CFSTR(":/?#[]@!$ &'()*+,;=\"<>%{}|\\^~`"), CFStringConvertNSStringEncodingToEncoding([self stringEncoding]))) autorelease];
|
||||
if (newString) {
|
||||
return newString;
|
||||
}
|
||||
return @"";
|
||||
}
|
||||
|
||||
#pragma mark init / dealloc
|
||||
|
||||
+ (id)requestWithURL:(NSURL *)newURL
|
||||
{
|
||||
return [[[self alloc] initWithURL:newURL] autorelease];
|
||||
}
|
||||
|
||||
- (id)initWithURL:(NSURL *)newURL
|
||||
{
|
||||
self = [super initWithURL:newURL];
|
||||
[self setPostFormat:ASIURLEncodedPostFormat];
|
||||
[self setStringEncoding:NSUTF8StringEncoding];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
[debugBodyString release];
|
||||
#endif
|
||||
|
||||
[postData release];
|
||||
[fileData release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
#pragma mark setup request
|
||||
|
||||
- (void)addPostValue:(id <NSObject>)value forKey:(NSString *)key
|
||||
{
|
||||
if (!key) {
|
||||
return;
|
||||
}
|
||||
if (![self postData]) {
|
||||
[self setPostData:[NSMutableArray array]];
|
||||
}
|
||||
NSMutableDictionary *keyValuePair = [NSMutableDictionary dictionaryWithCapacity:2];
|
||||
[keyValuePair setValue:key forKey:@"key"];
|
||||
[keyValuePair setValue:[value description] forKey:@"value"];
|
||||
[[self postData] addObject:keyValuePair];
|
||||
}
|
||||
|
||||
- (void)setPostValue:(id <NSObject>)value forKey:(NSString *)key
|
||||
{
|
||||
// Remove any existing value
|
||||
NSUInteger i;
|
||||
for (i=0; i<[[self postData] count]; i++) {
|
||||
NSDictionary *val = [[self postData] objectAtIndex:i];
|
||||
if ([[val objectForKey:@"key"] isEqualToString:key]) {
|
||||
[[self postData] removeObjectAtIndex:i];
|
||||
i--;
|
||||
}
|
||||
}
|
||||
[self addPostValue:value forKey:key];
|
||||
}
|
||||
|
||||
|
||||
- (void)addFile:(NSString *)filePath forKey:(NSString *)key
|
||||
{
|
||||
[self addFile:filePath withFileName:nil andContentType:nil forKey:key];
|
||||
}
|
||||
|
||||
- (void)addFile:(NSString *)filePath withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key
|
||||
{
|
||||
BOOL isDirectory = NO;
|
||||
BOOL fileExists = [[[[NSFileManager alloc] init] autorelease] fileExistsAtPath:filePath isDirectory:&isDirectory];
|
||||
if (!fileExists || isDirectory) {
|
||||
[self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIInternalErrorWhileBuildingRequestType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"No file exists at %@",filePath],NSLocalizedDescriptionKey,nil]]];
|
||||
}
|
||||
|
||||
// If the caller didn't specify a custom file name, we'll use the file name of the file we were passed
|
||||
if (!fileName) {
|
||||
fileName = [filePath lastPathComponent];
|
||||
}
|
||||
|
||||
// If we were given the path to a file, and the user didn't specify a mime type, we can detect it from the file extension
|
||||
if (!contentType) {
|
||||
contentType = [ASIHTTPRequest mimeTypeForFileAtPath:filePath];
|
||||
}
|
||||
[self addData:filePath withFileName:fileName andContentType:contentType forKey:key];
|
||||
}
|
||||
|
||||
- (void)setFile:(NSString *)filePath forKey:(NSString *)key
|
||||
{
|
||||
[self setFile:filePath withFileName:nil andContentType:nil forKey:key];
|
||||
}
|
||||
|
||||
- (void)setFile:(id)data withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key
|
||||
{
|
||||
// Remove any existing value
|
||||
NSUInteger i;
|
||||
for (i=0; i<[[self fileData] count]; i++) {
|
||||
NSDictionary *val = [[self fileData] objectAtIndex:i];
|
||||
if ([[val objectForKey:@"key"] isEqualToString:key]) {
|
||||
[[self fileData] removeObjectAtIndex:i];
|
||||
i--;
|
||||
}
|
||||
}
|
||||
[self addFile:data withFileName:fileName andContentType:contentType forKey:key];
|
||||
}
|
||||
|
||||
- (void)addData:(NSData *)data forKey:(NSString *)key
|
||||
{
|
||||
[self addData:data withFileName:@"file" andContentType:nil forKey:key];
|
||||
}
|
||||
|
||||
- (void)addData:(id)data withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key
|
||||
{
|
||||
if (![self fileData]) {
|
||||
[self setFileData:[NSMutableArray array]];
|
||||
}
|
||||
if (!contentType) {
|
||||
contentType = @"application/octet-stream";
|
||||
}
|
||||
|
||||
NSMutableDictionary *fileInfo = [NSMutableDictionary dictionaryWithCapacity:4];
|
||||
[fileInfo setValue:key forKey:@"key"];
|
||||
[fileInfo setValue:fileName forKey:@"fileName"];
|
||||
[fileInfo setValue:contentType forKey:@"contentType"];
|
||||
[fileInfo setValue:data forKey:@"data"];
|
||||
|
||||
[[self fileData] addObject:fileInfo];
|
||||
}
|
||||
|
||||
- (void)setData:(NSData *)data forKey:(NSString *)key
|
||||
{
|
||||
[self setData:data withFileName:@"file" andContentType:nil forKey:key];
|
||||
}
|
||||
|
||||
- (void)setData:(id)data withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key
|
||||
{
|
||||
// Remove any existing value
|
||||
NSUInteger i;
|
||||
for (i=0; i<[[self fileData] count]; i++) {
|
||||
NSDictionary *val = [[self fileData] objectAtIndex:i];
|
||||
if ([[val objectForKey:@"key"] isEqualToString:key]) {
|
||||
[[self fileData] removeObjectAtIndex:i];
|
||||
i--;
|
||||
}
|
||||
}
|
||||
[self addData:data withFileName:fileName andContentType:contentType forKey:key];
|
||||
}
|
||||
|
||||
- (void)buildPostBody
|
||||
{
|
||||
if ([self haveBuiltPostBody]) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
[self setDebugBodyString:@""];
|
||||
#endif
|
||||
|
||||
if (![self postData] && ![self fileData]) {
|
||||
[super buildPostBody];
|
||||
return;
|
||||
}
|
||||
if ([[self fileData] count] > 0) {
|
||||
[self setShouldStreamPostDataFromDisk:YES];
|
||||
}
|
||||
|
||||
if ([self postFormat] == ASIURLEncodedPostFormat) {
|
||||
[self buildURLEncodedPostBody];
|
||||
} else {
|
||||
[self buildMultipartFormDataPostBody];
|
||||
}
|
||||
|
||||
[super buildPostBody];
|
||||
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
NSLog(@"%@",[self debugBodyString]);
|
||||
[self setDebugBodyString:nil];
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
- (void)buildMultipartFormDataPostBody
|
||||
{
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
[self addToDebugBody:@"\r\n==== Building a multipart/form-data body ====\r\n"];
|
||||
#endif
|
||||
|
||||
NSString *charset = (NSString *)CFStringConvertEncodingToIANACharSetName(CFStringConvertNSStringEncodingToEncoding([self stringEncoding]));
|
||||
|
||||
// We don't bother to check if post data contains the boundary, since it's pretty unlikely that it does.
|
||||
CFUUIDRef uuid = CFUUIDCreate(nil);
|
||||
NSString *uuidString = [(NSString*)CFUUIDCreateString(nil, uuid) autorelease];
|
||||
CFRelease(uuid);
|
||||
NSString *stringBoundary = [NSString stringWithFormat:@"0xKhTmLbOuNdArY-%@",uuidString];
|
||||
|
||||
[self addRequestHeader:@"Content-Type" value:[NSString stringWithFormat:@"multipart/form-data; charset=%@; boundary=%@", charset, stringBoundary]];
|
||||
|
||||
[self appendPostString:[NSString stringWithFormat:@"--%@\r\n",stringBoundary]];
|
||||
|
||||
// Adds post data
|
||||
NSString *endItemBoundary = [NSString stringWithFormat:@"\r\n--%@\r\n",stringBoundary];
|
||||
NSUInteger i=0;
|
||||
for (NSDictionary *val in [self postData]) {
|
||||
[self appendPostString:[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n",[val objectForKey:@"key"]]];
|
||||
[self appendPostString:[val objectForKey:@"value"]];
|
||||
i++;
|
||||
if (i != [[self postData] count] || [[self fileData] count] > 0) { //Only add the boundary if this is not the last item in the post body
|
||||
[self appendPostString:endItemBoundary];
|
||||
}
|
||||
}
|
||||
|
||||
// Adds files to upload
|
||||
i=0;
|
||||
for (NSDictionary *val in [self fileData]) {
|
||||
|
||||
[self appendPostString:[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", [val objectForKey:@"key"], [val objectForKey:@"fileName"]]];
|
||||
[self appendPostString:[NSString stringWithFormat:@"Content-Type: %@\r\n\r\n", [val objectForKey:@"contentType"]]];
|
||||
|
||||
id data = [val objectForKey:@"data"];
|
||||
if ([data isKindOfClass:[NSString class]]) {
|
||||
[self appendPostDataFromFile:data];
|
||||
} else {
|
||||
[self appendPostData:data];
|
||||
}
|
||||
i++;
|
||||
// Only add the boundary if this is not the last item in the post body
|
||||
if (i != [[self fileData] count]) {
|
||||
[self appendPostString:endItemBoundary];
|
||||
}
|
||||
}
|
||||
|
||||
[self appendPostString:[NSString stringWithFormat:@"\r\n--%@--\r\n",stringBoundary]];
|
||||
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
[self addToDebugBody:@"==== End of multipart/form-data body ====\r\n"];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)buildURLEncodedPostBody
|
||||
{
|
||||
|
||||
// We can't post binary data using application/x-www-form-urlencoded
|
||||
if ([[self fileData] count] > 0) {
|
||||
[self setPostFormat:ASIMultipartFormDataPostFormat];
|
||||
[self buildMultipartFormDataPostBody];
|
||||
return;
|
||||
}
|
||||
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
[self addToDebugBody:@"\r\n==== Building an application/x-www-form-urlencoded body ====\r\n"];
|
||||
#endif
|
||||
|
||||
|
||||
NSString *charset = (NSString *)CFStringConvertEncodingToIANACharSetName(CFStringConvertNSStringEncodingToEncoding([self stringEncoding]));
|
||||
|
||||
[self addRequestHeader:@"Content-Type" value:[NSString stringWithFormat:@"application/x-www-form-urlencoded; charset=%@",charset]];
|
||||
|
||||
|
||||
NSUInteger i=0;
|
||||
NSUInteger count = [[self postData] count]-1;
|
||||
for (NSDictionary *val in [self postData]) {
|
||||
NSString *data = [NSString stringWithFormat:@"%@=%@%@", [self encodeURL:[val objectForKey:@"key"]], [self encodeURL:[val objectForKey:@"value"]],(i<count ? @"&" : @"")];
|
||||
[self appendPostString:data];
|
||||
i++;
|
||||
}
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
[self addToDebugBody:@"\r\n==== End of application/x-www-form-urlencoded body ====\r\n"];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)appendPostString:(NSString *)string
|
||||
{
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
[self addToDebugBody:string];
|
||||
#endif
|
||||
[super appendPostData:[string dataUsingEncoding:[self stringEncoding]]];
|
||||
}
|
||||
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
- (void)appendPostData:(NSData *)data
|
||||
{
|
||||
[self addToDebugBody:[NSString stringWithFormat:@"[%lu bytes of data]",(unsigned long)[data length]]];
|
||||
[super appendPostData:data];
|
||||
}
|
||||
|
||||
- (void)appendPostDataFromFile:(NSString *)file
|
||||
{
|
||||
NSError *err = nil;
|
||||
unsigned long long fileSize = [[[[[[NSFileManager alloc] init] autorelease] attributesOfItemAtPath:file error:&err] objectForKey:NSFileSize] unsignedLongLongValue];
|
||||
if (err) {
|
||||
[self addToDebugBody:[NSString stringWithFormat:@"[Error: Failed to obtain the size of the file at '%@']",file]];
|
||||
} else {
|
||||
[self addToDebugBody:[NSString stringWithFormat:@"[%llu bytes of data from file '%@']",fileSize,file]];
|
||||
}
|
||||
|
||||
[super appendPostDataFromFile:file];
|
||||
}
|
||||
|
||||
- (void)addToDebugBody:(NSString *)string
|
||||
{
|
||||
if (string) {
|
||||
[self setDebugBodyString:[[self debugBodyString] stringByAppendingString:string]];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#pragma mark NSCopying
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
ASIFormDataRequest *newRequest = [super copyWithZone:zone];
|
||||
[newRequest setPostData:[[[self postData] mutableCopyWithZone:zone] autorelease]];
|
||||
[newRequest setFileData:[[[self fileData] mutableCopyWithZone:zone] autorelease]];
|
||||
[newRequest setPostFormat:[self postFormat]];
|
||||
[newRequest setStringEncoding:[self stringEncoding]];
|
||||
[newRequest setRequestMethod:[self requestMethod]];
|
||||
return newRequest;
|
||||
}
|
||||
|
||||
@synthesize postData;
|
||||
@synthesize fileData;
|
||||
@synthesize postFormat;
|
||||
@synthesize stringEncoding;
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
@synthesize debugBodyString;
|
||||
#endif
|
||||
@end
|
||||
1004
IOSBoilerplate/ASIHTTPRequest.h
Normal file
1004
IOSBoilerplate/ASIHTTPRequest.h
Normal file
File diff suppressed because it is too large
Load Diff
5107
IOSBoilerplate/ASIHTTPRequest.m
Normal file
5107
IOSBoilerplate/ASIHTTPRequest.m
Normal file
File diff suppressed because it is too large
Load Diff
37
IOSBoilerplate/ASIHTTPRequestConfig.h
Normal file
37
IOSBoilerplate/ASIHTTPRequestConfig.h
Normal file
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// ASIHTTPRequestConfig.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 14/12/2009.
|
||||
// Copyright 2009 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
// ======
|
||||
// Debug output configuration options
|
||||
// ======
|
||||
|
||||
// When set to 1 ASIHTTPRequests will print information about what a request is doing
|
||||
#ifndef DEBUG_REQUEST_STATUS
|
||||
#define DEBUG_REQUEST_STATUS 0
|
||||
#endif
|
||||
|
||||
// When set to 1, ASIFormDataRequests will print information about the request body to the console
|
||||
#ifndef DEBUG_FORM_DATA_REQUEST
|
||||
#define DEBUG_FORM_DATA_REQUEST 0
|
||||
#endif
|
||||
|
||||
// When set to 1, ASIHTTPRequests will print information about bandwidth throttling to the console
|
||||
#ifndef DEBUG_THROTTLING
|
||||
#define DEBUG_THROTTLING 0
|
||||
#endif
|
||||
|
||||
// When set to 1, ASIHTTPRequests will print information about persistent connections to the console
|
||||
#ifndef DEBUG_PERSISTENT_CONNECTIONS
|
||||
#define DEBUG_PERSISTENT_CONNECTIONS 0
|
||||
#endif
|
||||
|
||||
// When set to 1, ASIHTTPRequests will print information about HTTP authentication (Basic, Digest or NTLM) to the console
|
||||
#ifndef DEBUG_HTTP_AUTHENTICATION
|
||||
#define DEBUG_HTTP_AUTHENTICATION 0
|
||||
#endif
|
||||
35
IOSBoilerplate/ASIHTTPRequestDelegate.h
Normal file
35
IOSBoilerplate/ASIHTTPRequestDelegate.h
Normal file
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// ASIHTTPRequestDelegate.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 13/04/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
@class ASIHTTPRequest;
|
||||
|
||||
@protocol ASIHTTPRequestDelegate <NSObject>
|
||||
|
||||
@optional
|
||||
|
||||
// These are the default delegate methods for request status
|
||||
// You can use different ones by setting didStartSelector / didFinishSelector / didFailSelector
|
||||
- (void)requestStarted:(ASIHTTPRequest *)request;
|
||||
- (void)request:(ASIHTTPRequest *)request didReceiveResponseHeaders:(NSDictionary *)responseHeaders;
|
||||
- (void)request:(ASIHTTPRequest *)request willRedirectToURL:(NSURL *)newURL;
|
||||
- (void)requestFinished:(ASIHTTPRequest *)request;
|
||||
- (void)requestFailed:(ASIHTTPRequest *)request;
|
||||
- (void)requestRedirected:(ASIHTTPRequest *)request;
|
||||
|
||||
// When a delegate implements this method, it is expected to process all incoming data itself
|
||||
// This means that responseData / responseString / downloadDestinationPath etc are ignored
|
||||
// You can have the request call a different method by setting didReceiveDataSelector
|
||||
- (void)request:(ASIHTTPRequest *)request didReceiveData:(NSData *)data;
|
||||
|
||||
// If a delegate implements one of these, it will be asked to supply credentials when none are available
|
||||
// The delegate can then either restart the request ([request retryUsingSuppliedCredentials]) once credentials have been set
|
||||
// or cancel it ([request cancelAuthentication])
|
||||
- (void)authenticationNeededForRequest:(ASIHTTPRequest *)request;
|
||||
- (void)proxyAuthenticationNeededForRequest:(ASIHTTPRequest *)request;
|
||||
|
||||
@end
|
||||
26
IOSBoilerplate/ASIInputStream.h
Normal file
26
IOSBoilerplate/ASIInputStream.h
Normal file
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// ASIInputStream.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 10/08/2009.
|
||||
// Copyright 2009 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class ASIHTTPRequest;
|
||||
|
||||
// This is a wrapper for NSInputStream that pretends to be an NSInputStream itself
|
||||
// Subclassing NSInputStream seems to be tricky, and may involve overriding undocumented methods, so we'll cheat instead.
|
||||
// It is used by ASIHTTPRequest whenever we have a request body, and handles measuring and throttling the bandwidth used for uploading
|
||||
|
||||
@interface ASIInputStream : NSObject {
|
||||
NSInputStream *stream;
|
||||
ASIHTTPRequest *request;
|
||||
}
|
||||
+ (id)inputStreamWithFileAtPath:(NSString *)path request:(ASIHTTPRequest *)request;
|
||||
+ (id)inputStreamWithData:(NSData *)data request:(ASIHTTPRequest *)request;
|
||||
|
||||
@property (retain, nonatomic) NSInputStream *stream;
|
||||
@property (assign, nonatomic) ASIHTTPRequest *request;
|
||||
@end
|
||||
138
IOSBoilerplate/ASIInputStream.m
Normal file
138
IOSBoilerplate/ASIInputStream.m
Normal file
@@ -0,0 +1,138 @@
|
||||
//
|
||||
// ASIInputStream.m
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 10/08/2009.
|
||||
// Copyright 2009 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ASIInputStream.h"
|
||||
#import "ASIHTTPRequest.h"
|
||||
|
||||
// Used to ensure only one request can read data at once
|
||||
static NSLock *readLock = nil;
|
||||
|
||||
@implementation ASIInputStream
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self == [ASIInputStream class]) {
|
||||
readLock = [[NSLock alloc] init];
|
||||
}
|
||||
}
|
||||
|
||||
+ (id)inputStreamWithFileAtPath:(NSString *)path request:(ASIHTTPRequest *)theRequest
|
||||
{
|
||||
ASIInputStream *theStream = [[[self alloc] init] autorelease];
|
||||
[theStream setRequest:theRequest];
|
||||
[theStream setStream:[NSInputStream inputStreamWithFileAtPath:path]];
|
||||
return theStream;
|
||||
}
|
||||
|
||||
+ (id)inputStreamWithData:(NSData *)data request:(ASIHTTPRequest *)theRequest
|
||||
{
|
||||
ASIInputStream *theStream = [[[self alloc] init] autorelease];
|
||||
[theStream setRequest:theRequest];
|
||||
[theStream setStream:[NSInputStream inputStreamWithData:data]];
|
||||
return theStream;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[stream release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
// Called when CFNetwork wants to read more of our request body
|
||||
// When throttling is on, we ask ASIHTTPRequest for the maximum amount of data we can read
|
||||
- (NSInteger)read:(uint8_t *)buffer maxLength:(NSUInteger)len
|
||||
{
|
||||
[readLock lock];
|
||||
unsigned long toRead = len;
|
||||
if ([ASIHTTPRequest isBandwidthThrottled]) {
|
||||
toRead = [ASIHTTPRequest maxUploadReadLength];
|
||||
if (toRead > len) {
|
||||
toRead = len;
|
||||
} else if (toRead == 0) {
|
||||
toRead = 1;
|
||||
}
|
||||
[request performThrottling];
|
||||
}
|
||||
[readLock unlock];
|
||||
NSInteger rv = [stream read:buffer maxLength:toRead];
|
||||
if (rv > 0)
|
||||
[ASIHTTPRequest incrementBandwidthUsedInLastSecond:rv];
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Implement NSInputStream mandatory methods to make sure they are implemented
|
||||
* (necessary for MacRuby for example) and avoid the overhead of method
|
||||
* forwarding for these common methods.
|
||||
*/
|
||||
- (void)open
|
||||
{
|
||||
[stream open];
|
||||
}
|
||||
|
||||
- (void)close
|
||||
{
|
||||
[stream close];
|
||||
}
|
||||
|
||||
- (id)delegate
|
||||
{
|
||||
return [stream delegate];
|
||||
}
|
||||
|
||||
- (void)setDelegate:(id)delegate
|
||||
{
|
||||
[stream setDelegate:delegate];
|
||||
}
|
||||
|
||||
- (void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode
|
||||
{
|
||||
[stream scheduleInRunLoop:aRunLoop forMode:mode];
|
||||
}
|
||||
|
||||
- (void)removeFromRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode
|
||||
{
|
||||
[stream removeFromRunLoop:aRunLoop forMode:mode];
|
||||
}
|
||||
|
||||
- (id)propertyForKey:(NSString *)key
|
||||
{
|
||||
return [stream propertyForKey:key];
|
||||
}
|
||||
|
||||
- (BOOL)setProperty:(id)property forKey:(NSString *)key
|
||||
{
|
||||
return [stream setProperty:property forKey:key];
|
||||
}
|
||||
|
||||
- (NSStreamStatus)streamStatus
|
||||
{
|
||||
return [stream streamStatus];
|
||||
}
|
||||
|
||||
- (NSError *)streamError
|
||||
{
|
||||
return [stream streamError];
|
||||
}
|
||||
|
||||
// If we get asked to perform a method we don't have (probably internal ones),
|
||||
// we'll just forward the message to our stream
|
||||
|
||||
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
|
||||
{
|
||||
return [stream methodSignatureForSelector:aSelector];
|
||||
}
|
||||
|
||||
- (void)forwardInvocation:(NSInvocation *)anInvocation
|
||||
{
|
||||
[anInvocation invokeWithTarget:stream];
|
||||
}
|
||||
|
||||
@synthesize stream;
|
||||
@synthesize request;
|
||||
@end
|
||||
38
IOSBoilerplate/ASIProgressDelegate.h
Normal file
38
IOSBoilerplate/ASIProgressDelegate.h
Normal file
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// ASIProgressDelegate.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 13/04/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
@class ASIHTTPRequest;
|
||||
|
||||
@protocol ASIProgressDelegate <NSObject>
|
||||
|
||||
@optional
|
||||
|
||||
// These methods are used to update UIProgressViews (iPhone OS) or NSProgressIndicators (Mac OS X)
|
||||
// If you are using a custom progress delegate, you may find it easier to implement didReceiveBytes / didSendBytes instead
|
||||
#if TARGET_OS_IPHONE
|
||||
- (void)setProgress:(float)newProgress;
|
||||
#else
|
||||
- (void)setDoubleValue:(double)newProgress;
|
||||
- (void)setMaxValue:(double)newMax;
|
||||
#endif
|
||||
|
||||
// Called when the request receives some data - bytes is the length of that data
|
||||
- (void)request:(ASIHTTPRequest *)request didReceiveBytes:(long long)bytes;
|
||||
|
||||
// Called when the request sends some data
|
||||
// The first 32KB (128KB on older platforms) of data sent is not included in this amount because of limitations with the CFNetwork API
|
||||
// bytes may be less than zero if a request needs to remove upload progress (probably because the request needs to run again)
|
||||
- (void)request:(ASIHTTPRequest *)request didSendBytes:(long long)bytes;
|
||||
|
||||
// Called when a request needs to change the length of the content to download
|
||||
- (void)request:(ASIHTTPRequest *)request incrementDownloadSizeBy:(long long)newLength;
|
||||
|
||||
// Called when a request needs to change the length of the content to upload
|
||||
// newLength may be less than zero when a request needs to remove the size of the internal buffer from progress tracking
|
||||
- (void)request:(ASIHTTPRequest *)request incrementUploadSizeBy:(long long)newLength;
|
||||
@end
|
||||
18
IOSBoilerplate/AsyncCell.h
Normal file
18
IOSBoilerplate/AsyncCell.h
Normal file
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// AsyncCell.h
|
||||
// IOSBoilerplate
|
||||
//
|
||||
// Created by Alberto Gimeno Brieba on 08/09/11.
|
||||
// Copyright 2011 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "FastCell.h"
|
||||
|
||||
@interface AsyncCell : FastCell
|
||||
|
||||
@property (nonatomic, retain) NSDictionary* info;
|
||||
@property (nonatomic, retain) NSURL* imageURL;
|
||||
|
||||
- (void) updateCellInfo:(NSDictionary*)_info;
|
||||
|
||||
@end
|
||||
94
IOSBoilerplate/AsyncCell.m
Normal file
94
IOSBoilerplate/AsyncCell.m
Normal file
@@ -0,0 +1,94 @@
|
||||
//
|
||||
// AsyncCell.m
|
||||
// IOSBoilerplate
|
||||
//
|
||||
// Created by Alberto Gimeno Brieba on 08/09/11.
|
||||
// Copyright 2011 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "AsyncCell.h"
|
||||
#import "ImageManager.h"
|
||||
#import "DictionaryHelper.h"
|
||||
|
||||
@implementation AsyncCell
|
||||
|
||||
@synthesize info;
|
||||
@synthesize imageURL;
|
||||
|
||||
- (id) initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
|
||||
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier])
|
||||
{
|
||||
self.backgroundColor = [UIColor whiteColor];
|
||||
self.opaque = YES;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) prepareForReuse {
|
||||
[super prepareForReuse];
|
||||
}
|
||||
|
||||
static UIFont* system14 = nil;
|
||||
static UIFont* bold14 = nil;
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if(self == [AsyncCell class])
|
||||
{
|
||||
system14 = [[UIFont systemFontOfSize:14] retain];
|
||||
bold14 = [[UIFont boldSystemFontOfSize:14] retain];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[info release];
|
||||
[imageURL release];
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void) drawContentView:(CGRect)rect {
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
|
||||
[[UIColor whiteColor] set];
|
||||
CGContextFillRect(context, rect);
|
||||
|
||||
NSString* name = [info stringForKey:@"from_user"];
|
||||
NSString* text = [info stringForKey:@"text"];
|
||||
|
||||
CGFloat widthr = self.frame.size.width - 70;
|
||||
|
||||
[[UIColor blackColor] set];
|
||||
[name drawInRect:CGRectMake(63.0, 5.0, widthr, 20.0) withFont:bold14 lineBreakMode:UILineBreakModeTailTruncation];
|
||||
[[UIColor grayColor] set];
|
||||
[text drawInRect:CGRectMake(63.0, 25.0, widthr, 20.0) withFont:system14 lineBreakMode:UILineBreakModeTailTruncation];
|
||||
|
||||
if (imageURL) {
|
||||
UIImage* img = [ImageManager loadImage:imageURL];
|
||||
if (img) {
|
||||
CGRect r = CGRectMake(5.0, 5.0, 48.0, 48.0);
|
||||
[img drawInRect:r];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void) updateCellInfo:(NSDictionary*)_info {
|
||||
self.info = _info;
|
||||
NSString* image = [info stringForKey:@"profile_image_url"];
|
||||
if (image) {
|
||||
NSURL* url = [[NSURL alloc] initWithString:image];
|
||||
self.imageURL = url;
|
||||
[url release];
|
||||
} else {
|
||||
self.imageURL = nil;
|
||||
}
|
||||
[self setNeedsDisplay];
|
||||
}
|
||||
|
||||
- (void) imageLoaded:(UIImage*)image withURL:(NSURL*)url {
|
||||
if ([imageURL isEqual:url]) {
|
||||
[self setNeedsDisplay];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
16
IOSBoilerplate/AsyncCellImagesExample.h
Normal file
16
IOSBoilerplate/AsyncCellImagesExample.h
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// AsyncCellImagesExample.h
|
||||
// IOSBoilerplate
|
||||
//
|
||||
// Created by Alberto Gimeno Brieba on 08/09/11.
|
||||
// Copyright 2011 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "BaseViewController.h"
|
||||
|
||||
@interface AsyncCellImagesExample : BaseViewController <UITableViewDelegate, UITableViewDataSource>
|
||||
|
||||
@property (nonatomic, retain) IBOutlet UITableView* table;
|
||||
@property (nonatomic, retain) NSArray* results;
|
||||
|
||||
@end
|
||||
128
IOSBoilerplate/AsyncCellImagesExample.m
Normal file
128
IOSBoilerplate/AsyncCellImagesExample.m
Normal file
@@ -0,0 +1,128 @@
|
||||
//
|
||||
// AsyncCellImagesExample.m
|
||||
// IOSBoilerplate
|
||||
//
|
||||
// Created by Alberto Gimeno Brieba on 08/09/11.
|
||||
// Copyright 2011 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "AsyncCellImagesExample.h"
|
||||
#import "SVProgressHUD.h"
|
||||
#import "JSONKit.h"
|
||||
#import "DictionaryHelper.h"
|
||||
#import "AsyncCell.h"
|
||||
|
||||
@implementation AsyncCellImagesExample
|
||||
|
||||
@synthesize table;
|
||||
@synthesize results;
|
||||
|
||||
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
|
||||
{
|
||||
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
|
||||
if (self) {
|
||||
// Custom initialization
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)didReceiveMemoryWarning
|
||||
{
|
||||
// Releases the view if it doesn't have a superview.
|
||||
[super didReceiveMemoryWarning];
|
||||
|
||||
// Release any cached data, images, etc that aren't in use.
|
||||
}
|
||||
|
||||
#pragma mark - UITableViewDelegate and DataSource
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
|
||||
{
|
||||
return [results count];
|
||||
}
|
||||
|
||||
// Customize the appearance of table view cells.
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
static NSString *CellIdentifier = @"Cell";
|
||||
|
||||
AsyncCell *cell = (AsyncCell*) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
|
||||
if (cell == nil) {
|
||||
cell = [[[AsyncCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
|
||||
}
|
||||
|
||||
NSDictionary* obj = [results objectAtIndex:indexPath.row];
|
||||
[cell updateCellInfo:obj];
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (void) imageLoaded:(UIImage*)image withURL:(NSURL*)url {
|
||||
[self refreshCellsWithImage:image fromURL:url inTable:table];
|
||||
}
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
return 58;
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
||||
}
|
||||
|
||||
#pragma mark - View lifecycle
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
self.title = @"Latest twits about iOS";
|
||||
}
|
||||
|
||||
- (void)viewDidUnload
|
||||
{
|
||||
[super viewDidUnload];
|
||||
// Release any retained subviews of the main view.
|
||||
// e.g. self.myOutlet = nil;
|
||||
}
|
||||
|
||||
- (void)viewDidAppear:(BOOL)animated {
|
||||
[super viewDidAppear:animated];
|
||||
|
||||
[SVProgressHUD showInView:self.view];
|
||||
|
||||
// By using [self requestWithURL:@"..."]; the reques is cancelled if the user closes this view controller
|
||||
ASIHTTPRequest* request = [self requestWithURL:@"http://search.twitter.com/search.json?q=ios"];
|
||||
[request setDidFinishSelector:@selector(requestFinished:)];
|
||||
[request setDidFailSelector:@selector(requestFailed:)];
|
||||
[request startAsynchronous];
|
||||
}
|
||||
|
||||
- (void)requestFinished:(ASIHTTPRequest*)request {
|
||||
[SVProgressHUD dismiss];
|
||||
|
||||
NSDictionary* result = [[request responseString] objectFromJSONString];
|
||||
self.results = [result arrayForKey:@"results"];
|
||||
[table reloadData];
|
||||
}
|
||||
|
||||
- (void)requestFailed:(ASIHTTPRequest*)request {
|
||||
[SVProgressHUD dismissWithError:[[request error] localizedDescription]];
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[table release];
|
||||
[results release];
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@end
|
||||
230
IOSBoilerplate/AsyncCellImagesExample.xib
Normal file
230
IOSBoilerplate/AsyncCellImagesExample.xib
Normal file
@@ -0,0 +1,230 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<archive type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="7.10">
|
||||
<data>
|
||||
<int key="IBDocument.SystemTarget">1056</int>
|
||||
<string key="IBDocument.SystemVersion">11B26</string>
|
||||
<string key="IBDocument.InterfaceBuilderVersion">1617</string>
|
||||
<string key="IBDocument.AppKitVersion">1138</string>
|
||||
<string key="IBDocument.HIToolboxVersion">566.00</string>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string key="NS.object.0">534</string>
|
||||
</object>
|
||||
<object class="NSArray" key="IBDocument.IntegratedClassDependencies">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>IBProxyObject</string>
|
||||
<string>IBUIView</string>
|
||||
<string>IBUITableView</string>
|
||||
</object>
|
||||
<object class="NSArray" key="IBDocument.PluginDependencies">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="IBDocument.Metadata">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys" id="0">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
</object>
|
||||
<reference key="dict.values" ref="0"/>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBProxyObject" id="372490531">
|
||||
<string key="IBProxiedObjectIdentifier">IBFilesOwner</string>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
</object>
|
||||
<object class="IBProxyObject" id="975951072">
|
||||
<string key="IBProxiedObjectIdentifier">IBFirstResponder</string>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
</object>
|
||||
<object class="IBUIView" id="191373211">
|
||||
<reference key="NSNextResponder"/>
|
||||
<int key="NSvFlags">274</int>
|
||||
<object class="NSMutableArray" key="NSSubviews">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBUITableView" id="245389582">
|
||||
<reference key="NSNextResponder" ref="191373211"/>
|
||||
<int key="NSvFlags">274</int>
|
||||
<string key="NSFrameSize">{320, 460}</string>
|
||||
<reference key="NSSuperview" ref="191373211"/>
|
||||
<reference key="NSWindow"/>
|
||||
<string key="NSReuseIdentifierKey">_NS:392</string>
|
||||
<object class="NSColor" key="IBUIBackgroundColor">
|
||||
<int key="NSColorSpace">3</int>
|
||||
<bytes key="NSWhite">MQA</bytes>
|
||||
</object>
|
||||
<bool key="IBUIClipsSubviews">YES</bool>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
<bool key="IBUIAlwaysBounceVertical">YES</bool>
|
||||
<int key="IBUISeparatorStyle">1</int>
|
||||
<int key="IBUISectionIndexMinimumDisplayRowCount">0</int>
|
||||
<bool key="IBUIShowsSelectionImmediatelyOnTouchBegin">YES</bool>
|
||||
<float key="IBUIRowHeight">44</float>
|
||||
<float key="IBUISectionHeaderHeight">22</float>
|
||||
<float key="IBUISectionFooterHeight">22</float>
|
||||
</object>
|
||||
</object>
|
||||
<string key="NSFrame">{{0, 20}, {320, 460}}</string>
|
||||
<reference key="NSSuperview"/>
|
||||
<reference key="NSWindow"/>
|
||||
<object class="NSColor" key="IBUIBackgroundColor">
|
||||
<int key="NSColorSpace">3</int>
|
||||
<bytes key="NSWhite">MQA</bytes>
|
||||
<object class="NSColorSpace" key="NSCustomColorSpace">
|
||||
<int key="NSID">2</int>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBUISimulatedStatusBarMetrics" key="IBUISimulatedStatusBarMetrics"/>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBObjectContainer" key="IBDocument.Objects">
|
||||
<object class="NSMutableArray" key="connectionRecords">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchOutletConnection" key="connection">
|
||||
<string key="label">view</string>
|
||||
<reference key="source" ref="372490531"/>
|
||||
<reference key="destination" ref="191373211"/>
|
||||
</object>
|
||||
<int key="connectionID">3</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchOutletConnection" key="connection">
|
||||
<string key="label">table</string>
|
||||
<reference key="source" ref="372490531"/>
|
||||
<reference key="destination" ref="245389582"/>
|
||||
</object>
|
||||
<int key="connectionID">5</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchOutletConnection" key="connection">
|
||||
<string key="label">dataSource</string>
|
||||
<reference key="source" ref="245389582"/>
|
||||
<reference key="destination" ref="372490531"/>
|
||||
</object>
|
||||
<int key="connectionID">6</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchOutletConnection" key="connection">
|
||||
<string key="label">delegate</string>
|
||||
<reference key="source" ref="245389582"/>
|
||||
<reference key="destination" ref="372490531"/>
|
||||
</object>
|
||||
<int key="connectionID">7</int>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBMutableOrderedSet" key="objectRecords">
|
||||
<object class="NSArray" key="orderedObjects">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">0</int>
|
||||
<reference key="object" ref="0"/>
|
||||
<reference key="children" ref="1000"/>
|
||||
<nil key="parent"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">1</int>
|
||||
<reference key="object" ref="191373211"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="245389582"/>
|
||||
</object>
|
||||
<reference key="parent" ref="0"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">-1</int>
|
||||
<reference key="object" ref="372490531"/>
|
||||
<reference key="parent" ref="0"/>
|
||||
<string key="objectName">File's Owner</string>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">-2</int>
|
||||
<reference key="object" ref="975951072"/>
|
||||
<reference key="parent" ref="0"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">4</int>
|
||||
<reference key="object" ref="245389582"/>
|
||||
<reference key="parent" ref="191373211"/>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="flattenedProperties">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>-1.CustomClassName</string>
|
||||
<string>-1.IBPluginDependency</string>
|
||||
<string>-2.CustomClassName</string>
|
||||
<string>-2.IBPluginDependency</string>
|
||||
<string>1.IBPluginDependency</string>
|
||||
<string>4.IBPluginDependency</string>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>AsyncCellImagesExample</string>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string>UIResponder</string>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="unlocalizedProperties">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference key="dict.sortedKeys" ref="0"/>
|
||||
<reference key="dict.values" ref="0"/>
|
||||
</object>
|
||||
<nil key="activeLocalization"/>
|
||||
<object class="NSMutableDictionary" key="localizations">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference key="dict.sortedKeys" ref="0"/>
|
||||
<reference key="dict.values" ref="0"/>
|
||||
</object>
|
||||
<nil key="sourceID"/>
|
||||
<int key="maxID">7</int>
|
||||
</object>
|
||||
<object class="IBClassDescriber" key="IBDocument.Classes">
|
||||
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">AsyncCellImagesExample</string>
|
||||
<string key="superclassName">BaseViewController</string>
|
||||
<object class="NSMutableDictionary" key="outlets">
|
||||
<string key="NS.key.0">table</string>
|
||||
<string key="NS.object.0">UITableView</string>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="toOneOutletInfosByName">
|
||||
<string key="NS.key.0">table</string>
|
||||
<object class="IBToOneOutletInfo" key="NS.object.0">
|
||||
<string key="name">table</string>
|
||||
<string key="candidateClassName">UITableView</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">./Classes/AsyncCellImagesExample.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">BaseViewController</string>
|
||||
<string key="superclassName">UIViewController</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">./Classes/BaseViewController.h</string>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<int key="IBDocument.localizationMode">0</int>
|
||||
<string key="IBDocument.TargetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3</string>
|
||||
<integer value="3000" key="NS.object.0"/>
|
||||
</object>
|
||||
<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
|
||||
<int key="IBDocument.defaultPropertyAccessControl">3</int>
|
||||
<string key="IBCocoaTouchPluginVersion">534</string>
|
||||
</data>
|
||||
</archive>
|
||||
16
IOSBoilerplate/AsyncImageExample.h
Normal file
16
IOSBoilerplate/AsyncImageExample.h
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// AsyncImageExample.h
|
||||
// IOSBoilerplate
|
||||
//
|
||||
// Created by Alberto Gimeno Brieba on 08/09/11.
|
||||
// Copyright 2011 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "BaseViewController.h"
|
||||
|
||||
@interface AsyncImageExample : BaseViewController
|
||||
|
||||
@property (nonatomic, retain) IBOutlet UIImageView* imageView;
|
||||
@property (nonatomic, retain) NSURL* url;
|
||||
|
||||
@end
|
||||
79
IOSBoilerplate/AsyncImageExample.m
Normal file
79
IOSBoilerplate/AsyncImageExample.m
Normal file
@@ -0,0 +1,79 @@
|
||||
//
|
||||
// AsyncImageExample.m
|
||||
// IOSBoilerplate
|
||||
//
|
||||
// Created by Alberto Gimeno Brieba on 08/09/11.
|
||||
// Copyright 2011 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "AsyncImageExample.h"
|
||||
#import "ImageManager.h"
|
||||
|
||||
@implementation AsyncImageExample
|
||||
|
||||
@synthesize imageView;
|
||||
@synthesize url;
|
||||
|
||||
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
|
||||
{
|
||||
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
|
||||
if (self) {
|
||||
// Custom initialization
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)didReceiveMemoryWarning
|
||||
{
|
||||
// Releases the view if it doesn't have a superview.
|
||||
[super didReceiveMemoryWarning];
|
||||
|
||||
// Release any cached data, images, etc that aren't in use.
|
||||
}
|
||||
|
||||
#pragma mark - View lifecycle
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
// Do any additional setup after loading the view from its nib.
|
||||
}
|
||||
|
||||
- (void)viewDidUnload
|
||||
{
|
||||
[super viewDidUnload];
|
||||
// Release any retained subviews of the main view.
|
||||
// e.g. self.myOutlet = nil;
|
||||
}
|
||||
|
||||
- (void)viewDidAppear:(BOOL)animated {
|
||||
|
||||
NSURL* _url = [[NSURL alloc] initWithString:@"http://upload.wikimedia.org/wikipedia/commons/thumb/e/ef/Zaragoza_shel.JPG/266px-Zaragoza_shel.JPG"];
|
||||
self.url = _url;
|
||||
[_url release];
|
||||
|
||||
UIImage* image = [ImageManager loadImage:url];
|
||||
|
||||
if (image) {
|
||||
imageView.image = image;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)imageLoaded:(UIImage*)image withURL:(NSURL*)_url {
|
||||
if ([url isEqual:_url]) {
|
||||
imageView.image = image;
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[imageView release];
|
||||
[url release];
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@end
|
||||
204
IOSBoilerplate/AsyncImageExample.xib
Normal file
204
IOSBoilerplate/AsyncImageExample.xib
Normal file
@@ -0,0 +1,204 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<archive type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="7.10">
|
||||
<data>
|
||||
<int key="IBDocument.SystemTarget">1056</int>
|
||||
<string key="IBDocument.SystemVersion">11B26</string>
|
||||
<string key="IBDocument.InterfaceBuilderVersion">1617</string>
|
||||
<string key="IBDocument.AppKitVersion">1138</string>
|
||||
<string key="IBDocument.HIToolboxVersion">566.00</string>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string key="NS.object.0">534</string>
|
||||
</object>
|
||||
<object class="NSArray" key="IBDocument.IntegratedClassDependencies">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>IBProxyObject</string>
|
||||
<string>IBUIView</string>
|
||||
<string>IBUIImageView</string>
|
||||
</object>
|
||||
<object class="NSArray" key="IBDocument.PluginDependencies">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="IBDocument.Metadata">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys" id="0">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
</object>
|
||||
<reference key="dict.values" ref="0"/>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBProxyObject" id="372490531">
|
||||
<string key="IBProxiedObjectIdentifier">IBFilesOwner</string>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
</object>
|
||||
<object class="IBProxyObject" id="975951072">
|
||||
<string key="IBProxiedObjectIdentifier">IBFirstResponder</string>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
</object>
|
||||
<object class="IBUIView" id="191373211">
|
||||
<reference key="NSNextResponder"/>
|
||||
<int key="NSvFlags">274</int>
|
||||
<object class="NSMutableArray" key="NSSubviews">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBUIImageView" id="835278">
|
||||
<reference key="NSNextResponder" ref="191373211"/>
|
||||
<int key="NSvFlags">274</int>
|
||||
<string key="NSFrameSize">{320, 460}</string>
|
||||
<reference key="NSSuperview" ref="191373211"/>
|
||||
<reference key="NSWindow"/>
|
||||
<string key="NSReuseIdentifierKey">_NS:541</string>
|
||||
<int key="IBUIContentMode">4</int>
|
||||
<bool key="IBUIUserInteractionEnabled">NO</bool>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
</object>
|
||||
</object>
|
||||
<string key="NSFrame">{{0, 20}, {320, 460}}</string>
|
||||
<reference key="NSSuperview"/>
|
||||
<reference key="NSWindow"/>
|
||||
<object class="NSColor" key="IBUIBackgroundColor">
|
||||
<int key="NSColorSpace">3</int>
|
||||
<bytes key="NSWhite">MQA</bytes>
|
||||
<object class="NSColorSpace" key="NSCustomColorSpace">
|
||||
<int key="NSID">2</int>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBUISimulatedStatusBarMetrics" key="IBUISimulatedStatusBarMetrics"/>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBObjectContainer" key="IBDocument.Objects">
|
||||
<object class="NSMutableArray" key="connectionRecords">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchOutletConnection" key="connection">
|
||||
<string key="label">view</string>
|
||||
<reference key="source" ref="372490531"/>
|
||||
<reference key="destination" ref="191373211"/>
|
||||
</object>
|
||||
<int key="connectionID">3</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchOutletConnection" key="connection">
|
||||
<string key="label">imageView</string>
|
||||
<reference key="source" ref="372490531"/>
|
||||
<reference key="destination" ref="835278"/>
|
||||
</object>
|
||||
<int key="connectionID">5</int>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBMutableOrderedSet" key="objectRecords">
|
||||
<object class="NSArray" key="orderedObjects">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">0</int>
|
||||
<reference key="object" ref="0"/>
|
||||
<reference key="children" ref="1000"/>
|
||||
<nil key="parent"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">1</int>
|
||||
<reference key="object" ref="191373211"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="835278"/>
|
||||
</object>
|
||||
<reference key="parent" ref="0"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">-1</int>
|
||||
<reference key="object" ref="372490531"/>
|
||||
<reference key="parent" ref="0"/>
|
||||
<string key="objectName">File's Owner</string>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">-2</int>
|
||||
<reference key="object" ref="975951072"/>
|
||||
<reference key="parent" ref="0"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">4</int>
|
||||
<reference key="object" ref="835278"/>
|
||||
<reference key="parent" ref="191373211"/>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="flattenedProperties">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>-1.CustomClassName</string>
|
||||
<string>-1.IBPluginDependency</string>
|
||||
<string>-2.CustomClassName</string>
|
||||
<string>-2.IBPluginDependency</string>
|
||||
<string>1.IBPluginDependency</string>
|
||||
<string>4.IBPluginDependency</string>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>AsyncImageExample</string>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string>UIResponder</string>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="unlocalizedProperties">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference key="dict.sortedKeys" ref="0"/>
|
||||
<reference key="dict.values" ref="0"/>
|
||||
</object>
|
||||
<nil key="activeLocalization"/>
|
||||
<object class="NSMutableDictionary" key="localizations">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference key="dict.sortedKeys" ref="0"/>
|
||||
<reference key="dict.values" ref="0"/>
|
||||
</object>
|
||||
<nil key="sourceID"/>
|
||||
<int key="maxID">5</int>
|
||||
</object>
|
||||
<object class="IBClassDescriber" key="IBDocument.Classes">
|
||||
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">AsyncImageExample</string>
|
||||
<string key="superclassName">BaseViewController</string>
|
||||
<object class="NSMutableDictionary" key="outlets">
|
||||
<string key="NS.key.0">imageView</string>
|
||||
<string key="NS.object.0">UIImageView</string>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="toOneOutletInfosByName">
|
||||
<string key="NS.key.0">imageView</string>
|
||||
<object class="IBToOneOutletInfo" key="NS.object.0">
|
||||
<string key="name">imageView</string>
|
||||
<string key="candidateClassName">UIImageView</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">./Classes/AsyncImageExample.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">BaseViewController</string>
|
||||
<string key="superclassName">UIViewController</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">./Classes/BaseViewController.h</string>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<int key="IBDocument.localizationMode">0</int>
|
||||
<string key="IBDocument.TargetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3</string>
|
||||
<integer value="3000" key="NS.object.0"/>
|
||||
</object>
|
||||
<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
|
||||
<int key="IBDocument.defaultPropertyAccessControl">3</int>
|
||||
<string key="IBCocoaTouchPluginVersion">534</string>
|
||||
</data>
|
||||
</archive>
|
||||
26
IOSBoilerplate/BaseViewController.h
Normal file
26
IOSBoilerplate/BaseViewController.h
Normal file
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// BaseViewController.h
|
||||
//
|
||||
// Created by Alberto Gimeno Brieba on 08/09/11.
|
||||
// Copyright 2011 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "ASIHTTPRequest.h"
|
||||
#import "ASIFormDataRequest.h"
|
||||
|
||||
@interface BaseViewController : UIViewController {
|
||||
|
||||
NSMutableArray* requests;
|
||||
|
||||
}
|
||||
|
||||
- (ASIHTTPRequest*) requestWithURL:(NSString*) s;
|
||||
- (ASIFormDataRequest*) formRequestWithURL:(NSString*) s;
|
||||
- (void) addRequest:(ASIHTTPRequest*)request;
|
||||
- (void) clearFinishedRequests;
|
||||
- (void) cancelRequests;
|
||||
|
||||
- (void) refreshCellsWithImage:(UIImage*)image fromURL:(NSURL*)url inTable:(UITableView*)tableView;
|
||||
|
||||
@end
|
||||
97
IOSBoilerplate/BaseViewController.m
Normal file
97
IOSBoilerplate/BaseViewController.m
Normal file
@@ -0,0 +1,97 @@
|
||||
//
|
||||
// BaseViewController.m
|
||||
//
|
||||
// Created by Alberto Gimeno Brieba on 08/09/11.
|
||||
// Copyright 2011 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "BaseViewController.h"
|
||||
#import "IOSBoilerplateAppDelegate.h"
|
||||
|
||||
@implementation BaseViewController
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark HTTP requests
|
||||
|
||||
- (ASIHTTPRequest*) requestWithURL:(NSString*) s {
|
||||
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:s]];
|
||||
[self addRequest:request];
|
||||
return request;
|
||||
}
|
||||
|
||||
- (ASIFormDataRequest*) formRequestWithURL:(NSString*) s {
|
||||
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:[NSURL URLWithString:s]];
|
||||
[self addRequest:request];
|
||||
return request;
|
||||
}
|
||||
|
||||
- (void) addRequest:(ASIHTTPRequest*)request {
|
||||
[request setDelegate:self];
|
||||
if (!requests) {
|
||||
requests = [[NSMutableArray alloc] initWithCapacity:3];
|
||||
} else {
|
||||
[self clearFinishedRequests];
|
||||
}
|
||||
[requests addObject:request];
|
||||
}
|
||||
|
||||
- (void) clearFinishedRequests {
|
||||
NSMutableArray* toremove = [[NSMutableArray alloc] initWithCapacity:[requests count]];
|
||||
for (ASIHTTPRequest* r in requests) {
|
||||
if ([r isFinished]) {
|
||||
[toremove addObject:r];
|
||||
}
|
||||
}
|
||||
|
||||
for (ASIHTTPRequest* r in toremove) {
|
||||
[requests removeObject:r];
|
||||
}
|
||||
[toremove release];
|
||||
}
|
||||
|
||||
- (void) cancelRequests {
|
||||
for (ASIHTTPRequest* r in requests) {
|
||||
r.delegate = nil;
|
||||
[r cancel];
|
||||
}
|
||||
[requests removeAllObjects];
|
||||
}
|
||||
|
||||
- (void) refreshCellsWithImage:(UIImage*)image fromURL:(NSURL*)url inTable:(UITableView*)tableView {
|
||||
NSArray *cells = [tableView visibleCells];
|
||||
[cells retain];
|
||||
SEL selector = @selector(imageLoaded:withURL:);
|
||||
for (int i = 0; i < [cells count]; i++) {
|
||||
UITableViewCell* c = [[cells objectAtIndex: i] retain];
|
||||
if ([c respondsToSelector:selector]) {
|
||||
[c performSelector:selector withObject:image withObject:url];
|
||||
}
|
||||
[c release];
|
||||
c = nil;
|
||||
}
|
||||
[cells release];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark UIViewController
|
||||
|
||||
- (void) viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
}
|
||||
|
||||
- (void) viewDidUnload {
|
||||
[super viewDidUnload];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Memory management
|
||||
|
||||
- (void)dealloc {
|
||||
[self cancelRequests];
|
||||
[requests release];
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
21
IOSBoilerplate/DictionaryHelper.h
Normal file
21
IOSBoilerplate/DictionaryHelper.h
Normal file
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// DictionaryHelper.h
|
||||
// IOSBoilerplate
|
||||
//
|
||||
// Created by Alberto Gimeno Brieba on 08/09/11.
|
||||
// Copyright 2011 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface NSDictionary (helper)
|
||||
|
||||
- (NSString*) stringForKey:(id)key;
|
||||
|
||||
- (NSNumber*) numberForKey:(id)key;
|
||||
|
||||
- (NSMutableDictionary*) dictionaryForKey:(id)key;
|
||||
|
||||
- (NSMutableArray*) arrayForKey:(id)key;
|
||||
|
||||
@end
|
||||
46
IOSBoilerplate/DictionaryHelper.m
Normal file
46
IOSBoilerplate/DictionaryHelper.m
Normal file
@@ -0,0 +1,46 @@
|
||||
//
|
||||
// DictionaryHelper.m
|
||||
// IOSBoilerplate
|
||||
//
|
||||
// Created by Alberto Gimeno Brieba on 08/09/11.
|
||||
// Copyright 2011 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "DictionaryHelper.h"
|
||||
|
||||
@implementation NSDictionary (helper)
|
||||
|
||||
- (NSString*) stringForKey:(id)key {
|
||||
id s = [self objectForKey:key];
|
||||
if (s == [NSNull null] || ![s isKindOfClass:[NSString class]]) {
|
||||
return nil;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
- (NSNumber*) numberForKey:(id)key {
|
||||
id s = [self objectForKey:key];
|
||||
if (s == [NSNull null] || ![s isKindOfClass:[NSNumber class]]) {
|
||||
return nil;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
- (NSMutableDictionary*) dictionaryForKey:(id)key {
|
||||
id s = [self objectForKey:key];
|
||||
if (s == [NSNull null] || ![s isKindOfClass:[NSMutableDictionary class]]) {
|
||||
return nil;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
- (NSMutableArray*) arrayForKey:(id)key {
|
||||
id s = [self objectForKey:key];
|
||||
if (s == [NSNull null] || ![s isKindOfClass:[NSMutableArray class]]) {
|
||||
return nil;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
19
IOSBoilerplate/FastCell.h
Normal file
19
IOSBoilerplate/FastCell.h
Normal file
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// FastCell.h
|
||||
// IOSBoilerplate
|
||||
//
|
||||
// Created by Alberto Gimeno Brieba on 08/09/11.
|
||||
// Copyright 2011 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface FastCell : UITableViewCell {
|
||||
|
||||
UIView* contentView;
|
||||
|
||||
}
|
||||
|
||||
- (void) drawContentView:(CGRect)r;
|
||||
|
||||
@end
|
||||
57
IOSBoilerplate/FastCell.m
Normal file
57
IOSBoilerplate/FastCell.m
Normal file
@@ -0,0 +1,57 @@
|
||||
//
|
||||
// FastCell.m
|
||||
// IOSBoilerplate
|
||||
//
|
||||
// Created by Alberto Gimeno Brieba on 08/09/11.
|
||||
// Copyright 2011 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "FastCell.h"
|
||||
|
||||
@interface ContentView : UIView
|
||||
@end
|
||||
|
||||
@implementation ContentView
|
||||
|
||||
- (void)drawRect:(CGRect)r
|
||||
{
|
||||
[(FastCell*)[self superview] drawContentView:r];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation FastCell
|
||||
|
||||
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
|
||||
if ((self = [super initWithStyle:style reuseIdentifier:reuseIdentifier])) {
|
||||
contentView = [[ContentView alloc] initWithFrame:CGRectZero];
|
||||
contentView.opaque = YES;
|
||||
[self addSubview:contentView];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[contentView removeFromSuperview];
|
||||
[contentView release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void)setFrame:(CGRect)f {
|
||||
[super setFrame:f];
|
||||
CGRect b = [self bounds];
|
||||
b.size.height -= 1; // leave room for the seperator line
|
||||
|
||||
[contentView setFrame:b];
|
||||
}
|
||||
|
||||
- (void)setNeedsDisplay {
|
||||
[super setNeedsDisplay];
|
||||
[contentView setNeedsDisplay];
|
||||
}
|
||||
|
||||
- (void)drawContentView:(CGRect)r {
|
||||
// subclasses should implement this
|
||||
}
|
||||
|
||||
@end
|
||||
17
IOSBoilerplate/HTTPHUDExample.h
Normal file
17
IOSBoilerplate/HTTPHUDExample.h
Normal file
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// HTTPHUDExample.h
|
||||
// IOSBoilerplate
|
||||
//
|
||||
// Created by Alberto Gimeno Brieba on 08/09/11.
|
||||
// Copyright 2011 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "BaseViewController.h"
|
||||
|
||||
@interface HTTPHUDExample : BaseViewController {
|
||||
|
||||
}
|
||||
|
||||
@property (nonatomic, retain) IBOutlet UILabel* label;
|
||||
|
||||
@end
|
||||
86
IOSBoilerplate/HTTPHUDExample.m
Normal file
86
IOSBoilerplate/HTTPHUDExample.m
Normal file
@@ -0,0 +1,86 @@
|
||||
//
|
||||
// HTTPHUDExample.m
|
||||
// IOSBoilerplate
|
||||
//
|
||||
// Created by Alberto Gimeno Brieba on 08/09/11.
|
||||
// Copyright 2011 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HTTPHUDExample.h"
|
||||
#import "SVProgressHUD.h"
|
||||
#import "JSONKit.h"
|
||||
#import "DictionaryHelper.h"
|
||||
|
||||
@implementation HTTPHUDExample
|
||||
|
||||
@synthesize label;
|
||||
|
||||
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
|
||||
{
|
||||
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
|
||||
if (self) {
|
||||
// Custom initialization
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)didReceiveMemoryWarning
|
||||
{
|
||||
// Releases the view if it doesn't have a superview.
|
||||
[super didReceiveMemoryWarning];
|
||||
|
||||
// Release any cached data, images, etc that aren't in use.
|
||||
}
|
||||
|
||||
#pragma mark - View lifecycle
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
self.title = @"HTTP + HUD + JSON parsing";
|
||||
label.text = @"Loading...";
|
||||
}
|
||||
|
||||
- (void)viewDidUnload
|
||||
{
|
||||
[super viewDidUnload];
|
||||
// Release any retained subviews of the main view.
|
||||
// e.g. self.myOutlet = nil;
|
||||
}
|
||||
|
||||
- (void)viewDidAppear:(BOOL)animated {
|
||||
[super viewDidAppear:animated];
|
||||
|
||||
[SVProgressHUD showInView:self.view];
|
||||
|
||||
// By using [self requestWithURL:@"..."]; the reques is cancelled if the user closes this view controller
|
||||
ASIHTTPRequest* request = [self requestWithURL:@"http://api.twitter.com/1/statuses/show.json?id=111529655042965504&include_entities=false"];
|
||||
[request setDidFinishSelector:@selector(requestFinished:)];
|
||||
[request setDidFailSelector:@selector(requestFailed:)];
|
||||
[request startAsynchronous];
|
||||
}
|
||||
|
||||
- (void)requestFinished:(ASIHTTPRequest*)request {
|
||||
[SVProgressHUD dismissWithSuccess:@"Ok!"];
|
||||
|
||||
NSDictionary* result = [[request responseString] objectFromJSONString];
|
||||
NSString* text = [result stringForKey:@"text"]; // method from DictionaryHelper
|
||||
label.text = text;
|
||||
}
|
||||
|
||||
- (void)requestFailed:(ASIHTTPRequest*)request {
|
||||
[SVProgressHUD dismissWithError:[[request error] localizedDescription]];
|
||||
}
|
||||
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
- (void)dealloc {
|
||||
[label release];
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@end
|
||||
216
IOSBoilerplate/HTTPHUDExample.xib
Normal file
216
IOSBoilerplate/HTTPHUDExample.xib
Normal file
@@ -0,0 +1,216 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<archive type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="7.10">
|
||||
<data>
|
||||
<int key="IBDocument.SystemTarget">1056</int>
|
||||
<string key="IBDocument.SystemVersion">11B26</string>
|
||||
<string key="IBDocument.InterfaceBuilderVersion">1617</string>
|
||||
<string key="IBDocument.AppKitVersion">1138</string>
|
||||
<string key="IBDocument.HIToolboxVersion">566.00</string>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string key="NS.object.0">534</string>
|
||||
</object>
|
||||
<object class="NSArray" key="IBDocument.IntegratedClassDependencies">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>IBProxyObject</string>
|
||||
<string>IBUIView</string>
|
||||
<string>IBUILabel</string>
|
||||
</object>
|
||||
<object class="NSArray" key="IBDocument.PluginDependencies">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="IBDocument.Metadata">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys" id="0">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
</object>
|
||||
<reference key="dict.values" ref="0"/>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBProxyObject" id="372490531">
|
||||
<string key="IBProxiedObjectIdentifier">IBFilesOwner</string>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
</object>
|
||||
<object class="IBProxyObject" id="975951072">
|
||||
<string key="IBProxiedObjectIdentifier">IBFirstResponder</string>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
</object>
|
||||
<object class="IBUIView" id="191373211">
|
||||
<reference key="NSNextResponder"/>
|
||||
<int key="NSvFlags">274</int>
|
||||
<object class="NSMutableArray" key="NSSubviews">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBUILabel" id="984153463">
|
||||
<reference key="NSNextResponder" ref="191373211"/>
|
||||
<int key="NSvFlags">274</int>
|
||||
<string key="NSFrame">{{20, 20}, {280, 420}}</string>
|
||||
<reference key="NSSuperview" ref="191373211"/>
|
||||
<reference key="NSWindow"/>
|
||||
<string key="NSReuseIdentifierKey">_NS:311</string>
|
||||
<bool key="IBUIOpaque">NO</bool>
|
||||
<bool key="IBUIClipsSubviews">YES</bool>
|
||||
<int key="IBUIContentMode">7</int>
|
||||
<bool key="IBUIUserInteractionEnabled">NO</bool>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
<string key="IBUIText">Label</string>
|
||||
<object class="NSColor" key="IBUITextColor">
|
||||
<int key="NSColorSpace">1</int>
|
||||
<bytes key="NSRGB">MCAwIDAAA</bytes>
|
||||
</object>
|
||||
<nil key="IBUIHighlightedColor"/>
|
||||
<int key="IBUIBaselineAdjustment">1</int>
|
||||
<float key="IBUIMinimumFontSize">10</float>
|
||||
<int key="IBUINumberOfLines">0</int>
|
||||
<int key="IBUITextAlignment">1</int>
|
||||
</object>
|
||||
</object>
|
||||
<string key="NSFrame">{{0, 20}, {320, 460}}</string>
|
||||
<reference key="NSSuperview"/>
|
||||
<reference key="NSWindow"/>
|
||||
<object class="NSColor" key="IBUIBackgroundColor">
|
||||
<int key="NSColorSpace">3</int>
|
||||
<bytes key="NSWhite">MQA</bytes>
|
||||
<object class="NSColorSpace" key="NSCustomColorSpace">
|
||||
<int key="NSID">2</int>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBUISimulatedStatusBarMetrics" key="IBUISimulatedStatusBarMetrics"/>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBObjectContainer" key="IBDocument.Objects">
|
||||
<object class="NSMutableArray" key="connectionRecords">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchOutletConnection" key="connection">
|
||||
<string key="label">view</string>
|
||||
<reference key="source" ref="372490531"/>
|
||||
<reference key="destination" ref="191373211"/>
|
||||
</object>
|
||||
<int key="connectionID">3</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchOutletConnection" key="connection">
|
||||
<string key="label">label</string>
|
||||
<reference key="source" ref="372490531"/>
|
||||
<reference key="destination" ref="984153463"/>
|
||||
</object>
|
||||
<int key="connectionID">5</int>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBMutableOrderedSet" key="objectRecords">
|
||||
<object class="NSArray" key="orderedObjects">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">0</int>
|
||||
<reference key="object" ref="0"/>
|
||||
<reference key="children" ref="1000"/>
|
||||
<nil key="parent"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">1</int>
|
||||
<reference key="object" ref="191373211"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="984153463"/>
|
||||
</object>
|
||||
<reference key="parent" ref="0"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">-1</int>
|
||||
<reference key="object" ref="372490531"/>
|
||||
<reference key="parent" ref="0"/>
|
||||
<string key="objectName">File's Owner</string>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">-2</int>
|
||||
<reference key="object" ref="975951072"/>
|
||||
<reference key="parent" ref="0"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">4</int>
|
||||
<reference key="object" ref="984153463"/>
|
||||
<reference key="parent" ref="191373211"/>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="flattenedProperties">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>-1.CustomClassName</string>
|
||||
<string>-1.IBPluginDependency</string>
|
||||
<string>-2.CustomClassName</string>
|
||||
<string>-2.IBPluginDependency</string>
|
||||
<string>1.IBPluginDependency</string>
|
||||
<string>4.IBPluginDependency</string>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>HTTPHUDExample</string>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string>UIResponder</string>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="unlocalizedProperties">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference key="dict.sortedKeys" ref="0"/>
|
||||
<reference key="dict.values" ref="0"/>
|
||||
</object>
|
||||
<nil key="activeLocalization"/>
|
||||
<object class="NSMutableDictionary" key="localizations">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference key="dict.sortedKeys" ref="0"/>
|
||||
<reference key="dict.values" ref="0"/>
|
||||
</object>
|
||||
<nil key="sourceID"/>
|
||||
<int key="maxID">5</int>
|
||||
</object>
|
||||
<object class="IBClassDescriber" key="IBDocument.Classes">
|
||||
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">BaseViewController</string>
|
||||
<string key="superclassName">UIViewController</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">./Classes/BaseViewController.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">HTTPHUDExample</string>
|
||||
<string key="superclassName">BaseViewController</string>
|
||||
<object class="NSMutableDictionary" key="outlets">
|
||||
<string key="NS.key.0">label</string>
|
||||
<string key="NS.object.0">UILabel</string>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="toOneOutletInfosByName">
|
||||
<string key="NS.key.0">label</string>
|
||||
<object class="IBToOneOutletInfo" key="NS.object.0">
|
||||
<string key="name">label</string>
|
||||
<string key="candidateClassName">UILabel</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">./Classes/HTTPHUDExample.h</string>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<int key="IBDocument.localizationMode">0</int>
|
||||
<string key="IBDocument.TargetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3</string>
|
||||
<integer value="3000" key="NS.object.0"/>
|
||||
</object>
|
||||
<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
|
||||
<int key="IBDocument.defaultPropertyAccessControl">3</int>
|
||||
<string key="IBCocoaTouchPluginVersion">534</string>
|
||||
</data>
|
||||
</archive>
|
||||
@@ -14,4 +14,6 @@
|
||||
|
||||
@property (nonatomic, retain) IBOutlet UINavigationController *navigationController;
|
||||
|
||||
+ (IOSBoilerplateAppDelegate*) sharedAppDelegate;
|
||||
|
||||
@end
|
||||
|
||||
@@ -7,12 +7,17 @@
|
||||
//
|
||||
|
||||
#import "IOSBoilerplateAppDelegate.h"
|
||||
#import "ImageManager.h"
|
||||
|
||||
@implementation IOSBoilerplateAppDelegate
|
||||
|
||||
@synthesize window = _window;
|
||||
@synthesize navigationController = _navigationController;
|
||||
|
||||
+ (IOSBoilerplateAppDelegate*) sharedAppDelegate {
|
||||
return (IOSBoilerplateAppDelegate*) [UIApplication sharedApplication].delegate;
|
||||
}
|
||||
|
||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
||||
{
|
||||
// Override point for customization after application launch.
|
||||
@@ -59,6 +64,11 @@
|
||||
Save data if appropriate.
|
||||
See also applicationDidEnterBackground:.
|
||||
*/
|
||||
[ImageManager releaseSingleton];
|
||||
}
|
||||
|
||||
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
|
||||
[ImageManager clearMemoryCache];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
|
||||
34
IOSBoilerplate/ImageManager.h
Normal file
34
IOSBoilerplate/ImageManager.h
Normal file
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// ImageManager.h
|
||||
// IOSBoilerplate
|
||||
//
|
||||
// Created by Alberto Gimeno Brieba on 08/09/11.
|
||||
// Copyright 2011 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "ASIDownloadCache.h"
|
||||
|
||||
@interface ImageManager : NSObject {
|
||||
|
||||
NSMutableArray* pendingImages;
|
||||
NSMutableDictionary* loadedImages;
|
||||
NSOperationQueue *downloadQueue;
|
||||
ASIDownloadCache *cache;
|
||||
|
||||
}
|
||||
|
||||
+ (UIImage*)loadImage:(NSURL *)url;
|
||||
- (UIImage*)loadImage:(NSURL *)url;
|
||||
|
||||
+ (void) clearMemoryCache;
|
||||
- (void) clearMemoryCache;
|
||||
|
||||
+ (void) clearCache;
|
||||
- (void) clearCache;
|
||||
|
||||
- (NSString*) cacheDirectory;
|
||||
|
||||
+ (void) releaseSingleton;
|
||||
|
||||
@end
|
||||
148
IOSBoilerplate/ImageManager.m
Normal file
148
IOSBoilerplate/ImageManager.m
Normal file
@@ -0,0 +1,148 @@
|
||||
//
|
||||
// ImageManager.m
|
||||
// IOSBoilerplate
|
||||
//
|
||||
// Created by Alberto Gimeno Brieba on 08/09/11.
|
||||
// Copyright 2011 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ImageManager.h"
|
||||
#import "ASIHTTPRequest.h"
|
||||
#import "IOSBoilerplateAppDelegate.h"
|
||||
|
||||
@implementation ImageManager
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
pendingImages = [[NSMutableArray alloc] initWithCapacity:10];
|
||||
loadedImages = [[NSMutableDictionary alloc] initWithCapacity:50];
|
||||
downloadQueue = [[NSOperationQueue alloc] init];
|
||||
[downloadQueue setMaxConcurrentOperationCount:3];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[pendingImages release];
|
||||
[loadedImages release];
|
||||
[downloadQueue release];
|
||||
[cache release];
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
static ImageManager *sharedSingleton;
|
||||
|
||||
+ (void)initialize {
|
||||
static BOOL initialized = NO;
|
||||
if(!initialized) {
|
||||
initialized = YES;
|
||||
sharedSingleton = [[ImageManager alloc] init];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString*) cacheDirectory {
|
||||
return [NSHomeDirectory() stringByAppendingString:@"/Library/Caches/images/"];
|
||||
}
|
||||
|
||||
+ (UIImage*)loadImage:(NSURL *)url {
|
||||
return [sharedSingleton loadImage:url];
|
||||
}
|
||||
|
||||
- (UIImage*)loadImage:(NSURL *)url {
|
||||
// NSLog(@"url = %@", url);
|
||||
UIImage* img = [loadedImages objectForKey:url];
|
||||
if (img) {
|
||||
return img;
|
||||
}
|
||||
|
||||
if ([pendingImages containsObject:url]) {
|
||||
// already being downloaded
|
||||
return nil;
|
||||
}
|
||||
|
||||
[pendingImages addObject:url];
|
||||
|
||||
ASIHTTPRequest *request = [[ASIHTTPRequest alloc] initWithURL:url];
|
||||
/*
|
||||
Here you can configure a cache system
|
||||
|
||||
if (!cache) {
|
||||
ASIDownloadCache* _cache = [[ASIDownloadCache alloc] init];
|
||||
self.cache = _cache;
|
||||
[_cache release];
|
||||
[cache setStoragePath:[self cacheDirectory]];
|
||||
}
|
||||
// [request setDownloadCache:cache];
|
||||
// [request setCachePolicy:ASIOnlyLoadIfNotCachedCachePolicy];
|
||||
// [request setCacheStoragePolicy:ASICachePermanentlyCacheStoragePolicy];
|
||||
|
||||
*/
|
||||
|
||||
[request setDelegate:self];
|
||||
[request setDidFinishSelector:@selector(imageDone:)];
|
||||
[request setDidFailSelector:@selector(imageWentWrong:)];
|
||||
[downloadQueue addOperation:request];
|
||||
[request release];
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)imageDone:(ASIHTTPRequest*)request {
|
||||
UIImage* image = [UIImage imageWithData:[request responseData]];
|
||||
if (!image) {
|
||||
return;
|
||||
}
|
||||
|
||||
// NSLog(@"image done. %@ cached = %d", request.url, [request didUseCachedResponse]);
|
||||
|
||||
[pendingImages removeObject:request.url];
|
||||
[loadedImages setObject:image forKey:request.url];
|
||||
|
||||
SEL selector = @selector(imageLoaded:withURL:);
|
||||
NSArray* viewControllers = nil;
|
||||
|
||||
IOSBoilerplateAppDelegate* delegate = [IOSBoilerplateAppDelegate sharedAppDelegate];
|
||||
// change this if your application is not based on a UINavigationController
|
||||
viewControllers = delegate.navigationController.viewControllers;
|
||||
|
||||
for (UIViewController* vc in viewControllers) {
|
||||
if ([vc respondsToSelector:selector]) {
|
||||
[vc performSelector:selector withObject:image withObject:request.url];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)imageWentWrong:(ASIHTTPRequest*)request {
|
||||
NSLog(@"image went wrong %@", [[request error] localizedDescription]);
|
||||
[pendingImages removeObject:request.url]; // TODO should not try to load the image again for a while
|
||||
}
|
||||
|
||||
+ (void) clearMemoryCache {
|
||||
[sharedSingleton clearMemoryCache];
|
||||
}
|
||||
|
||||
- (void) clearMemoryCache {
|
||||
[loadedImages removeAllObjects];
|
||||
[pendingImages removeAllObjects];
|
||||
}
|
||||
|
||||
+ (void) clearCache {
|
||||
[sharedSingleton clearCache];
|
||||
}
|
||||
|
||||
- (void) clearCache {
|
||||
NSFileManager* fs = [NSFileManager defaultManager];
|
||||
// BOOL b =
|
||||
[fs removeItemAtPath:[self cacheDirectory] error:NULL];
|
||||
|
||||
}
|
||||
|
||||
+ (void) releaseSingleton {
|
||||
[sharedSingleton release];
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
251
IOSBoilerplate/JSONKit.h
Normal file
251
IOSBoilerplate/JSONKit.h
Normal file
@@ -0,0 +1,251 @@
|
||||
//
|
||||
// JSONKit.h
|
||||
// http://github.com/johnezang/JSONKit
|
||||
// Dual licensed under either the terms of the BSD License, or alternatively
|
||||
// under the terms of the Apache License, Version 2.0, as specified below.
|
||||
//
|
||||
|
||||
/*
|
||||
Copyright (c) 2011, John Engelhart
|
||||
|
||||
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 of the Zang Industries 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
|
||||
OWNER 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2011 John Engelhart
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
#include <TargetConditionals.h>
|
||||
#include <AvailabilityMacros.h>
|
||||
|
||||
#ifdef __OBJC__
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSData.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSError.h>
|
||||
#import <Foundation/NSObjCRuntime.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#endif // __OBJC__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
// For Mac OS X < 10.5.
|
||||
#ifndef NSINTEGER_DEFINED
|
||||
#define NSINTEGER_DEFINED
|
||||
#if defined(__LP64__) || defined(NS_BUILD_32_LIKE_64)
|
||||
typedef long NSInteger;
|
||||
typedef unsigned long NSUInteger;
|
||||
#define NSIntegerMin LONG_MIN
|
||||
#define NSIntegerMax LONG_MAX
|
||||
#define NSUIntegerMax ULONG_MAX
|
||||
#else // defined(__LP64__) || defined(NS_BUILD_32_LIKE_64)
|
||||
typedef int NSInteger;
|
||||
typedef unsigned int NSUInteger;
|
||||
#define NSIntegerMin INT_MIN
|
||||
#define NSIntegerMax INT_MAX
|
||||
#define NSUIntegerMax UINT_MAX
|
||||
#endif // defined(__LP64__) || defined(NS_BUILD_32_LIKE_64)
|
||||
#endif // NSINTEGER_DEFINED
|
||||
|
||||
|
||||
#ifndef _JSONKIT_H_
|
||||
#define _JSONKIT_H_
|
||||
|
||||
#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__APPLE_CC__) && (__APPLE_CC__ >= 5465)
|
||||
#define JK_DEPRECATED_ATTRIBUTE __attribute__((deprecated))
|
||||
#else
|
||||
#define JK_DEPRECATED_ATTRIBUTE
|
||||
#endif
|
||||
|
||||
#define JSONKIT_VERSION_MAJOR 1
|
||||
#define JSONKIT_VERSION_MINOR 4
|
||||
|
||||
typedef NSUInteger JKFlags;
|
||||
|
||||
/*
|
||||
JKParseOptionComments : Allow C style // and /_* ... *_/ (without a _, obviously) comments in JSON.
|
||||
JKParseOptionUnicodeNewlines : Allow Unicode recommended (?:\r\n|[\n\v\f\r\x85\p{Zl}\p{Zp}]) newlines.
|
||||
JKParseOptionLooseUnicode : Normally the decoder will stop with an error at any malformed Unicode.
|
||||
This option allows JSON with malformed Unicode to be parsed without reporting an error.
|
||||
Any malformed Unicode is replaced with \uFFFD, or "REPLACEMENT CHARACTER".
|
||||
*/
|
||||
|
||||
enum {
|
||||
JKParseOptionNone = 0,
|
||||
JKParseOptionStrict = 0,
|
||||
JKParseOptionComments = (1 << 0),
|
||||
JKParseOptionUnicodeNewlines = (1 << 1),
|
||||
JKParseOptionLooseUnicode = (1 << 2),
|
||||
JKParseOptionPermitTextAfterValidJSON = (1 << 3),
|
||||
JKParseOptionValidFlags = (JKParseOptionComments | JKParseOptionUnicodeNewlines | JKParseOptionLooseUnicode | JKParseOptionPermitTextAfterValidJSON),
|
||||
};
|
||||
typedef JKFlags JKParseOptionFlags;
|
||||
|
||||
enum {
|
||||
JKSerializeOptionNone = 0,
|
||||
JKSerializeOptionPretty = (1 << 0),
|
||||
JKSerializeOptionEscapeUnicode = (1 << 1),
|
||||
JKSerializeOptionEscapeForwardSlashes = (1 << 4),
|
||||
JKSerializeOptionValidFlags = (JKSerializeOptionPretty | JKSerializeOptionEscapeUnicode | JKSerializeOptionEscapeForwardSlashes),
|
||||
};
|
||||
typedef JKFlags JKSerializeOptionFlags;
|
||||
|
||||
#ifdef __OBJC__
|
||||
|
||||
typedef struct JKParseState JKParseState; // Opaque internal, private type.
|
||||
|
||||
// As a general rule of thumb, if you use a method that doesn't accept a JKParseOptionFlags argument, it defaults to JKParseOptionStrict
|
||||
|
||||
@interface JSONDecoder : NSObject {
|
||||
JKParseState *parseState;
|
||||
}
|
||||
+ (id)decoder;
|
||||
+ (id)decoderWithParseOptions:(JKParseOptionFlags)parseOptionFlags;
|
||||
- (id)initWithParseOptions:(JKParseOptionFlags)parseOptionFlags;
|
||||
- (void)clearCache;
|
||||
|
||||
// The parse... methods were deprecated in v1.4 in favor of the v1.4 objectWith... methods.
|
||||
- (id)parseUTF8String:(const unsigned char *)string length:(size_t)length JK_DEPRECATED_ATTRIBUTE; // Deprecated in JSONKit v1.4. Use objectWithUTF8String:length: instead.
|
||||
- (id)parseUTF8String:(const unsigned char *)string length:(size_t)length error:(NSError **)error JK_DEPRECATED_ATTRIBUTE; // Deprecated in JSONKit v1.4. Use objectWithUTF8String:length:error: instead.
|
||||
// The NSData MUST be UTF8 encoded JSON.
|
||||
- (id)parseJSONData:(NSData *)jsonData JK_DEPRECATED_ATTRIBUTE; // Deprecated in JSONKit v1.4. Use objectWithData: instead.
|
||||
- (id)parseJSONData:(NSData *)jsonData error:(NSError **)error JK_DEPRECATED_ATTRIBUTE; // Deprecated in JSONKit v1.4. Use objectWithData:error: instead.
|
||||
|
||||
// Methods that return immutable collection objects.
|
||||
- (id)objectWithUTF8String:(const unsigned char *)string length:(NSUInteger)length;
|
||||
- (id)objectWithUTF8String:(const unsigned char *)string length:(NSUInteger)length error:(NSError **)error;
|
||||
// The NSData MUST be UTF8 encoded JSON.
|
||||
- (id)objectWithData:(NSData *)jsonData;
|
||||
- (id)objectWithData:(NSData *)jsonData error:(NSError **)error;
|
||||
|
||||
// Methods that return mutable collection objects.
|
||||
- (id)mutableObjectWithUTF8String:(const unsigned char *)string length:(NSUInteger)length;
|
||||
- (id)mutableObjectWithUTF8String:(const unsigned char *)string length:(NSUInteger)length error:(NSError **)error;
|
||||
// The NSData MUST be UTF8 encoded JSON.
|
||||
- (id)mutableObjectWithData:(NSData *)jsonData;
|
||||
- (id)mutableObjectWithData:(NSData *)jsonData error:(NSError **)error;
|
||||
|
||||
@end
|
||||
|
||||
////////////
|
||||
#pragma mark Deserializing methods
|
||||
////////////
|
||||
|
||||
@interface NSString (JSONKitDeserializing)
|
||||
- (id)objectFromJSONString;
|
||||
- (id)objectFromJSONStringWithParseOptions:(JKParseOptionFlags)parseOptionFlags;
|
||||
- (id)objectFromJSONStringWithParseOptions:(JKParseOptionFlags)parseOptionFlags error:(NSError **)error;
|
||||
- (id)mutableObjectFromJSONString;
|
||||
- (id)mutableObjectFromJSONStringWithParseOptions:(JKParseOptionFlags)parseOptionFlags;
|
||||
- (id)mutableObjectFromJSONStringWithParseOptions:(JKParseOptionFlags)parseOptionFlags error:(NSError **)error;
|
||||
@end
|
||||
|
||||
@interface NSData (JSONKitDeserializing)
|
||||
// The NSData MUST be UTF8 encoded JSON.
|
||||
- (id)objectFromJSONData;
|
||||
- (id)objectFromJSONDataWithParseOptions:(JKParseOptionFlags)parseOptionFlags;
|
||||
- (id)objectFromJSONDataWithParseOptions:(JKParseOptionFlags)parseOptionFlags error:(NSError **)error;
|
||||
- (id)mutableObjectFromJSONData;
|
||||
- (id)mutableObjectFromJSONDataWithParseOptions:(JKParseOptionFlags)parseOptionFlags;
|
||||
- (id)mutableObjectFromJSONDataWithParseOptions:(JKParseOptionFlags)parseOptionFlags error:(NSError **)error;
|
||||
@end
|
||||
|
||||
////////////
|
||||
#pragma mark Serializing methods
|
||||
////////////
|
||||
|
||||
@interface NSString (JSONKitSerializing)
|
||||
// Convenience methods for those that need to serialize the receiving NSString (i.e., instead of having to serialize a NSArray with a single NSString, you can "serialize to JSON" just the NSString).
|
||||
// Normally, a string that is serialized to JSON has quotation marks surrounding it, which you may or may not want when serializing a single string, and can be controlled with includeQuotes:
|
||||
// includeQuotes:YES `a "test"...` -> `"a \"test\"..."`
|
||||
// includeQuotes:NO `a "test"...` -> `a \"test\"...`
|
||||
- (NSData *)JSONData; // Invokes JSONDataWithOptions:JKSerializeOptionNone includeQuotes:YES
|
||||
- (NSData *)JSONDataWithOptions:(JKSerializeOptionFlags)serializeOptions includeQuotes:(BOOL)includeQuotes error:(NSError **)error;
|
||||
- (NSString *)JSONString; // Invokes JSONStringWithOptions:JKSerializeOptionNone includeQuotes:YES
|
||||
- (NSString *)JSONStringWithOptions:(JKSerializeOptionFlags)serializeOptions includeQuotes:(BOOL)includeQuotes error:(NSError **)error;
|
||||
@end
|
||||
|
||||
@interface NSArray (JSONKitSerializing)
|
||||
- (NSData *)JSONData;
|
||||
- (NSData *)JSONDataWithOptions:(JKSerializeOptionFlags)serializeOptions error:(NSError **)error;
|
||||
- (NSData *)JSONDataWithOptions:(JKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingDelegate:(id)delegate selector:(SEL)selector error:(NSError **)error;
|
||||
- (NSString *)JSONString;
|
||||
- (NSString *)JSONStringWithOptions:(JKSerializeOptionFlags)serializeOptions error:(NSError **)error;
|
||||
- (NSString *)JSONStringWithOptions:(JKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingDelegate:(id)delegate selector:(SEL)selector error:(NSError **)error;
|
||||
@end
|
||||
|
||||
@interface NSDictionary (JSONKitSerializing)
|
||||
- (NSData *)JSONData;
|
||||
- (NSData *)JSONDataWithOptions:(JKSerializeOptionFlags)serializeOptions error:(NSError **)error;
|
||||
- (NSData *)JSONDataWithOptions:(JKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingDelegate:(id)delegate selector:(SEL)selector error:(NSError **)error;
|
||||
- (NSString *)JSONString;
|
||||
- (NSString *)JSONStringWithOptions:(JKSerializeOptionFlags)serializeOptions error:(NSError **)error;
|
||||
- (NSString *)JSONStringWithOptions:(JKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingDelegate:(id)delegate selector:(SEL)selector error:(NSError **)error;
|
||||
@end
|
||||
|
||||
#ifdef __BLOCKS__
|
||||
|
||||
@interface NSArray (JSONKitSerializingBlockAdditions)
|
||||
- (NSData *)JSONDataWithOptions:(JKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingBlock:(id(^)(id object))block error:(NSError **)error;
|
||||
- (NSString *)JSONStringWithOptions:(JKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingBlock:(id(^)(id object))block error:(NSError **)error;
|
||||
@end
|
||||
|
||||
@interface NSDictionary (JSONKitSerializingBlockAdditions)
|
||||
- (NSData *)JSONDataWithOptions:(JKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingBlock:(id(^)(id object))block error:(NSError **)error;
|
||||
- (NSString *)JSONStringWithOptions:(JKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingBlock:(id(^)(id object))block error:(NSError **)error;
|
||||
@end
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif // __OBJC__
|
||||
|
||||
#endif // _JSONKIT_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
3022
IOSBoilerplate/JSONKit.m
Normal file
3022
IOSBoilerplate/JSONKit.m
Normal file
File diff suppressed because it is too large
Load Diff
194
IOSBoilerplate/Reachability/Reachability.h
Normal file
194
IOSBoilerplate/Reachability/Reachability.h
Normal file
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
|
||||
File: Reachability.h
|
||||
Abstract: Basic demonstration of how to use the SystemConfiguration Reachablity APIs.
|
||||
|
||||
Version: 2.0.4ddg
|
||||
*/
|
||||
|
||||
/*
|
||||
Significant additions made by Andrew W. Donoho, August 11, 2009.
|
||||
This is a derived work of Apple's Reachability v2.0 class.
|
||||
|
||||
The below license is the new BSD license with the OSI recommended personalizations.
|
||||
<http://www.opensource.org/licenses/bsd-license.php>
|
||||
|
||||
Extensions Copyright (C) 2009 Donoho Design Group, LLC. 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 of Andrew W. Donoho nor Donoho Design Group, L.L.C.
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY DONOHO DESIGN GROUP, L.L.C. "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.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
|
||||
Apple's Original License on Reachability v2.0
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc.
|
||||
("Apple") in consideration of your agreement to the following terms, and your
|
||||
use, installation, modification or redistribution of this Apple software
|
||||
constitutes acceptance of these terms. If you do not agree with these terms,
|
||||
please do not use, install, modify or redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and subject
|
||||
to these terms, Apple grants you a personal, non-exclusive license, under
|
||||
Apple's copyrights in this original Apple software (the "Apple Software"), to
|
||||
use, reproduce, modify and redistribute the Apple Software, with or without
|
||||
modifications, in source and/or binary forms; provided that if you redistribute
|
||||
the Apple Software in its entirety and without modifications, you must retain
|
||||
this notice and the following text and disclaimers in all such redistributions
|
||||
of the Apple Software.
|
||||
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may be used
|
||||
to endorse or promote products derived from the Apple Software without specific
|
||||
prior written permission from Apple. Except as expressly stated in this notice,
|
||||
no other rights or licenses, express or implied, are granted by Apple herein,
|
||||
including but not limited to any patent rights that may be infringed by your
|
||||
derivative works or by other works in which the Apple Software may be
|
||||
incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
|
||||
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
|
||||
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
|
||||
COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR
|
||||
DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF
|
||||
CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
|
||||
APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2009 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
DDG extensions include:
|
||||
Each reachability object now has a copy of the key used to store it in a
|
||||
dictionary. This allows each observer to quickly determine if the event is
|
||||
important to them.
|
||||
|
||||
-currentReachabilityStatus also has a significantly different decision criteria than
|
||||
Apple's code.
|
||||
|
||||
A multiple convenience test methods have been added.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <SystemConfiguration/SystemConfiguration.h>
|
||||
#import <netinet/in.h>
|
||||
|
||||
#define USE_DDG_EXTENSIONS 1 // Use DDG's Extensions to test network criteria.
|
||||
// Since NSAssert and NSCAssert are used in this code,
|
||||
// I recommend you set NS_BLOCK_ASSERTIONS=1 in the release versions of your projects.
|
||||
|
||||
enum {
|
||||
|
||||
// DDG NetworkStatus Constant Names.
|
||||
kNotReachable = 0, // Apple's code depends upon 'NotReachable' being the same value as 'NO'.
|
||||
kReachableViaWWAN, // Switched order from Apple's enum. WWAN is active before WiFi.
|
||||
kReachableViaWiFi
|
||||
|
||||
};
|
||||
typedef uint32_t NetworkStatus;
|
||||
|
||||
enum {
|
||||
|
||||
// Apple NetworkStatus Constant Names.
|
||||
NotReachable = kNotReachable,
|
||||
ReachableViaWiFi = kReachableViaWiFi,
|
||||
ReachableViaWWAN = kReachableViaWWAN
|
||||
|
||||
};
|
||||
|
||||
|
||||
extern NSString *const kInternetConnection;
|
||||
extern NSString *const kLocalWiFiConnection;
|
||||
extern NSString *const kReachabilityChangedNotification;
|
||||
|
||||
@interface Reachability: NSObject {
|
||||
|
||||
@private
|
||||
NSString *key_;
|
||||
SCNetworkReachabilityRef reachabilityRef;
|
||||
|
||||
}
|
||||
|
||||
@property (copy) NSString *key; // Atomic because network operations are asynchronous.
|
||||
|
||||
// Designated Initializer.
|
||||
- (Reachability *) initWithReachabilityRef: (SCNetworkReachabilityRef) ref;
|
||||
|
||||
// Use to check the reachability of a particular host name.
|
||||
+ (Reachability *) reachabilityWithHostName: (NSString*) hostName;
|
||||
|
||||
// Use to check the reachability of a particular IP address.
|
||||
+ (Reachability *) reachabilityWithAddress: (const struct sockaddr_in*) hostAddress;
|
||||
|
||||
// Use to check whether the default route is available.
|
||||
// Should be used to, at minimum, establish network connectivity.
|
||||
+ (Reachability *) reachabilityForInternetConnection;
|
||||
|
||||
// Use to check whether a local wifi connection is available.
|
||||
+ (Reachability *) reachabilityForLocalWiFi;
|
||||
|
||||
//Start listening for reachability notifications on the current run loop.
|
||||
- (BOOL) startNotifier;
|
||||
- (void) stopNotifier;
|
||||
|
||||
// Comparison routines to enable choosing actions in a notification.
|
||||
- (BOOL) isEqual: (Reachability *) r;
|
||||
|
||||
// These are the status tests.
|
||||
- (NetworkStatus) currentReachabilityStatus;
|
||||
|
||||
// The main direct test of reachability.
|
||||
- (BOOL) isReachable;
|
||||
|
||||
// WWAN may be available, but not active until a connection has been established.
|
||||
// WiFi may require a connection for VPN on Demand.
|
||||
- (BOOL) isConnectionRequired; // Identical DDG variant.
|
||||
- (BOOL) connectionRequired; // Apple's routine.
|
||||
|
||||
// Dynamic, on demand connection?
|
||||
- (BOOL) isConnectionOnDemand;
|
||||
|
||||
// Is user intervention required?
|
||||
- (BOOL) isInterventionRequired;
|
||||
|
||||
// Routines for specific connection testing by your app.
|
||||
- (BOOL) isReachableViaWWAN;
|
||||
- (BOOL) isReachableViaWiFi;
|
||||
|
||||
- (SCNetworkReachabilityFlags) reachabilityFlags;
|
||||
|
||||
@end
|
||||
814
IOSBoilerplate/Reachability/Reachability.m
Normal file
814
IOSBoilerplate/Reachability/Reachability.m
Normal file
@@ -0,0 +1,814 @@
|
||||
/*
|
||||
|
||||
File: Reachability.m
|
||||
Abstract: Basic demonstration of how to use the SystemConfiguration Reachablity APIs.
|
||||
|
||||
Version: 2.0.4ddg
|
||||
*/
|
||||
|
||||
/*
|
||||
Significant additions made by Andrew W. Donoho, August 11, 2009.
|
||||
This is a derived work of Apple's Reachability v2.0 class.
|
||||
|
||||
The below license is the new BSD license with the OSI recommended personalizations.
|
||||
<http://www.opensource.org/licenses/bsd-license.php>
|
||||
|
||||
Extensions Copyright (C) 2009 Donoho Design Group, LLC. 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 of Andrew W. Donoho nor Donoho Design Group, L.L.C.
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY DONOHO DESIGN GROUP, L.L.C. "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.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
|
||||
Apple's Original License on Reachability v2.0
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc.
|
||||
("Apple") in consideration of your agreement to the following terms, and your
|
||||
use, installation, modification or redistribution of this Apple software
|
||||
constitutes acceptance of these terms. If you do not agree with these terms,
|
||||
please do not use, install, modify or redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and subject
|
||||
to these terms, Apple grants you a personal, non-exclusive license, under
|
||||
Apple's copyrights in this original Apple software (the "Apple Software"), to
|
||||
use, reproduce, modify and redistribute the Apple Software, with or without
|
||||
modifications, in source and/or binary forms; provided that if you redistribute
|
||||
the Apple Software in its entirety and without modifications, you must retain
|
||||
this notice and the following text and disclaimers in all such redistributions
|
||||
of the Apple Software.
|
||||
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may be used
|
||||
to endorse or promote products derived from the Apple Software without specific
|
||||
prior written permission from Apple. Except as expressly stated in this notice,
|
||||
no other rights or licenses, express or implied, are granted by Apple herein,
|
||||
including but not limited to any patent rights that may be infringed by your
|
||||
derivative works or by other works in which the Apple Software may be
|
||||
incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
|
||||
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
|
||||
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
|
||||
COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR
|
||||
DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF
|
||||
CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
|
||||
APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2009 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
Each reachability object now has a copy of the key used to store it in a dictionary.
|
||||
This allows each observer to quickly determine if the event is important to them.
|
||||
*/
|
||||
|
||||
#import <sys/socket.h>
|
||||
#import <netinet/in.h>
|
||||
#import <netinet6/in6.h>
|
||||
#import <arpa/inet.h>
|
||||
#import <ifaddrs.h>
|
||||
#import <netdb.h>
|
||||
|
||||
#import <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
#import "Reachability.h"
|
||||
|
||||
NSString *const kInternetConnection = @"InternetConnection";
|
||||
NSString *const kLocalWiFiConnection = @"LocalWiFiConnection";
|
||||
NSString *const kReachabilityChangedNotification = @"NetworkReachabilityChangedNotification";
|
||||
|
||||
#define CLASS_DEBUG 1 // Turn on logReachabilityFlags. Must also have a project wide defined DEBUG.
|
||||
|
||||
#if (defined DEBUG && defined CLASS_DEBUG)
|
||||
#define logReachabilityFlags(flags) (logReachabilityFlags_(__PRETTY_FUNCTION__, __LINE__, flags))
|
||||
|
||||
static NSString *reachabilityFlags_(SCNetworkReachabilityFlags flags) {
|
||||
|
||||
#if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 30000) // Apple advises you to use the magic number instead of a symbol.
|
||||
return [NSString stringWithFormat:@"Reachability Flags: %c%c %c%c%c%c%c%c%c",
|
||||
(flags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsReachable) ? 'R' : '-',
|
||||
|
||||
(flags & kSCNetworkReachabilityFlagsConnectionRequired) ? 'c' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsTransientConnection) ? 't' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) ? 'C' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsConnectionOnDemand) ? 'D' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsIsLocalAddress) ? 'l' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsIsDirect) ? 'd' : '-'];
|
||||
#else
|
||||
// Compile out the v3.0 features for v2.2.1 deployment.
|
||||
return [NSString stringWithFormat:@"Reachability Flags: %c%c %c%c%c%c%c%c",
|
||||
(flags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsReachable) ? 'R' : '-',
|
||||
|
||||
(flags & kSCNetworkReachabilityFlagsConnectionRequired) ? 'c' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsTransientConnection) ? 't' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-',
|
||||
// v3 kSCNetworkReachabilityFlagsConnectionOnTraffic == v2 kSCNetworkReachabilityFlagsConnectionAutomatic
|
||||
(flags & kSCNetworkReachabilityFlagsConnectionAutomatic) ? 'C' : '-',
|
||||
// (flags & kSCNetworkReachabilityFlagsConnectionOnDemand) ? 'D' : '-', // No v2 equivalent.
|
||||
(flags & kSCNetworkReachabilityFlagsIsLocalAddress) ? 'l' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsIsDirect) ? 'd' : '-'];
|
||||
#endif
|
||||
|
||||
} // reachabilityFlags_()
|
||||
|
||||
static void logReachabilityFlags_(const char *name, int line, SCNetworkReachabilityFlags flags) {
|
||||
|
||||
NSLog(@"%s (%d) \n\t%@", name, line, reachabilityFlags_(flags));
|
||||
|
||||
} // logReachabilityFlags_()
|
||||
|
||||
#define logNetworkStatus(status) (logNetworkStatus_(__PRETTY_FUNCTION__, __LINE__, status))
|
||||
|
||||
static void logNetworkStatus_(const char *name, int line, NetworkStatus status) {
|
||||
|
||||
NSString *statusString = nil;
|
||||
|
||||
switch (status) {
|
||||
case kNotReachable:
|
||||
statusString = [NSString stringWithString: @"Not Reachable"];
|
||||
break;
|
||||
case kReachableViaWWAN:
|
||||
statusString = [NSString stringWithString: @"Reachable via WWAN"];
|
||||
break;
|
||||
case kReachableViaWiFi:
|
||||
statusString = [NSString stringWithString: @"Reachable via WiFi"];
|
||||
break;
|
||||
}
|
||||
|
||||
NSLog(@"%s (%d) \n\tNetwork Status: %@", name, line, statusString);
|
||||
|
||||
} // logNetworkStatus_()
|
||||
|
||||
#else
|
||||
#define logReachabilityFlags(flags)
|
||||
#define logNetworkStatus(status)
|
||||
#endif
|
||||
|
||||
@interface Reachability (private)
|
||||
|
||||
- (NetworkStatus) networkStatusForFlags: (SCNetworkReachabilityFlags) flags;
|
||||
|
||||
@end
|
||||
|
||||
@implementation Reachability
|
||||
|
||||
@synthesize key = key_;
|
||||
|
||||
// Preclude direct access to ivars.
|
||||
+ (BOOL) accessInstanceVariablesDirectly {
|
||||
|
||||
return NO;
|
||||
|
||||
} // accessInstanceVariablesDirectly
|
||||
|
||||
|
||||
- (void) dealloc {
|
||||
|
||||
[self stopNotifier];
|
||||
if(reachabilityRef) {
|
||||
|
||||
CFRelease(reachabilityRef); reachabilityRef = NULL;
|
||||
|
||||
}
|
||||
|
||||
self.key = nil;
|
||||
|
||||
[super dealloc];
|
||||
|
||||
} // dealloc
|
||||
|
||||
|
||||
- (Reachability *) initWithReachabilityRef: (SCNetworkReachabilityRef) ref
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
reachabilityRef = ref;
|
||||
}
|
||||
|
||||
return self;
|
||||
|
||||
} // initWithReachabilityRef:
|
||||
|
||||
|
||||
#if (defined DEBUG && defined CLASS_DEBUG)
|
||||
- (NSString *) description {
|
||||
|
||||
NSAssert(reachabilityRef, @"-description called with NULL reachabilityRef");
|
||||
|
||||
SCNetworkReachabilityFlags flags = 0;
|
||||
|
||||
SCNetworkReachabilityGetFlags(reachabilityRef, &flags);
|
||||
|
||||
return [NSString stringWithFormat: @"%@\n\t%@", self.key, reachabilityFlags_(flags)];
|
||||
|
||||
} // description
|
||||
#endif
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Notification Management Methods
|
||||
|
||||
|
||||
//Start listening for reachability notifications on the current run loop
|
||||
static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info) {
|
||||
|
||||
#pragma unused (target, flags)
|
||||
NSCAssert(info, @"info was NULL in ReachabilityCallback");
|
||||
NSCAssert([(NSObject*) info isKindOfClass: [Reachability class]], @"info was the wrong class in ReachabilityCallback");
|
||||
|
||||
//We're on the main RunLoop, so an NSAutoreleasePool is not necessary, but is added defensively
|
||||
// in case someone uses the Reachablity object in a different thread.
|
||||
NSAutoreleasePool* pool = [NSAutoreleasePool new];
|
||||
|
||||
// Post a notification to notify the client that the network reachability changed.
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName: kReachabilityChangedNotification
|
||||
object: (Reachability *) info];
|
||||
|
||||
[pool release];
|
||||
|
||||
} // ReachabilityCallback()
|
||||
|
||||
|
||||
- (BOOL) startNotifier {
|
||||
|
||||
SCNetworkReachabilityContext context = {0, self, NULL, NULL, NULL};
|
||||
|
||||
if(SCNetworkReachabilitySetCallback(reachabilityRef, ReachabilityCallback, &context)) {
|
||||
|
||||
if(SCNetworkReachabilityScheduleWithRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) {
|
||||
|
||||
return YES;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return NO;
|
||||
|
||||
} // startNotifier
|
||||
|
||||
|
||||
- (void) stopNotifier {
|
||||
|
||||
if(reachabilityRef) {
|
||||
|
||||
SCNetworkReachabilityUnscheduleFromRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
||||
|
||||
}
|
||||
|
||||
} // stopNotifier
|
||||
|
||||
|
||||
- (BOOL) isEqual: (Reachability *) r {
|
||||
|
||||
return [r.key isEqualToString: self.key];
|
||||
|
||||
} // isEqual:
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Reachability Allocation Methods
|
||||
|
||||
|
||||
+ (Reachability *) reachabilityWithHostName: (NSString *) hostName {
|
||||
|
||||
SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]);
|
||||
|
||||
if (ref) {
|
||||
|
||||
Reachability *r = [[[self alloc] initWithReachabilityRef: ref] autorelease];
|
||||
|
||||
r.key = hostName;
|
||||
|
||||
return r;
|
||||
|
||||
}
|
||||
|
||||
return nil;
|
||||
|
||||
} // reachabilityWithHostName
|
||||
|
||||
|
||||
+ (NSString *) makeAddressKey: (in_addr_t) addr {
|
||||
// addr is assumed to be in network byte order.
|
||||
|
||||
static const int highShift = 24;
|
||||
static const int highMidShift = 16;
|
||||
static const int lowMidShift = 8;
|
||||
static const in_addr_t mask = 0x000000ff;
|
||||
|
||||
addr = ntohl(addr);
|
||||
|
||||
return [NSString stringWithFormat: @"%d.%d.%d.%d",
|
||||
(addr >> highShift) & mask,
|
||||
(addr >> highMidShift) & mask,
|
||||
(addr >> lowMidShift) & mask,
|
||||
addr & mask];
|
||||
|
||||
} // makeAddressKey:
|
||||
|
||||
|
||||
+ (Reachability *) reachabilityWithAddress: (const struct sockaddr_in *) hostAddress {
|
||||
|
||||
SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr*)hostAddress);
|
||||
|
||||
if (ref) {
|
||||
|
||||
Reachability *r = [[[self alloc] initWithReachabilityRef: ref] autorelease];
|
||||
|
||||
r.key = [self makeAddressKey: hostAddress->sin_addr.s_addr];
|
||||
|
||||
return r;
|
||||
|
||||
}
|
||||
|
||||
return nil;
|
||||
|
||||
} // reachabilityWithAddress
|
||||
|
||||
|
||||
+ (Reachability *) reachabilityForInternetConnection {
|
||||
|
||||
struct sockaddr_in zeroAddress;
|
||||
bzero(&zeroAddress, sizeof(zeroAddress));
|
||||
zeroAddress.sin_len = sizeof(zeroAddress);
|
||||
zeroAddress.sin_family = AF_INET;
|
||||
|
||||
Reachability *r = [self reachabilityWithAddress: &zeroAddress];
|
||||
|
||||
r.key = kInternetConnection;
|
||||
|
||||
return r;
|
||||
|
||||
} // reachabilityForInternetConnection
|
||||
|
||||
|
||||
+ (Reachability *) reachabilityForLocalWiFi {
|
||||
|
||||
struct sockaddr_in localWifiAddress;
|
||||
bzero(&localWifiAddress, sizeof(localWifiAddress));
|
||||
localWifiAddress.sin_len = sizeof(localWifiAddress);
|
||||
localWifiAddress.sin_family = AF_INET;
|
||||
// IN_LINKLOCALNETNUM is defined in <netinet/in.h> as 169.254.0.0
|
||||
localWifiAddress.sin_addr.s_addr = htonl(IN_LINKLOCALNETNUM);
|
||||
|
||||
Reachability *r = [self reachabilityWithAddress: &localWifiAddress];
|
||||
|
||||
r.key = kLocalWiFiConnection;
|
||||
|
||||
return r;
|
||||
|
||||
} // reachabilityForLocalWiFi
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Network Flag Handling Methods
|
||||
|
||||
|
||||
#if USE_DDG_EXTENSIONS
|
||||
//
|
||||
// iPhone condition codes as reported by a 3GS running iPhone OS v3.0.
|
||||
// Airplane Mode turned on: Reachability Flag Status: -- -------
|
||||
// WWAN Active: Reachability Flag Status: WR -t-----
|
||||
// WWAN Connection required: Reachability Flag Status: WR ct-----
|
||||
// WiFi turned on: Reachability Flag Status: -R ------- Reachable.
|
||||
// Local WiFi turned on: Reachability Flag Status: -R xxxxxxd Reachable.
|
||||
// WiFi turned on: Reachability Flag Status: -R ct----- Connection down. (Non-intuitive, empirically determined answer.)
|
||||
const SCNetworkReachabilityFlags kConnectionDown = kSCNetworkReachabilityFlagsConnectionRequired |
|
||||
kSCNetworkReachabilityFlagsTransientConnection;
|
||||
// WiFi turned on: Reachability Flag Status: -R ct-i--- Reachable but it will require user intervention (e.g. enter a WiFi password).
|
||||
// WiFi turned on: Reachability Flag Status: -R -t----- Reachable via VPN.
|
||||
//
|
||||
// In the below method, an 'x' in the flag status means I don't care about its value.
|
||||
//
|
||||
// This method differs from Apple's by testing explicitly for empirically observed values.
|
||||
// This gives me more confidence in it's correct behavior. Apple's code covers more cases
|
||||
// than mine. My code covers the cases that occur.
|
||||
//
|
||||
- (NetworkStatus) networkStatusForFlags: (SCNetworkReachabilityFlags) flags {
|
||||
|
||||
if (flags & kSCNetworkReachabilityFlagsReachable) {
|
||||
|
||||
// Local WiFi -- Test derived from Apple's code: -localWiFiStatusForFlags:.
|
||||
if (self.key == kLocalWiFiConnection) {
|
||||
|
||||
// Reachability Flag Status: xR xxxxxxd Reachable.
|
||||
return (flags & kSCNetworkReachabilityFlagsIsDirect) ? kReachableViaWiFi : kNotReachable;
|
||||
|
||||
}
|
||||
|
||||
// Observed WWAN Values:
|
||||
// WWAN Active: Reachability Flag Status: WR -t-----
|
||||
// WWAN Connection required: Reachability Flag Status: WR ct-----
|
||||
//
|
||||
// Test Value: Reachability Flag Status: WR xxxxxxx
|
||||
if (flags & kSCNetworkReachabilityFlagsIsWWAN) { return kReachableViaWWAN; }
|
||||
|
||||
// Clear moot bits.
|
||||
flags &= ~kSCNetworkReachabilityFlagsReachable;
|
||||
flags &= ~kSCNetworkReachabilityFlagsIsDirect;
|
||||
flags &= ~kSCNetworkReachabilityFlagsIsLocalAddress; // kInternetConnection is local.
|
||||
|
||||
// Reachability Flag Status: -R ct---xx Connection down.
|
||||
if (flags == kConnectionDown) { return kNotReachable; }
|
||||
|
||||
// Reachability Flag Status: -R -t---xx Reachable. WiFi + VPN(is up) (Thank you Ling Wang)
|
||||
if (flags & kSCNetworkReachabilityFlagsTransientConnection) { return kReachableViaWiFi; }
|
||||
|
||||
// Reachability Flag Status: -R -----xx Reachable.
|
||||
if (flags == 0) { return kReachableViaWiFi; }
|
||||
|
||||
// Apple's code tests for dynamic connection types here. I don't.
|
||||
// If a connection is required, regardless of whether it is on demand or not, it is a WiFi connection.
|
||||
// If you care whether a connection needs to be brought up, use -isConnectionRequired.
|
||||
// If you care about whether user intervention is necessary, use -isInterventionRequired.
|
||||
// If you care about dynamically establishing the connection, use -isConnectionIsOnDemand.
|
||||
|
||||
// Reachability Flag Status: -R cxxxxxx Reachable.
|
||||
if (flags & kSCNetworkReachabilityFlagsConnectionRequired) { return kReachableViaWiFi; }
|
||||
|
||||
// Required by the compiler. Should never get here. Default to not connected.
|
||||
#if (defined DEBUG && defined CLASS_DEBUG)
|
||||
NSAssert1(NO, @"Uncaught reachability test. Flags: %@", reachabilityFlags_(flags));
|
||||
#endif
|
||||
return kNotReachable;
|
||||
|
||||
}
|
||||
|
||||
// Reachability Flag Status: x- xxxxxxx
|
||||
return kNotReachable;
|
||||
|
||||
} // networkStatusForFlags:
|
||||
|
||||
|
||||
- (NetworkStatus) currentReachabilityStatus {
|
||||
|
||||
NSAssert(reachabilityRef, @"currentReachabilityStatus called with NULL reachabilityRef");
|
||||
|
||||
SCNetworkReachabilityFlags flags = 0;
|
||||
NetworkStatus status = kNotReachable;
|
||||
|
||||
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) {
|
||||
|
||||
// logReachabilityFlags(flags);
|
||||
|
||||
status = [self networkStatusForFlags: flags];
|
||||
|
||||
return status;
|
||||
|
||||
}
|
||||
|
||||
return kNotReachable;
|
||||
|
||||
} // currentReachabilityStatus
|
||||
|
||||
|
||||
- (BOOL) isReachable {
|
||||
|
||||
NSAssert(reachabilityRef, @"isReachable called with NULL reachabilityRef");
|
||||
|
||||
SCNetworkReachabilityFlags flags = 0;
|
||||
NetworkStatus status = kNotReachable;
|
||||
|
||||
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) {
|
||||
|
||||
// logReachabilityFlags(flags);
|
||||
|
||||
status = [self networkStatusForFlags: flags];
|
||||
|
||||
// logNetworkStatus(status);
|
||||
|
||||
return (kNotReachable != status);
|
||||
|
||||
}
|
||||
|
||||
return NO;
|
||||
|
||||
} // isReachable
|
||||
|
||||
|
||||
- (BOOL) isConnectionRequired {
|
||||
|
||||
NSAssert(reachabilityRef, @"isConnectionRequired called with NULL reachabilityRef");
|
||||
|
||||
SCNetworkReachabilityFlags flags;
|
||||
|
||||
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) {
|
||||
|
||||
logReachabilityFlags(flags);
|
||||
|
||||
return (flags & kSCNetworkReachabilityFlagsConnectionRequired);
|
||||
|
||||
}
|
||||
|
||||
return NO;
|
||||
|
||||
} // isConnectionRequired
|
||||
|
||||
|
||||
- (BOOL) connectionRequired {
|
||||
|
||||
return [self isConnectionRequired];
|
||||
|
||||
} // connectionRequired
|
||||
#endif
|
||||
|
||||
|
||||
#if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 30000)
|
||||
static const SCNetworkReachabilityFlags kOnDemandConnection = kSCNetworkReachabilityFlagsConnectionOnTraffic |
|
||||
kSCNetworkReachabilityFlagsConnectionOnDemand;
|
||||
#else
|
||||
static const SCNetworkReachabilityFlags kOnDemandConnection = kSCNetworkReachabilityFlagsConnectionAutomatic;
|
||||
#endif
|
||||
|
||||
- (BOOL) isConnectionOnDemand {
|
||||
|
||||
NSAssert(reachabilityRef, @"isConnectionIsOnDemand called with NULL reachabilityRef");
|
||||
|
||||
SCNetworkReachabilityFlags flags;
|
||||
|
||||
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) {
|
||||
|
||||
logReachabilityFlags(flags);
|
||||
|
||||
return ((flags & kSCNetworkReachabilityFlagsConnectionRequired) &&
|
||||
(flags & kOnDemandConnection));
|
||||
|
||||
}
|
||||
|
||||
return NO;
|
||||
|
||||
} // isConnectionOnDemand
|
||||
|
||||
|
||||
- (BOOL) isInterventionRequired {
|
||||
|
||||
NSAssert(reachabilityRef, @"isInterventionRequired called with NULL reachabilityRef");
|
||||
|
||||
SCNetworkReachabilityFlags flags;
|
||||
|
||||
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) {
|
||||
|
||||
logReachabilityFlags(flags);
|
||||
|
||||
return ((flags & kSCNetworkReachabilityFlagsConnectionRequired) &&
|
||||
(flags & kSCNetworkReachabilityFlagsInterventionRequired));
|
||||
|
||||
}
|
||||
|
||||
return NO;
|
||||
|
||||
} // isInterventionRequired
|
||||
|
||||
|
||||
- (BOOL) isReachableViaWWAN {
|
||||
|
||||
NSAssert(reachabilityRef, @"isReachableViaWWAN called with NULL reachabilityRef");
|
||||
|
||||
SCNetworkReachabilityFlags flags = 0;
|
||||
NetworkStatus status = kNotReachable;
|
||||
|
||||
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) {
|
||||
|
||||
logReachabilityFlags(flags);
|
||||
|
||||
status = [self networkStatusForFlags: flags];
|
||||
|
||||
return (kReachableViaWWAN == status);
|
||||
|
||||
}
|
||||
|
||||
return NO;
|
||||
|
||||
} // isReachableViaWWAN
|
||||
|
||||
|
||||
- (BOOL) isReachableViaWiFi {
|
||||
|
||||
NSAssert(reachabilityRef, @"isReachableViaWiFi called with NULL reachabilityRef");
|
||||
|
||||
SCNetworkReachabilityFlags flags = 0;
|
||||
NetworkStatus status = kNotReachable;
|
||||
|
||||
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) {
|
||||
|
||||
logReachabilityFlags(flags);
|
||||
|
||||
status = [self networkStatusForFlags: flags];
|
||||
|
||||
return (kReachableViaWiFi == status);
|
||||
|
||||
}
|
||||
|
||||
return NO;
|
||||
|
||||
} // isReachableViaWiFi
|
||||
|
||||
|
||||
- (SCNetworkReachabilityFlags) reachabilityFlags {
|
||||
|
||||
NSAssert(reachabilityRef, @"reachabilityFlags called with NULL reachabilityRef");
|
||||
|
||||
SCNetworkReachabilityFlags flags = 0;
|
||||
|
||||
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) {
|
||||
|
||||
logReachabilityFlags(flags);
|
||||
|
||||
return flags;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
} // reachabilityFlags
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Apple's Network Flag Handling Methods
|
||||
|
||||
|
||||
#if !USE_DDG_EXTENSIONS
|
||||
/*
|
||||
*
|
||||
* Apple's Network Status testing code.
|
||||
* The only changes that have been made are to use the new logReachabilityFlags macro and
|
||||
* test for local WiFi via the key instead of Apple's boolean. Also, Apple's code was for v3.0 only
|
||||
* iPhone OS. v2.2.1 and earlier conditional compiling is turned on. Hence, to mirror Apple's behavior,
|
||||
* set your Base SDK to v3.0 or higher.
|
||||
*
|
||||
*/
|
||||
|
||||
- (NetworkStatus) localWiFiStatusForFlags: (SCNetworkReachabilityFlags) flags
|
||||
{
|
||||
logReachabilityFlags(flags);
|
||||
|
||||
BOOL retVal = NotReachable;
|
||||
if((flags & kSCNetworkReachabilityFlagsReachable) && (flags & kSCNetworkReachabilityFlagsIsDirect))
|
||||
{
|
||||
retVal = ReachableViaWiFi;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
- (NetworkStatus) networkStatusForFlags: (SCNetworkReachabilityFlags) flags
|
||||
{
|
||||
logReachabilityFlags(flags);
|
||||
if (!(flags & kSCNetworkReachabilityFlagsReachable))
|
||||
{
|
||||
// if target host is not reachable
|
||||
return NotReachable;
|
||||
}
|
||||
|
||||
BOOL retVal = NotReachable;
|
||||
|
||||
if (!(flags & kSCNetworkReachabilityFlagsConnectionRequired))
|
||||
{
|
||||
// if target host is reachable and no connection is required
|
||||
// then we'll assume (for now) that your on Wi-Fi
|
||||
retVal = ReachableViaWiFi;
|
||||
}
|
||||
|
||||
#if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 30000) // Apple advises you to use the magic number instead of a symbol.
|
||||
if ((flags & kSCNetworkReachabilityFlagsConnectionOnDemand) ||
|
||||
(flags & kSCNetworkReachabilityFlagsConnectionOnTraffic))
|
||||
#else
|
||||
if (flags & kSCNetworkReachabilityFlagsConnectionAutomatic)
|
||||
#endif
|
||||
{
|
||||
// ... and the connection is on-demand (or on-traffic) if the
|
||||
// calling application is using the CFSocketStream or higher APIs
|
||||
|
||||
if (!(flags & kSCNetworkReachabilityFlagsInterventionRequired))
|
||||
{
|
||||
// ... and no [user] intervention is needed
|
||||
retVal = ReachableViaWiFi;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & kSCNetworkReachabilityFlagsIsWWAN)
|
||||
{
|
||||
// ... but WWAN connections are OK if the calling application
|
||||
// is using the CFNetwork (CFSocketStream?) APIs.
|
||||
retVal = ReachableViaWWAN;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
- (NetworkStatus) currentReachabilityStatus
|
||||
{
|
||||
NSAssert(reachabilityRef, @"currentReachabilityStatus called with NULL reachabilityRef");
|
||||
|
||||
NetworkStatus retVal = NotReachable;
|
||||
SCNetworkReachabilityFlags flags;
|
||||
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags))
|
||||
{
|
||||
if(self.key == kLocalWiFiConnection)
|
||||
{
|
||||
retVal = [self localWiFiStatusForFlags: flags];
|
||||
}
|
||||
else
|
||||
{
|
||||
retVal = [self networkStatusForFlags: flags];
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL) isReachable {
|
||||
|
||||
NSAssert(reachabilityRef, @"isReachable called with NULL reachabilityRef");
|
||||
|
||||
SCNetworkReachabilityFlags flags = 0;
|
||||
NetworkStatus status = kNotReachable;
|
||||
|
||||
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) {
|
||||
|
||||
logReachabilityFlags(flags);
|
||||
|
||||
if(self.key == kLocalWiFiConnection) {
|
||||
|
||||
status = [self localWiFiStatusForFlags: flags];
|
||||
|
||||
} else {
|
||||
|
||||
status = [self networkStatusForFlags: flags];
|
||||
|
||||
}
|
||||
|
||||
return (kNotReachable != status);
|
||||
|
||||
}
|
||||
|
||||
return NO;
|
||||
|
||||
} // isReachable
|
||||
|
||||
|
||||
- (BOOL) isConnectionRequired {
|
||||
|
||||
return [self connectionRequired];
|
||||
|
||||
} // isConnectionRequired
|
||||
|
||||
|
||||
- (BOOL) connectionRequired {
|
||||
|
||||
NSAssert(reachabilityRef, @"connectionRequired called with NULL reachabilityRef");
|
||||
|
||||
SCNetworkReachabilityFlags flags;
|
||||
|
||||
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) {
|
||||
|
||||
logReachabilityFlags(flags);
|
||||
|
||||
return (flags & kSCNetworkReachabilityFlagsConnectionRequired);
|
||||
|
||||
}
|
||||
|
||||
return NO;
|
||||
|
||||
} // connectionRequired
|
||||
#endif
|
||||
|
||||
@end
|
||||
@@ -7,7 +7,12 @@
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "BaseViewController.h"
|
||||
|
||||
@interface RootViewController : UITableViewController
|
||||
@interface RootViewController : BaseViewController <UITableViewDelegate, UITableViewDataSource> {
|
||||
|
||||
}
|
||||
|
||||
@property (nonatomic, retain) IBOutlet UITableView* table;
|
||||
|
||||
@end
|
||||
|
||||
@@ -7,13 +7,18 @@
|
||||
//
|
||||
|
||||
#import "RootViewController.h"
|
||||
#import "HTTPHUDExample.h"
|
||||
#import "AsyncImageExample.h"
|
||||
#import "AsyncCellImagesExample.h"
|
||||
|
||||
@implementation RootViewController
|
||||
|
||||
@synthesize table;
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
self.title = @"Demos";
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated
|
||||
@@ -36,23 +41,30 @@
|
||||
[super viewDidDisappear:animated];
|
||||
}
|
||||
|
||||
/*
|
||||
// Override to allow orientations other than the default portrait orientation.
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
|
||||
// Return YES for supported orientations.
|
||||
return (interfaceOrientation == UIInterfaceOrientationPortrait);
|
||||
return YES;
|
||||
}
|
||||
*/
|
||||
|
||||
// Customize the number of sections in the table view.
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
|
||||
switch (section) {
|
||||
case 0:
|
||||
return @"HTTP requests";
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
|
||||
{
|
||||
return 0;
|
||||
return 3;
|
||||
}
|
||||
|
||||
// Customize the appearance of table view cells.
|
||||
@@ -62,83 +74,75 @@
|
||||
|
||||
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
|
||||
if (cell == nil) {
|
||||
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
|
||||
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
|
||||
}
|
||||
|
||||
switch (indexPath.row) {
|
||||
case 0:
|
||||
cell.textLabel.text = @"HUD + JSON parsing";
|
||||
cell.detailTextLabel.text = @"Shows a HUD spinner and parses JSON";
|
||||
break;
|
||||
|
||||
case 1:
|
||||
cell.textLabel.text = @"Async image";
|
||||
cell.detailTextLabel.text = @"Loads a simple image asynchronously";
|
||||
break;
|
||||
|
||||
case 2:
|
||||
cell.textLabel.text = @"Async cell images";
|
||||
cell.detailTextLabel.text = @"Loads images inside cells asynchronously";
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Configure the cell.
|
||||
return cell;
|
||||
}
|
||||
|
||||
/*
|
||||
// Override to support conditional editing of the table view.
|
||||
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
// Return NO if you do not want the specified item to be editable.
|
||||
return YES;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
// Override to support editing the table view.
|
||||
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
if (editingStyle == UITableViewCellEditingStyleDelete)
|
||||
{
|
||||
// Delete the row from the data source.
|
||||
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
|
||||
}
|
||||
else if (editingStyle == UITableViewCellEditingStyleInsert)
|
||||
{
|
||||
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view.
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
// Override to support rearranging the table view.
|
||||
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
|
||||
{
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
// Override to support conditional rearranging of the table view.
|
||||
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
// Return NO if you do not want the item to be re-orderable.
|
||||
return YES;
|
||||
}
|
||||
*/
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
/*
|
||||
<#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:@"<#Nib name#>" bundle:nil];
|
||||
// ...
|
||||
// Pass the selected object to the new view controller.
|
||||
[self.navigationController pushViewController:detailViewController animated:YES];
|
||||
[detailViewController release];
|
||||
*/
|
||||
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
||||
|
||||
UIViewController* vc = nil;
|
||||
|
||||
switch (indexPath.row) {
|
||||
case 0:
|
||||
vc = [[HTTPHUDExample alloc] init];
|
||||
break;
|
||||
|
||||
case 1:
|
||||
vc = [[AsyncImageExample alloc] init];
|
||||
break;
|
||||
|
||||
case 2:
|
||||
vc = [[AsyncCellImagesExample alloc] init];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (vc) {
|
||||
[self.navigationController pushViewController:vc animated:YES];
|
||||
[vc release];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
- (void)didReceiveMemoryWarning
|
||||
{
|
||||
// Releases the view if it doesn't have a superview.
|
||||
[super didReceiveMemoryWarning];
|
||||
|
||||
// Relinquish ownership any cached data, images, etc that aren't in use.
|
||||
}
|
||||
|
||||
- (void)viewDidUnload
|
||||
{
|
||||
[super viewDidUnload];
|
||||
|
||||
// Relinquish ownership of anything that can be recreated in viewDidLoad or on demand.
|
||||
// For example: self.myOutlet = nil;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[table release];
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
|
||||
BIN
IOSBoilerplate/SVProgressHUD/.DS_Store
vendored
Normal file
BIN
IOSBoilerplate/SVProgressHUD/.DS_Store
vendored
Normal file
Binary file not shown.
BIN
IOSBoilerplate/SVProgressHUD/SVProgressHUD.bundle/error.png
Normal file
BIN
IOSBoilerplate/SVProgressHUD/SVProgressHUD.bundle/error.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 371 B |
BIN
IOSBoilerplate/SVProgressHUD/SVProgressHUD.bundle/error@2x.png
Normal file
BIN
IOSBoilerplate/SVProgressHUD/SVProgressHUD.bundle/error@2x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 739 B |
BIN
IOSBoilerplate/SVProgressHUD/SVProgressHUD.bundle/success.png
Normal file
BIN
IOSBoilerplate/SVProgressHUD/SVProgressHUD.bundle/success.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 508 B |
BIN
IOSBoilerplate/SVProgressHUD/SVProgressHUD.bundle/success@2x.png
Normal file
BIN
IOSBoilerplate/SVProgressHUD/SVProgressHUD.bundle/success@2x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 872 B |
41
IOSBoilerplate/SVProgressHUD/SVProgressHUD.h
Normal file
41
IOSBoilerplate/SVProgressHUD/SVProgressHUD.h
Normal file
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// SVProgressHUD.h
|
||||
//
|
||||
// Created by Sam Vermette on 27.03.11.
|
||||
// Copyright 2011 Sam Vermette. All rights reserved.
|
||||
//
|
||||
|
||||
typedef enum {
|
||||
SVProgressHUDMaskTypeNone, // allow user interactions while HUD is displayed
|
||||
SVProgressHUDMaskTypeClear, // don't allow
|
||||
SVProgressHUDMaskTypeBlack // don't allow and dim the UI in the back of the HUD
|
||||
} SVProgressHUDMaskType;
|
||||
|
||||
@interface SVProgressHUD : UIView {
|
||||
UIView *_maskView;
|
||||
}
|
||||
|
||||
/*
|
||||
showInView:(UIView*) -> the view you're adding the HUD to. By default, it's added to the keyWindow rootViewController, or the keyWindow if the rootViewController is nil
|
||||
status:(NSString*) -> a loading status for the HUD (different from the success and error messages)
|
||||
networkIndicator:(BOOL) -> whether or not the HUD also triggers the UIApplication's network activity indicator (default is YES)
|
||||
posY:(CGFloat) -> the vertical position of the HUD (default is viewHeight/2-viewHeight/8)
|
||||
maskType:(SVProgressHUDMaskType) -> set whether to allow user interactions while HUD is displayed
|
||||
*/
|
||||
|
||||
+ (void)show;
|
||||
+ (void)showInView:(UIView*)view;
|
||||
+ (void)showInView:(UIView*)view status:(NSString*)string;
|
||||
+ (void)showInView:(UIView*)view status:(NSString*)string networkIndicator:(BOOL)show;
|
||||
+ (void)showInView:(UIView*)view status:(NSString*)string networkIndicator:(BOOL)show posY:(CGFloat)posY;
|
||||
+ (void)showInView:(UIView*)view status:(NSString*)string networkIndicator:(BOOL)show posY:(CGFloat)posY maskType:(SVProgressHUDMaskType)maskType;
|
||||
|
||||
+ (void)setStatus:(NSString*)string; // change the HUD loading status while it's showing
|
||||
|
||||
+ (void)dismiss; // simply dismiss the HUD with a fade+scale out animation
|
||||
+ (void)dismissWithSuccess:(NSString*)successString; // also displays the success icon image
|
||||
+ (void)dismissWithSuccess:(NSString*)successString afterDelay:(NSTimeInterval)seconds;
|
||||
+ (void)dismissWithError:(NSString*)errorString; // also displays the error icon image
|
||||
+ (void)dismissWithError:(NSString*)errorString afterDelay:(NSTimeInterval)seconds;
|
||||
|
||||
@end
|
||||
336
IOSBoilerplate/SVProgressHUD/SVProgressHUD.m
Normal file
336
IOSBoilerplate/SVProgressHUD/SVProgressHUD.m
Normal file
@@ -0,0 +1,336 @@
|
||||
//
|
||||
// SVProgressHUD.m
|
||||
//
|
||||
// Created by Sam Vermette on 27.03.11.
|
||||
// Copyright 2011 Sam Vermette. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SVProgressHUD.h"
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
|
||||
@interface SVProgressHUD ()
|
||||
|
||||
@property (nonatomic, retain) NSTimer *fadeOutTimer;
|
||||
@property (nonatomic, retain) UILabel *stringLabel;
|
||||
@property (nonatomic, retain) UIImageView *imageView;
|
||||
@property (nonatomic, retain) UIActivityIndicatorView *spinnerView;
|
||||
|
||||
- (void)showInView:(UIView*)view status:(NSString*)string networkIndicator:(BOOL)show posY:(CGFloat)posY maskType:(SVProgressHUDMaskType)maskType;
|
||||
- (void)setStatus:(NSString*)string;
|
||||
|
||||
- (void)dismiss;
|
||||
- (void)dismissWithStatus:(NSString*)string error:(BOOL)error;
|
||||
- (void)dismissWithStatus:(NSString*)string error:(BOOL)error afterDelay:(NSTimeInterval)seconds;
|
||||
|
||||
- (void)memoryWarning:(NSNotification*)notification;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation SVProgressHUD
|
||||
|
||||
@synthesize fadeOutTimer, stringLabel, imageView, spinnerView;
|
||||
|
||||
static SVProgressHUD *sharedView = nil;
|
||||
|
||||
+ (SVProgressHUD*)sharedView {
|
||||
|
||||
if(sharedView == nil)
|
||||
sharedView = [[SVProgressHUD alloc] initWithFrame:CGRectZero];
|
||||
|
||||
return sharedView;
|
||||
}
|
||||
|
||||
+ (void)setStatus:(NSString *)string {
|
||||
[[SVProgressHUD sharedView] setStatus:string];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Show Methods
|
||||
|
||||
+ (void)show {
|
||||
[SVProgressHUD showInView:nil status:nil];
|
||||
}
|
||||
|
||||
|
||||
+ (void)showInView:(UIView*)view {
|
||||
[SVProgressHUD showInView:view status:nil];
|
||||
}
|
||||
|
||||
|
||||
+ (void)showInView:(UIView*)view status:(NSString*)string {
|
||||
[SVProgressHUD showInView:view status:string networkIndicator:YES];
|
||||
}
|
||||
|
||||
|
||||
+ (void)showInView:(UIView*)view status:(NSString*)string networkIndicator:(BOOL)show {
|
||||
[SVProgressHUD showInView:view status:string networkIndicator:show posY:-1];
|
||||
}
|
||||
|
||||
+ (void)showInView:(UIView*)view status:(NSString*)string networkIndicator:(BOOL)show posY:(CGFloat)posY {
|
||||
[SVProgressHUD showInView:view status:string networkIndicator:show posY:posY maskType:SVProgressHUDMaskTypeNone];
|
||||
}
|
||||
|
||||
|
||||
+ (void)showInView:(UIView*)view status:(NSString*)string networkIndicator:(BOOL)show posY:(CGFloat)posY maskType:(SVProgressHUDMaskType)maskType {
|
||||
|
||||
BOOL addingToWindow;
|
||||
|
||||
if(!view) {
|
||||
UIWindow* keyWindow = [UIApplication sharedApplication].keyWindow;
|
||||
addingToWindow = YES;
|
||||
|
||||
if ([keyWindow respondsToSelector:@selector(rootViewController)]) {
|
||||
//Use the rootViewController to reflect the device orientation
|
||||
view = keyWindow.rootViewController.view;
|
||||
}
|
||||
|
||||
if (view == nil) view = keyWindow;
|
||||
}
|
||||
|
||||
if(posY == -1) {
|
||||
posY = floor(CGRectGetHeight(view.bounds)/2);
|
||||
|
||||
if(addingToWindow)
|
||||
posY -= floor(CGRectGetHeight(view.bounds)/18); // move slightly towards the top
|
||||
}
|
||||
|
||||
[[SVProgressHUD sharedView] showInView:view status:string networkIndicator:show posY:posY maskType:maskType];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Dismiss Methods
|
||||
|
||||
+ (void)dismiss {
|
||||
[[SVProgressHUD sharedView] dismiss];
|
||||
}
|
||||
|
||||
+ (void)dismissWithSuccess:(NSString*)successString {
|
||||
[[SVProgressHUD sharedView] dismissWithStatus:successString error:NO];
|
||||
}
|
||||
|
||||
+ (void)dismissWithSuccess:(NSString *)successString afterDelay:(NSTimeInterval)seconds {
|
||||
[[SVProgressHUD sharedView] dismissWithStatus:successString error:NO afterDelay:seconds];
|
||||
}
|
||||
|
||||
+ (void)dismissWithError:(NSString*)errorString {
|
||||
[[SVProgressHUD sharedView] dismissWithStatus:errorString error:YES];
|
||||
}
|
||||
|
||||
+ (void)dismissWithError:(NSString *)errorString afterDelay:(NSTimeInterval)seconds {
|
||||
[[SVProgressHUD sharedView] dismissWithStatus:errorString error:YES afterDelay:seconds];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Instance Methods
|
||||
|
||||
- (void)dealloc {
|
||||
|
||||
if(fadeOutTimer != nil)
|
||||
[fadeOutTimer invalidate], [fadeOutTimer release], fadeOutTimer = nil;
|
||||
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame {
|
||||
|
||||
if ((self = [super initWithFrame:frame])) {
|
||||
self.layer.cornerRadius = 10;
|
||||
self.backgroundColor = [UIColor colorWithWhite:0 alpha:0.8];
|
||||
self.userInteractionEnabled = NO;
|
||||
self.layer.opacity = 0;
|
||||
self.autoresizingMask = (UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin |
|
||||
UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin);
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(memoryWarning:)
|
||||
name:UIApplicationDidReceiveMemoryWarningNotification
|
||||
object:nil];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setStatus:(NSString *)string {
|
||||
|
||||
CGFloat hudWidth = 100;
|
||||
|
||||
CGFloat stringWidth = [string sizeWithFont:self.stringLabel.font].width+28;
|
||||
|
||||
if(stringWidth > hudWidth)
|
||||
hudWidth = ceil(stringWidth/2)*2;
|
||||
|
||||
self.bounds = CGRectMake(0, 0, hudWidth, 100);
|
||||
|
||||
self.imageView.center = CGPointMake(CGRectGetWidth(self.bounds)/2, 36);
|
||||
|
||||
self.stringLabel.hidden = NO;
|
||||
self.stringLabel.text = string;
|
||||
self.stringLabel.frame = CGRectMake(0, 66, CGRectGetWidth(self.bounds), 20);
|
||||
|
||||
if(string)
|
||||
self.spinnerView.center = CGPointMake(ceil(CGRectGetWidth(self.bounds)/2)+0.5, 40.5);
|
||||
else
|
||||
self.spinnerView.center = CGPointMake(ceil(CGRectGetWidth(self.bounds)/2)+0.5, ceil(self.bounds.size.height/2)+0.5);
|
||||
}
|
||||
|
||||
|
||||
- (void)showInView:(UIView*)view status:(NSString*)string networkIndicator:(BOOL)show posY:(CGFloat)posY maskType:(SVProgressHUDMaskType)maskType {
|
||||
|
||||
if(fadeOutTimer != nil)
|
||||
[fadeOutTimer invalidate], [fadeOutTimer release], fadeOutTimer = nil;
|
||||
|
||||
if(show)
|
||||
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
|
||||
else
|
||||
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
|
||||
|
||||
self.imageView.hidden = YES;
|
||||
|
||||
[self setStatus:string];
|
||||
[spinnerView startAnimating];
|
||||
|
||||
if (!_maskView && maskType != SVProgressHUDMaskTypeNone) {
|
||||
_maskView = [[UIView alloc] initWithFrame:view.bounds];
|
||||
_maskView.backgroundColor = [UIColor clearColor];
|
||||
_maskView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
[view addSubview:_maskView];
|
||||
[_maskView release];
|
||||
}
|
||||
|
||||
if(![sharedView isDescendantOfView:view]) {
|
||||
sharedView.layer.opacity = 0;
|
||||
[view addSubview:sharedView];
|
||||
}
|
||||
|
||||
if(sharedView.layer.opacity != 1) {
|
||||
|
||||
self.center = CGPointMake(CGRectGetWidth(self.superview.bounds)/2, posY);
|
||||
|
||||
self.layer.transform = CATransform3DScale(CATransform3DMakeTranslation(0, 0, 0), 1.3, 1.3, 1);
|
||||
self.layer.opacity = 0.3;
|
||||
|
||||
[UIView animateWithDuration:0.15
|
||||
delay:0
|
||||
options:UIViewAnimationOptionAllowUserInteraction | UIViewAnimationCurveEaseOut
|
||||
animations:^{
|
||||
self.layer.transform = CATransform3DScale(CATransform3DMakeTranslation(0, 0, 0), 1, 1, 1);
|
||||
self.layer.opacity = 1;
|
||||
|
||||
if (_maskView && maskType == SVProgressHUDMaskTypeBlack) {
|
||||
_maskView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.5];
|
||||
}
|
||||
|
||||
}
|
||||
completion:NULL];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void)dismiss {
|
||||
|
||||
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
|
||||
|
||||
[UIView animateWithDuration:0.15
|
||||
delay:0
|
||||
options:UIViewAnimationCurveEaseIn | UIViewAnimationOptionAllowUserInteraction
|
||||
animations:^{
|
||||
self.layer.transform = CATransform3DScale(CATransform3DMakeTranslation(0, 0, 0), 0.8, 0.8, 1.0);
|
||||
self.layer.opacity = 0;
|
||||
if (_maskView) {
|
||||
_maskView.backgroundColor = [UIColor clearColor];
|
||||
}
|
||||
}
|
||||
completion:^(BOOL finished){
|
||||
if(self.layer.opacity == 0) {
|
||||
[_maskView removeFromSuperview];
|
||||
_maskView = nil;
|
||||
[self removeFromSuperview];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
- (void)dismissWithStatus:(NSString*)string error:(BOOL)error {
|
||||
[self dismissWithStatus:string error:error afterDelay:0.9];
|
||||
}
|
||||
|
||||
|
||||
- (void)dismissWithStatus:(NSString *)string error:(BOOL)error afterDelay:(NSTimeInterval)seconds {
|
||||
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
|
||||
|
||||
if(error)
|
||||
self.imageView.image = [UIImage imageNamed:@"SVProgressHUD.bundle/error.png"];
|
||||
else
|
||||
self.imageView.image = [UIImage imageNamed:@"SVProgressHUD.bundle/success.png"];
|
||||
|
||||
self.imageView.hidden = NO;
|
||||
|
||||
[self setStatus:string];
|
||||
|
||||
[self.spinnerView stopAnimating];
|
||||
|
||||
if(fadeOutTimer != nil)
|
||||
[fadeOutTimer invalidate], [fadeOutTimer release], fadeOutTimer = nil;
|
||||
|
||||
fadeOutTimer = [[NSTimer scheduledTimerWithTimeInterval:seconds target:self selector:@selector(dismiss) userInfo:nil repeats:NO] retain];
|
||||
}
|
||||
|
||||
#pragma mark - Getters
|
||||
|
||||
- (UILabel *)stringLabel {
|
||||
|
||||
if (stringLabel == nil) {
|
||||
stringLabel = [[UILabel alloc] initWithFrame:CGRectZero];
|
||||
stringLabel.textColor = [UIColor whiteColor];
|
||||
stringLabel.backgroundColor = [UIColor clearColor];
|
||||
stringLabel.adjustsFontSizeToFitWidth = YES;
|
||||
stringLabel.textAlignment = UITextAlignmentCenter;
|
||||
stringLabel.baselineAdjustment = UIBaselineAdjustmentAlignCenters;
|
||||
stringLabel.font = [UIFont boldSystemFontOfSize:16];
|
||||
stringLabel.shadowColor = [UIColor blackColor];
|
||||
stringLabel.shadowOffset = CGSizeMake(0, -1);
|
||||
[self addSubview:stringLabel];
|
||||
[stringLabel release];
|
||||
}
|
||||
|
||||
return stringLabel;
|
||||
}
|
||||
|
||||
- (UIImageView *)imageView {
|
||||
|
||||
if (imageView == nil) {
|
||||
imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 28, 28)];
|
||||
[self addSubview:imageView];
|
||||
[imageView release];
|
||||
}
|
||||
|
||||
return imageView;
|
||||
}
|
||||
|
||||
- (UIActivityIndicatorView *)spinnerView {
|
||||
|
||||
if (spinnerView == nil) {
|
||||
spinnerView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
|
||||
spinnerView.hidesWhenStopped = YES;
|
||||
spinnerView.bounds = CGRectMake(0, 0, 37, 37);
|
||||
[self addSubview:spinnerView];
|
||||
[spinnerView release];
|
||||
}
|
||||
|
||||
return spinnerView;
|
||||
}
|
||||
|
||||
#pragma mark - MemoryWarning
|
||||
|
||||
- (void)memoryWarning:(NSNotification *)notification {
|
||||
|
||||
if (sharedView.superview == nil) {
|
||||
[sharedView release];
|
||||
sharedView = nil;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -2,17 +2,19 @@
|
||||
<archive type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="7.10">
|
||||
<data>
|
||||
<int key="IBDocument.SystemTarget">784</int>
|
||||
<string key="IBDocument.SystemVersion">10D541</string>
|
||||
<string key="IBDocument.InterfaceBuilderVersion">760</string>
|
||||
<string key="IBDocument.AppKitVersion">1038.29</string>
|
||||
<string key="IBDocument.HIToolboxVersion">460.00</string>
|
||||
<string key="IBDocument.SystemVersion">11B26</string>
|
||||
<string key="IBDocument.InterfaceBuilderVersion">1617</string>
|
||||
<string key="IBDocument.AppKitVersion">1138</string>
|
||||
<string key="IBDocument.HIToolboxVersion">566.00</string>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string key="NS.object.0">81</string>
|
||||
<string key="NS.object.0">534</string>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
|
||||
<object class="NSArray" key="IBDocument.IntegratedClassDependencies">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<integer value="2"/>
|
||||
<string>IBProxyObject</string>
|
||||
<string>IBUIView</string>
|
||||
<string>IBUITableView</string>
|
||||
</object>
|
||||
<object class="NSArray" key="IBDocument.PluginDependencies">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
@@ -23,9 +25,7 @@
|
||||
<object class="NSArray" key="dict.sortedKeys" id="0">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
</object>
|
||||
<reference key="dict.values" ref="0"/>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
@@ -37,26 +37,45 @@
|
||||
<string key="IBProxiedObjectIdentifier">IBFirstResponder</string>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
</object>
|
||||
<object class="IBUITableView" id="709618507">
|
||||
<object class="IBUIView" id="539233205">
|
||||
<reference key="NSNextResponder"/>
|
||||
<int key="NSvFlags">274</int>
|
||||
<string key="NSFrameSize">{320, 247}</string>
|
||||
<int key="NSvFlags">292</int>
|
||||
<object class="NSMutableArray" key="NSSubviews">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBUITableView" id="359685268">
|
||||
<reference key="NSNextResponder" ref="539233205"/>
|
||||
<int key="NSvFlags">274</int>
|
||||
<string key="NSFrameSize">{320, 460}</string>
|
||||
<reference key="NSSuperview" ref="539233205"/>
|
||||
<reference key="NSWindow"/>
|
||||
<string key="NSReuseIdentifierKey">_NS:392</string>
|
||||
<object class="NSColor" key="IBUIBackgroundColor">
|
||||
<int key="NSColorSpace">3</int>
|
||||
<bytes key="NSWhite">MQA</bytes>
|
||||
</object>
|
||||
<bool key="IBUIClipsSubviews">YES</bool>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
<bool key="IBUIAlwaysBounceVertical">YES</bool>
|
||||
<int key="IBUISeparatorStyle">1</int>
|
||||
<int key="IBUISectionIndexMinimumDisplayRowCount">0</int>
|
||||
<bool key="IBUIShowsSelectionImmediatelyOnTouchBegin">YES</bool>
|
||||
<float key="IBUIRowHeight">44</float>
|
||||
<float key="IBUISectionHeaderHeight">22</float>
|
||||
<float key="IBUISectionFooterHeight">22</float>
|
||||
</object>
|
||||
</object>
|
||||
<string key="NSFrameSize">{320, 460}</string>
|
||||
<reference key="NSSuperview"/>
|
||||
<reference key="NSWindow"/>
|
||||
<string key="NSReuseIdentifierKey">_NS:180</string>
|
||||
<object class="NSColor" key="IBUIBackgroundColor">
|
||||
<int key="NSColorSpace">3</int>
|
||||
<bytes key="NSWhite">MQA</bytes>
|
||||
<object class="NSColorSpace" key="NSCustomColorSpace">
|
||||
<int key="NSID">2</int>
|
||||
</object>
|
||||
</object>
|
||||
<bool key="IBUIOpaque">NO</bool>
|
||||
<bool key="IBUIClipsSubviews">YES</bool>
|
||||
<bool key="IBUIClearsContextBeforeDrawing">NO</bool>
|
||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||
<bool key="IBUIBouncesZoom">NO</bool>
|
||||
<int key="IBUISeparatorStyle">1</int>
|
||||
<int key="IBUISectionIndexMinimumDisplayRowCount">0</int>
|
||||
<bool key="IBUIShowsSelectionImmediatelyOnTouchBegin">YES</bool>
|
||||
<float key="IBUIRowHeight">44</float>
|
||||
<float key="IBUISectionHeaderHeight">22</float>
|
||||
<float key="IBUISectionFooterHeight">22</float>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBObjectContainer" key="IBDocument.Objects">
|
||||
@@ -66,25 +85,25 @@
|
||||
<object class="IBCocoaTouchOutletConnection" key="connection">
|
||||
<string key="label">view</string>
|
||||
<reference key="source" ref="841351856"/>
|
||||
<reference key="destination" ref="709618507"/>
|
||||
<reference key="destination" ref="539233205"/>
|
||||
</object>
|
||||
<int key="connectionID">3</int>
|
||||
<int key="connectionID">7</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchOutletConnection" key="connection">
|
||||
<string key="label">dataSource</string>
|
||||
<reference key="source" ref="709618507"/>
|
||||
<reference key="source" ref="359685268"/>
|
||||
<reference key="destination" ref="841351856"/>
|
||||
</object>
|
||||
<int key="connectionID">4</int>
|
||||
<int key="connectionID">9</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBCocoaTouchOutletConnection" key="connection">
|
||||
<string key="label">delegate</string>
|
||||
<reference key="source" ref="709618507"/>
|
||||
<reference key="source" ref="359685268"/>
|
||||
<reference key="destination" ref="841351856"/>
|
||||
</object>
|
||||
<int key="connectionID">5</int>
|
||||
<int key="connectionID">10</int>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBMutableOrderedSet" key="objectRecords">
|
||||
@@ -108,10 +127,19 @@
|
||||
<reference key="parent" ref="0"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">2</int>
|
||||
<reference key="object" ref="709618507"/>
|
||||
<int key="objectID">6</int>
|
||||
<reference key="object" ref="539233205"/>
|
||||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="359685268"/>
|
||||
</object>
|
||||
<reference key="parent" ref="0"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">8</int>
|
||||
<reference key="object" ref="359685268"/>
|
||||
<reference key="parent" ref="539233205"/>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="flattenedProperties">
|
||||
@@ -119,249 +147,64 @@
|
||||
<object class="NSArray" key="dict.sortedKeys">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>-1.CustomClassName</string>
|
||||
<string>-1.IBPluginDependency</string>
|
||||
<string>-2.CustomClassName</string>
|
||||
<string>2.IBEditorWindowLastContentRect</string>
|
||||
<string>2.IBPluginDependency</string>
|
||||
<string>-2.IBPluginDependency</string>
|
||||
<string>6.IBPluginDependency</string>
|
||||
<string>8.IBPluginDependency</string>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<string>RootViewController</string>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string>UIResponder</string>
|
||||
<string>{{144, 609}, {320, 247}}</string>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="unlocalizedProperties">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference key="dict.sortedKeys" ref="0"/>
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
</object>
|
||||
<reference key="dict.values" ref="0"/>
|
||||
</object>
|
||||
<nil key="activeLocalization"/>
|
||||
<object class="NSMutableDictionary" key="localizations">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference key="dict.sortedKeys" ref="0"/>
|
||||
<object class="NSMutableArray" key="dict.values">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
</object>
|
||||
<reference key="dict.values" ref="0"/>
|
||||
</object>
|
||||
<nil key="sourceID"/>
|
||||
<int key="maxID">5</int>
|
||||
<int key="maxID">10</int>
|
||||
</object>
|
||||
<object class="IBClassDescriber" key="IBDocument.Classes">
|
||||
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">RootViewController</string>
|
||||
<string key="superclassName">UITableViewController</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">RootViewController.h</string>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableArray" key="referencedPartialClassDescriptionsV3.2+">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSError.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSFileManager.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSKeyValueCoding.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSKeyValueObserving.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSKeyedArchiver.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSNetServices.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSObject.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSPort.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSRunLoop.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSStream.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSThread.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSURL.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSURLConnection.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">Foundation.framework/Headers/NSXMLParser.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">UIKit.framework/Headers/UIAccessibility.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">UIKit.framework/Headers/UINibLoading.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier" id="654420027">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">UIKit.framework/Headers/UIResponder.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">UIResponder</string>
|
||||
<string key="superclassName">NSObject</string>
|
||||
<reference key="sourceIdentifier" ref="654420027"/>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">UIScrollView</string>
|
||||
<string key="superclassName">UIView</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">UIKit.framework/Headers/UIScrollView.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">UISearchBar</string>
|
||||
<string key="superclassName">UIView</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">UIKit.framework/Headers/UISearchBar.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">UISearchDisplayController</string>
|
||||
<string key="superclassName">NSObject</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">UIKit.framework/Headers/UISearchDisplayController.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">UITableView</string>
|
||||
<string key="superclassName">UIScrollView</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">UIKit.framework/Headers/UITableView.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">UITableViewController</string>
|
||||
<string key="className">BaseViewController</string>
|
||||
<string key="superclassName">UIViewController</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">UIKit.framework/Headers/UITableViewController.h</string>
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">./Classes/BaseViewController.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">UIView</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">UIKit.framework/Headers/UITextField.h</string>
|
||||
<string key="className">RootViewController</string>
|
||||
<string key="superclassName">BaseViewController</string>
|
||||
<object class="NSMutableDictionary" key="outlets">
|
||||
<string key="NS.key.0">table</string>
|
||||
<string key="NS.object.0">UITableView</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">UIView</string>
|
||||
<string key="superclassName">UIResponder</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">UIKit.framework/Headers/UIView.h</string>
|
||||
<object class="NSMutableDictionary" key="toOneOutletInfosByName">
|
||||
<string key="NS.key.0">table</string>
|
||||
<object class="IBToOneOutletInfo" key="NS.object.0">
|
||||
<string key="name">table</string>
|
||||
<string key="candidateClassName">UITableView</string>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">UIViewController</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">UIKit.framework/Headers/UINavigationController.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">UIViewController</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">UIKit.framework/Headers/UITabBarController.h</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBPartialClassDescription">
|
||||
<string key="className">UIViewController</string>
|
||||
<string key="superclassName">UIResponder</string>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBFrameworkSource</string>
|
||||
<string key="minorKey">UIKit.framework/Headers/UIViewController.h</string>
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">./Classes/RootViewController.h</string>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
@@ -377,8 +220,7 @@
|
||||
<integer value="3100" key="NS.object.0"/>
|
||||
</object>
|
||||
<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
|
||||
<string key="IBDocument.LastKnownRelativeProjectPath">IOSBoilerplate.xcodeproj</string>
|
||||
<int key="IBDocument.defaultPropertyAccessControl">3</int>
|
||||
<string key="IBCocoaTouchPluginVersion">81</string>
|
||||
<string key="IBCocoaTouchPluginVersion">534</string>
|
||||
</data>
|
||||
</archive>
|
||||
|
||||
20
README.md
Normal file
20
README.md
Normal file
@@ -0,0 +1,20 @@
|
||||
What is IOS Boilerplate
|
||||
-----------------------
|
||||
|
||||
Is a code base for iOS projects. Current version provides
|
||||
|
||||
- BaseViewController with methods for secure handling of async http requests
|
||||
- DictionaryHelper with methods for safe handling of collections
|
||||
- ImageManager: a class for downloading images asynchronously
|
||||
- FastCell (inspired on [Atebits implementation](http://nickharris.wordpress.com/2010/06/17/fast-uitableviewcell-with-a-uiwebview/)) is a base class for implementing custom UITableViewCells with fast scrolling.
|
||||
|
||||
The project contains some examples with the use of those utility classes.
|
||||
|
||||
|
||||
|
||||
It includes some third party software:
|
||||
|
||||
- [ASIHTTPRequest](http://allseeing-i.com/ASIHTTPRequest/)
|
||||
- [SVProgressHUD](https://github.com/samvermette/SVProgressHUD)
|
||||
- [JSONKit](https://github.com/johnezang/JSONKit)
|
||||
|
||||
Reference in New Issue
Block a user