First commit

This commit is contained in:
Alberto Gimeno
2011-09-08 17:42:58 +02:00
parent 8d800f0f86
commit 766ffbae00
57 changed files with 15160 additions and 315 deletions

12
.gitignore vendored Normal file
View File

@@ -0,0 +1,12 @@
.DS_Store
*.swp
*~.nib
build/
*.pbxuser
*.perspective
*.perspectivev3
*.mode1v3
*.mode2v3
xcuserdata

View File

@@ -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 */
};

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:IOSBoilerplate.xcodeproj">
</FileRef>
</Workspace>

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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>

View 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

View 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

View 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>

View 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

View 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

View 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

View 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
View 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
View 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

View 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

View 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

View 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>

View File

@@ -14,4 +14,6 @@
@property (nonatomic, retain) IBOutlet UINavigationController *navigationController;
+ (IOSBoilerplateAppDelegate*) sharedAppDelegate;
@end

View File

@@ -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

View 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

View 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
View 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

File diff suppressed because it is too large Load Diff

View 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

View 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

View File

@@ -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

View File

@@ -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

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 371 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 739 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 508 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 872 B

View 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

View 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

View File

@@ -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
View 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)