├── LASIImageView.podspec ├── LASIImageView.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── LASIImageView.xccheckout │ └── xcuserdata │ │ └── lukagabric.xcuserdatad │ │ └── WorkspaceSettings.xcsettings └── xcuserdata │ └── lukagabric.xcuserdatad │ └── xcschemes │ ├── LASIImageView.xcscheme │ └── xcschememanagement.plist ├── LASIImageView ├── Classes │ ├── AppDelegate │ │ ├── AppDelegate.h │ │ └── AppDelegate.m │ ├── LASIImageView │ │ ├── LASIImageView.h │ │ └── LASIImageView.m │ └── ViewControler │ │ ├── ViewController.h │ │ ├── ViewController.m │ │ └── ViewController.xib ├── External │ ├── ASIHTTPRequest │ │ ├── ASIAuthenticationDialog.h │ │ ├── ASIAuthenticationDialog.m │ │ ├── ASICacheDelegate.h │ │ ├── ASIDataCompressor.h │ │ ├── ASIDataCompressor.m │ │ ├── ASIDataDecompressor.h │ │ ├── ASIDataDecompressor.m │ │ ├── ASIDownloadCache.h │ │ ├── ASIDownloadCache.m │ │ ├── ASIFormDataRequest.h │ │ ├── ASIFormDataRequest.m │ │ ├── ASIHTTPRequest.h │ │ ├── ASIHTTPRequest.m │ │ ├── ASIHTTPRequestConfig.h │ │ ├── ASIHTTPRequestDelegate.h │ │ ├── ASIInputStream.h │ │ ├── ASIInputStream.m │ │ ├── ASINetworkQueue.h │ │ ├── ASINetworkQueue.m │ │ └── ASIProgressDelegate.h │ └── Reachability │ │ ├── Reachability.h │ │ └── Reachability.m └── Supporting Files │ ├── LASIImageView-Info.plist │ ├── LASIImageView-Prefix.pch │ └── main.m └── README.md /LASIImageView.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "LASIImageView" 3 | s.version = "1.0" 4 | s.summary = "Async Image View" 5 | s.platform = :ios, '5.0' 6 | s.homepage = "https://github.com/lukagabric/LASIImageView" 7 | s.source = { :git => 'https://github.com/lukagabric/LASIImageView'} 8 | s.source_files = 'LASIImageView/Classes/LASIImageView/*.{h,m}' 9 | s.dependency 'ASIHTTPRequest' 10 | s.requires_arc = true 11 | end -------------------------------------------------------------------------------- /LASIImageView.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 4103925217D45DE0006F6AB7 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4103925117D45DE0006F6AB7 /* UIKit.framework */; }; 11 | 4103925417D45DE0006F6AB7 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4103925317D45DE0006F6AB7 /* Foundation.framework */; }; 12 | 4103925617D45DE0006F6AB7 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4103925517D45DE0006F6AB7 /* CoreGraphics.framework */; }; 13 | 4103928317D45E1D006F6AB7 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 4103927F17D45E1D006F6AB7 /* main.m */; }; 14 | 4103928B17D45E80006F6AB7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4103928617D45E80006F6AB7 /* AppDelegate.m */; }; 15 | 4103928C17D45E80006F6AB7 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4103928A17D45E80006F6AB7 /* ViewController.m */; }; 16 | 410392A617D45F59006F6AB7 /* ASIAuthenticationDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 4103929017D45F59006F6AB7 /* ASIAuthenticationDialog.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 17 | 410392A717D45F59006F6AB7 /* ASIDataCompressor.m in Sources */ = {isa = PBXBuildFile; fileRef = 4103929317D45F59006F6AB7 /* ASIDataCompressor.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 18 | 410392A817D45F59006F6AB7 /* ASIDataDecompressor.m in Sources */ = {isa = PBXBuildFile; fileRef = 4103929517D45F59006F6AB7 /* ASIDataDecompressor.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 19 | 410392A917D45F59006F6AB7 /* ASIDownloadCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 4103929717D45F59006F6AB7 /* ASIDownloadCache.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 20 | 410392AA17D45F59006F6AB7 /* ASIFormDataRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4103929917D45F59006F6AB7 /* ASIFormDataRequest.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 21 | 410392AB17D45F59006F6AB7 /* ASIHTTPRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4103929B17D45F59006F6AB7 /* ASIHTTPRequest.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 22 | 410392AC17D45F59006F6AB7 /* ASIInputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 4103929F17D45F59006F6AB7 /* ASIInputStream.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 23 | 410392AD17D45F59006F6AB7 /* ASINetworkQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 410392A117D45F59006F6AB7 /* ASINetworkQueue.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 24 | 410392AE17D45F59006F6AB7 /* Reachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 410392A517D45F59006F6AB7 /* Reachability.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 25 | 410392B017D45FC7006F6AB7 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 410392AF17D45FC7006F6AB7 /* CFNetwork.framework */; }; 26 | 410392B217D45FCB006F6AB7 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 410392B117D45FCB006F6AB7 /* SystemConfiguration.framework */; }; 27 | 410392B417D45FD2006F6AB7 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 410392B317D45FD2006F6AB7 /* MobileCoreServices.framework */; }; 28 | 410392B617D45FE4006F6AB7 /* libz.1.2.5.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 410392B517D45FE4006F6AB7 /* libz.1.2.5.dylib */; }; 29 | 410392B917D4600E006F6AB7 /* LASIImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 410392B817D4600E006F6AB7 /* LASIImageView.m */; }; 30 | 4126B04017D47540004FD6EF /* ViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4126B03F17D47540004FD6EF /* ViewController.xib */; }; 31 | /* End PBXBuildFile section */ 32 | 33 | /* Begin PBXFileReference section */ 34 | 4103924E17D45DE0006F6AB7 /* LASIImageView.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LASIImageView.app; sourceTree = BUILT_PRODUCTS_DIR; }; 35 | 4103925117D45DE0006F6AB7 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 36 | 4103925317D45DE0006F6AB7 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 37 | 4103925517D45DE0006F6AB7 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 38 | 4103927D17D45E1D006F6AB7 /* LASIImageView-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "LASIImageView-Info.plist"; sourceTree = ""; }; 39 | 4103927E17D45E1D006F6AB7 /* LASIImageView-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "LASIImageView-Prefix.pch"; sourceTree = ""; }; 40 | 4103927F17D45E1D006F6AB7 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 41 | 4103928517D45E80006F6AB7 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 42 | 4103928617D45E80006F6AB7 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 43 | 4103928917D45E80006F6AB7 /* ViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 44 | 4103928A17D45E80006F6AB7 /* ViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 45 | 4103928F17D45F59006F6AB7 /* ASIAuthenticationDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIAuthenticationDialog.h; sourceTree = ""; }; 46 | 4103929017D45F59006F6AB7 /* ASIAuthenticationDialog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASIAuthenticationDialog.m; sourceTree = ""; }; 47 | 4103929117D45F59006F6AB7 /* ASICacheDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASICacheDelegate.h; sourceTree = ""; }; 48 | 4103929217D45F59006F6AB7 /* ASIDataCompressor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIDataCompressor.h; sourceTree = ""; }; 49 | 4103929317D45F59006F6AB7 /* ASIDataCompressor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASIDataCompressor.m; sourceTree = ""; }; 50 | 4103929417D45F59006F6AB7 /* ASIDataDecompressor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIDataDecompressor.h; sourceTree = ""; }; 51 | 4103929517D45F59006F6AB7 /* ASIDataDecompressor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASIDataDecompressor.m; sourceTree = ""; }; 52 | 4103929617D45F59006F6AB7 /* ASIDownloadCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIDownloadCache.h; sourceTree = ""; }; 53 | 4103929717D45F59006F6AB7 /* ASIDownloadCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASIDownloadCache.m; sourceTree = ""; }; 54 | 4103929817D45F59006F6AB7 /* ASIFormDataRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIFormDataRequest.h; sourceTree = ""; }; 55 | 4103929917D45F59006F6AB7 /* ASIFormDataRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASIFormDataRequest.m; sourceTree = ""; }; 56 | 4103929A17D45F59006F6AB7 /* ASIHTTPRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIHTTPRequest.h; sourceTree = ""; }; 57 | 4103929B17D45F59006F6AB7 /* ASIHTTPRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASIHTTPRequest.m; sourceTree = ""; }; 58 | 4103929C17D45F59006F6AB7 /* ASIHTTPRequestConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIHTTPRequestConfig.h; sourceTree = ""; }; 59 | 4103929D17D45F59006F6AB7 /* ASIHTTPRequestDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIHTTPRequestDelegate.h; sourceTree = ""; }; 60 | 4103929E17D45F59006F6AB7 /* ASIInputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIInputStream.h; sourceTree = ""; }; 61 | 4103929F17D45F59006F6AB7 /* ASIInputStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASIInputStream.m; sourceTree = ""; }; 62 | 410392A017D45F59006F6AB7 /* ASINetworkQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASINetworkQueue.h; sourceTree = ""; }; 63 | 410392A117D45F59006F6AB7 /* ASINetworkQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASINetworkQueue.m; sourceTree = ""; }; 64 | 410392A217D45F59006F6AB7 /* ASIProgressDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIProgressDelegate.h; sourceTree = ""; }; 65 | 410392A417D45F59006F6AB7 /* Reachability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Reachability.h; sourceTree = ""; }; 66 | 410392A517D45F59006F6AB7 /* Reachability.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Reachability.m; sourceTree = ""; }; 67 | 410392AF17D45FC7006F6AB7 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; }; 68 | 410392B117D45FCB006F6AB7 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; 69 | 410392B317D45FD2006F6AB7 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; }; 70 | 410392B517D45FE4006F6AB7 /* libz.1.2.5.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.1.2.5.dylib; path = usr/lib/libz.1.2.5.dylib; sourceTree = SDKROOT; }; 71 | 410392B717D4600E006F6AB7 /* LASIImageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LASIImageView.h; sourceTree = ""; }; 72 | 410392B817D4600E006F6AB7 /* LASIImageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LASIImageView.m; sourceTree = ""; }; 73 | 4126B03F17D47540004FD6EF /* ViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ViewController.xib; sourceTree = ""; }; 74 | /* End PBXFileReference section */ 75 | 76 | /* Begin PBXFrameworksBuildPhase section */ 77 | 4103924B17D45DE0006F6AB7 /* Frameworks */ = { 78 | isa = PBXFrameworksBuildPhase; 79 | buildActionMask = 2147483647; 80 | files = ( 81 | 410392B617D45FE4006F6AB7 /* libz.1.2.5.dylib in Frameworks */, 82 | 4103925617D45DE0006F6AB7 /* CoreGraphics.framework in Frameworks */, 83 | 410392B417D45FD2006F6AB7 /* MobileCoreServices.framework in Frameworks */, 84 | 410392B217D45FCB006F6AB7 /* SystemConfiguration.framework in Frameworks */, 85 | 410392B017D45FC7006F6AB7 /* CFNetwork.framework in Frameworks */, 86 | 4103925217D45DE0006F6AB7 /* UIKit.framework in Frameworks */, 87 | 4103925417D45DE0006F6AB7 /* Foundation.framework in Frameworks */, 88 | ); 89 | runOnlyForDeploymentPostprocessing = 0; 90 | }; 91 | /* End PBXFrameworksBuildPhase section */ 92 | 93 | /* Begin PBXGroup section */ 94 | 4103924517D45DE0006F6AB7 = { 95 | isa = PBXGroup; 96 | children = ( 97 | 4103925717D45DE0006F6AB7 /* LASIImageView */, 98 | 4103925017D45DE0006F6AB7 /* Frameworks */, 99 | 4103924F17D45DE0006F6AB7 /* Products */, 100 | ); 101 | sourceTree = ""; 102 | }; 103 | 4103924F17D45DE0006F6AB7 /* Products */ = { 104 | isa = PBXGroup; 105 | children = ( 106 | 4103924E17D45DE0006F6AB7 /* LASIImageView.app */, 107 | ); 108 | name = Products; 109 | sourceTree = ""; 110 | }; 111 | 4103925017D45DE0006F6AB7 /* Frameworks */ = { 112 | isa = PBXGroup; 113 | children = ( 114 | 410392B517D45FE4006F6AB7 /* libz.1.2.5.dylib */, 115 | 410392B317D45FD2006F6AB7 /* MobileCoreServices.framework */, 116 | 410392B117D45FCB006F6AB7 /* SystemConfiguration.framework */, 117 | 410392AF17D45FC7006F6AB7 /* CFNetwork.framework */, 118 | 4103925117D45DE0006F6AB7 /* UIKit.framework */, 119 | 4103925317D45DE0006F6AB7 /* Foundation.framework */, 120 | 4103925517D45DE0006F6AB7 /* CoreGraphics.framework */, 121 | ); 122 | name = Frameworks; 123 | sourceTree = ""; 124 | }; 125 | 4103925717D45DE0006F6AB7 /* LASIImageView */ = { 126 | isa = PBXGroup; 127 | children = ( 128 | 4103927717D45E1D006F6AB7 /* Classes */, 129 | 4103928D17D45F59006F6AB7 /* External */, 130 | 4103927C17D45E1D006F6AB7 /* Supporting Files */, 131 | ); 132 | path = LASIImageView; 133 | sourceTree = ""; 134 | }; 135 | 4103927717D45E1D006F6AB7 /* Classes */ = { 136 | isa = PBXGroup; 137 | children = ( 138 | 4103928717D45E80006F6AB7 /* LASIImageView */, 139 | 4103928417D45E80006F6AB7 /* AppDelegate */, 140 | 4103928817D45E80006F6AB7 /* ViewControler */, 141 | ); 142 | path = Classes; 143 | sourceTree = ""; 144 | }; 145 | 4103927C17D45E1D006F6AB7 /* Supporting Files */ = { 146 | isa = PBXGroup; 147 | children = ( 148 | 4103927D17D45E1D006F6AB7 /* LASIImageView-Info.plist */, 149 | 4103927E17D45E1D006F6AB7 /* LASIImageView-Prefix.pch */, 150 | 4103927F17D45E1D006F6AB7 /* main.m */, 151 | ); 152 | path = "Supporting Files"; 153 | sourceTree = ""; 154 | }; 155 | 4103928417D45E80006F6AB7 /* AppDelegate */ = { 156 | isa = PBXGroup; 157 | children = ( 158 | 4103928517D45E80006F6AB7 /* AppDelegate.h */, 159 | 4103928617D45E80006F6AB7 /* AppDelegate.m */, 160 | ); 161 | path = AppDelegate; 162 | sourceTree = ""; 163 | }; 164 | 4103928717D45E80006F6AB7 /* LASIImageView */ = { 165 | isa = PBXGroup; 166 | children = ( 167 | 410392B717D4600E006F6AB7 /* LASIImageView.h */, 168 | 410392B817D4600E006F6AB7 /* LASIImageView.m */, 169 | ); 170 | path = LASIImageView; 171 | sourceTree = ""; 172 | }; 173 | 4103928817D45E80006F6AB7 /* ViewControler */ = { 174 | isa = PBXGroup; 175 | children = ( 176 | 4103928917D45E80006F6AB7 /* ViewController.h */, 177 | 4103928A17D45E80006F6AB7 /* ViewController.m */, 178 | 4126B03F17D47540004FD6EF /* ViewController.xib */, 179 | ); 180 | path = ViewControler; 181 | sourceTree = ""; 182 | }; 183 | 4103928D17D45F59006F6AB7 /* External */ = { 184 | isa = PBXGroup; 185 | children = ( 186 | 4103928E17D45F59006F6AB7 /* ASIHTTPRequest */, 187 | 410392A317D45F59006F6AB7 /* Reachability */, 188 | ); 189 | path = External; 190 | sourceTree = ""; 191 | }; 192 | 4103928E17D45F59006F6AB7 /* ASIHTTPRequest */ = { 193 | isa = PBXGroup; 194 | children = ( 195 | 4103928F17D45F59006F6AB7 /* ASIAuthenticationDialog.h */, 196 | 4103929017D45F59006F6AB7 /* ASIAuthenticationDialog.m */, 197 | 4103929117D45F59006F6AB7 /* ASICacheDelegate.h */, 198 | 4103929217D45F59006F6AB7 /* ASIDataCompressor.h */, 199 | 4103929317D45F59006F6AB7 /* ASIDataCompressor.m */, 200 | 4103929417D45F59006F6AB7 /* ASIDataDecompressor.h */, 201 | 4103929517D45F59006F6AB7 /* ASIDataDecompressor.m */, 202 | 4103929617D45F59006F6AB7 /* ASIDownloadCache.h */, 203 | 4103929717D45F59006F6AB7 /* ASIDownloadCache.m */, 204 | 4103929817D45F59006F6AB7 /* ASIFormDataRequest.h */, 205 | 4103929917D45F59006F6AB7 /* ASIFormDataRequest.m */, 206 | 4103929A17D45F59006F6AB7 /* ASIHTTPRequest.h */, 207 | 4103929B17D45F59006F6AB7 /* ASIHTTPRequest.m */, 208 | 4103929C17D45F59006F6AB7 /* ASIHTTPRequestConfig.h */, 209 | 4103929D17D45F59006F6AB7 /* ASIHTTPRequestDelegate.h */, 210 | 4103929E17D45F59006F6AB7 /* ASIInputStream.h */, 211 | 4103929F17D45F59006F6AB7 /* ASIInputStream.m */, 212 | 410392A017D45F59006F6AB7 /* ASINetworkQueue.h */, 213 | 410392A117D45F59006F6AB7 /* ASINetworkQueue.m */, 214 | 410392A217D45F59006F6AB7 /* ASIProgressDelegate.h */, 215 | ); 216 | path = ASIHTTPRequest; 217 | sourceTree = ""; 218 | }; 219 | 410392A317D45F59006F6AB7 /* Reachability */ = { 220 | isa = PBXGroup; 221 | children = ( 222 | 410392A417D45F59006F6AB7 /* Reachability.h */, 223 | 410392A517D45F59006F6AB7 /* Reachability.m */, 224 | ); 225 | path = Reachability; 226 | sourceTree = ""; 227 | }; 228 | /* End PBXGroup section */ 229 | 230 | /* Begin PBXNativeTarget section */ 231 | 4103924D17D45DE0006F6AB7 /* LASIImageView */ = { 232 | isa = PBXNativeTarget; 233 | buildConfigurationList = 4103927417D45DE0006F6AB7 /* Build configuration list for PBXNativeTarget "LASIImageView" */; 234 | buildPhases = ( 235 | 4103924A17D45DE0006F6AB7 /* Sources */, 236 | 4103924B17D45DE0006F6AB7 /* Frameworks */, 237 | 4103924C17D45DE0006F6AB7 /* Resources */, 238 | ); 239 | buildRules = ( 240 | ); 241 | dependencies = ( 242 | ); 243 | name = LASIImageView; 244 | productName = LASIImageView; 245 | productReference = 4103924E17D45DE0006F6AB7 /* LASIImageView.app */; 246 | productType = "com.apple.product-type.application"; 247 | }; 248 | /* End PBXNativeTarget section */ 249 | 250 | /* Begin PBXProject section */ 251 | 4103924617D45DE0006F6AB7 /* Project object */ = { 252 | isa = PBXProject; 253 | attributes = { 254 | LastUpgradeCheck = 0460; 255 | ORGANIZATIONNAME = "Luka Gabric"; 256 | }; 257 | buildConfigurationList = 4103924917D45DE0006F6AB7 /* Build configuration list for PBXProject "LASIImageView" */; 258 | compatibilityVersion = "Xcode 3.2"; 259 | developmentRegion = English; 260 | hasScannedForEncodings = 0; 261 | knownRegions = ( 262 | en, 263 | ); 264 | mainGroup = 4103924517D45DE0006F6AB7; 265 | productRefGroup = 4103924F17D45DE0006F6AB7 /* Products */; 266 | projectDirPath = ""; 267 | projectRoot = ""; 268 | targets = ( 269 | 4103924D17D45DE0006F6AB7 /* LASIImageView */, 270 | ); 271 | }; 272 | /* End PBXProject section */ 273 | 274 | /* Begin PBXResourcesBuildPhase section */ 275 | 4103924C17D45DE0006F6AB7 /* Resources */ = { 276 | isa = PBXResourcesBuildPhase; 277 | buildActionMask = 2147483647; 278 | files = ( 279 | 4126B04017D47540004FD6EF /* ViewController.xib in Resources */, 280 | ); 281 | runOnlyForDeploymentPostprocessing = 0; 282 | }; 283 | /* End PBXResourcesBuildPhase section */ 284 | 285 | /* Begin PBXSourcesBuildPhase section */ 286 | 4103924A17D45DE0006F6AB7 /* Sources */ = { 287 | isa = PBXSourcesBuildPhase; 288 | buildActionMask = 2147483647; 289 | files = ( 290 | 4103928317D45E1D006F6AB7 /* main.m in Sources */, 291 | 4103928B17D45E80006F6AB7 /* AppDelegate.m in Sources */, 292 | 4103928C17D45E80006F6AB7 /* ViewController.m in Sources */, 293 | 410392A617D45F59006F6AB7 /* ASIAuthenticationDialog.m in Sources */, 294 | 410392A717D45F59006F6AB7 /* ASIDataCompressor.m in Sources */, 295 | 410392A817D45F59006F6AB7 /* ASIDataDecompressor.m in Sources */, 296 | 410392A917D45F59006F6AB7 /* ASIDownloadCache.m in Sources */, 297 | 410392AA17D45F59006F6AB7 /* ASIFormDataRequest.m in Sources */, 298 | 410392AB17D45F59006F6AB7 /* ASIHTTPRequest.m in Sources */, 299 | 410392AC17D45F59006F6AB7 /* ASIInputStream.m in Sources */, 300 | 410392AD17D45F59006F6AB7 /* ASINetworkQueue.m in Sources */, 301 | 410392AE17D45F59006F6AB7 /* Reachability.m in Sources */, 302 | 410392B917D4600E006F6AB7 /* LASIImageView.m in Sources */, 303 | ); 304 | runOnlyForDeploymentPostprocessing = 0; 305 | }; 306 | /* End PBXSourcesBuildPhase section */ 307 | 308 | /* Begin XCBuildConfiguration section */ 309 | 4103927217D45DE0006F6AB7 /* Debug */ = { 310 | isa = XCBuildConfiguration; 311 | buildSettings = { 312 | ALWAYS_SEARCH_USER_PATHS = NO; 313 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 314 | CLANG_CXX_LIBRARY = "libc++"; 315 | CLANG_ENABLE_OBJC_ARC = YES; 316 | CLANG_WARN_CONSTANT_CONVERSION = YES; 317 | CLANG_WARN_EMPTY_BODY = YES; 318 | CLANG_WARN_ENUM_CONVERSION = YES; 319 | CLANG_WARN_INT_CONVERSION = YES; 320 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 321 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 322 | COPY_PHASE_STRIP = NO; 323 | GCC_C_LANGUAGE_STANDARD = gnu99; 324 | GCC_DYNAMIC_NO_PIC = NO; 325 | GCC_OPTIMIZATION_LEVEL = 0; 326 | GCC_PREPROCESSOR_DEFINITIONS = ( 327 | "DEBUG=1", 328 | "$(inherited)", 329 | ); 330 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 331 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 332 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 333 | GCC_WARN_UNUSED_VARIABLE = YES; 334 | IPHONEOS_DEPLOYMENT_TARGET = 6.1; 335 | ONLY_ACTIVE_ARCH = YES; 336 | SDKROOT = iphoneos; 337 | TARGETED_DEVICE_FAMILY = "1,2"; 338 | }; 339 | name = Debug; 340 | }; 341 | 4103927317D45DE0006F6AB7 /* Release */ = { 342 | isa = XCBuildConfiguration; 343 | buildSettings = { 344 | ALWAYS_SEARCH_USER_PATHS = NO; 345 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 346 | CLANG_CXX_LIBRARY = "libc++"; 347 | CLANG_ENABLE_OBJC_ARC = YES; 348 | CLANG_WARN_CONSTANT_CONVERSION = YES; 349 | CLANG_WARN_EMPTY_BODY = YES; 350 | CLANG_WARN_ENUM_CONVERSION = YES; 351 | CLANG_WARN_INT_CONVERSION = YES; 352 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 353 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 354 | COPY_PHASE_STRIP = YES; 355 | GCC_C_LANGUAGE_STANDARD = gnu99; 356 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 357 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 358 | GCC_WARN_UNUSED_VARIABLE = YES; 359 | IPHONEOS_DEPLOYMENT_TARGET = 6.1; 360 | OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; 361 | SDKROOT = iphoneos; 362 | TARGETED_DEVICE_FAMILY = "1,2"; 363 | VALIDATE_PRODUCT = YES; 364 | }; 365 | name = Release; 366 | }; 367 | 4103927517D45DE0006F6AB7 /* Debug */ = { 368 | isa = XCBuildConfiguration; 369 | buildSettings = { 370 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 371 | GCC_PREFIX_HEADER = "LASIImageView/Supporting Files/LASIImageView-Prefix.pch"; 372 | INFOPLIST_FILE = "LASIImageView/Supporting Files/LASIImageView-Info.plist"; 373 | IPHONEOS_DEPLOYMENT_TARGET = 5.0; 374 | PRODUCT_NAME = "$(TARGET_NAME)"; 375 | WRAPPER_EXTENSION = app; 376 | }; 377 | name = Debug; 378 | }; 379 | 4103927617D45DE0006F6AB7 /* Release */ = { 380 | isa = XCBuildConfiguration; 381 | buildSettings = { 382 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 383 | GCC_PREFIX_HEADER = "LASIImageView/Supporting Files/LASIImageView-Prefix.pch"; 384 | INFOPLIST_FILE = "LASIImageView/Supporting Files/LASIImageView-Info.plist"; 385 | IPHONEOS_DEPLOYMENT_TARGET = 5.0; 386 | PRODUCT_NAME = "$(TARGET_NAME)"; 387 | WRAPPER_EXTENSION = app; 388 | }; 389 | name = Release; 390 | }; 391 | /* End XCBuildConfiguration section */ 392 | 393 | /* Begin XCConfigurationList section */ 394 | 4103924917D45DE0006F6AB7 /* Build configuration list for PBXProject "LASIImageView" */ = { 395 | isa = XCConfigurationList; 396 | buildConfigurations = ( 397 | 4103927217D45DE0006F6AB7 /* Debug */, 398 | 4103927317D45DE0006F6AB7 /* Release */, 399 | ); 400 | defaultConfigurationIsVisible = 0; 401 | defaultConfigurationName = Release; 402 | }; 403 | 4103927417D45DE0006F6AB7 /* Build configuration list for PBXNativeTarget "LASIImageView" */ = { 404 | isa = XCConfigurationList; 405 | buildConfigurations = ( 406 | 4103927517D45DE0006F6AB7 /* Debug */, 407 | 4103927617D45DE0006F6AB7 /* Release */, 408 | ); 409 | defaultConfigurationIsVisible = 0; 410 | defaultConfigurationName = Release; 411 | }; 412 | /* End XCConfigurationList section */ 413 | }; 414 | rootObject = 4103924617D45DE0006F6AB7 /* Project object */; 415 | } 416 | -------------------------------------------------------------------------------- /LASIImageView.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /LASIImageView.xcodeproj/project.xcworkspace/xcshareddata/LASIImageView.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | EE69817A-CD6E-4B2C-B58E-F43760F5AF18 9 | IDESourceControlProjectName 10 | LASIImageView 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 746340D7-0A24-46AC-99B8-D31948CE9721 14 | https://github.com/lukagabric/LASIImageView.git 15 | 16 | IDESourceControlProjectPath 17 | LASIImageView.xcodeproj/project.xcworkspace 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | 746340D7-0A24-46AC-99B8-D31948CE9721 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/lukagabric/LASIImageView.git 25 | IDESourceControlProjectVersion 26 | 110 27 | IDESourceControlProjectWCCIdentifier 28 | 746340D7-0A24-46AC-99B8-D31948CE9721 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | 746340D7-0A24-46AC-99B8-D31948CE9721 36 | IDESourceControlWCCName 37 | LASIImageView 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /LASIImageView.xcodeproj/project.xcworkspace/xcuserdata/lukagabric.xcuserdatad/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges 6 | 7 | SnapshotAutomaticallyBeforeSignificantChanges 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /LASIImageView.xcodeproj/xcuserdata/lukagabric.xcuserdatad/xcschemes/LASIImageView.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 51 | 52 | 58 | 59 | 60 | 61 | 62 | 63 | 69 | 70 | 76 | 77 | 78 | 79 | 81 | 82 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /LASIImageView.xcodeproj/xcuserdata/lukagabric.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | LASIImageView.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 4103924D17D45DE0006F6AB7 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /LASIImageView/Classes/AppDelegate/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | 4 | @interface AppDelegate : UIResponder 5 | 6 | 7 | @property (strong, nonatomic) UIWindow *window; 8 | 9 | 10 | @end -------------------------------------------------------------------------------- /LASIImageView/Classes/AppDelegate/AppDelegate.m: -------------------------------------------------------------------------------- 1 | #import "AppDelegate.h" 2 | #import "ViewController.h" 3 | 4 | 5 | @implementation AppDelegate 6 | 7 | 8 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 9 | { 10 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 11 | self.window.rootViewController = [ViewController new]; 12 | [self.window makeKeyAndVisible]; 13 | return YES; 14 | } 15 | 16 | 17 | @end -------------------------------------------------------------------------------- /LASIImageView/Classes/LASIImageView/LASIImageView.h: -------------------------------------------------------------------------------- 1 | #import "ASIHTTPRequest.h" 2 | #import "ASIDownloadCache.h" 3 | #import "ASICacheDelegate.h" 4 | 5 | 6 | typedef enum tagLProgressType 7 | { 8 | LProgressTypeAnnular, 9 | LProgressTypeCircle = 1, 10 | LProgressTypePie = 2 11 | } 12 | LProgressType; 13 | 14 | 15 | @class LASIImageView; 16 | 17 | 18 | typedef void(^LASIImageViewDownloadFinishedBlock)(LASIImageView *, ASIHTTPRequest *); 19 | typedef void(^LASIImageViewDownloadFailedBlock)(LASIImageView *, ASIHTTPRequest *); 20 | 21 | 22 | @class LProgressView, LProgressAppearance, LRequestSettings, LASIImageViewAppearance; 23 | 24 | 25 | @interface LASIImageView : UIImageView 26 | { 27 | ASIHTTPRequest *_request; 28 | __weak LProgressView *_progressView; 29 | 30 | LProgressAppearance *_progressAppearance; 31 | LRequestSettings *_requestSettings; 32 | LASIImageViewAppearance *_asiImageViewAppearance; 33 | } 34 | 35 | 36 | @property (strong, nonatomic) NSString *imageUrl; 37 | 38 | @property (copy, nonatomic) LASIImageViewDownloadFinishedBlock finishedBlock; 39 | @property (copy, nonatomic) LASIImageViewDownloadFailedBlock failedBlock; 40 | 41 | @property (strong, nonatomic) LProgressAppearance *progressAppearance; 42 | @property (strong, nonatomic) LRequestSettings *requestSettings; 43 | @property (strong, nonatomic) LASIImageViewAppearance *asiImageViewAppearance; 44 | 45 | 46 | + (LProgressAppearance *)sharedProgressAppearance; 47 | + (LRequestSettings *)sharedRequestSettings; 48 | + (LASIImageViewAppearance *)sharedASIImageViewAppearance; 49 | 50 | 51 | @end 52 | 53 | 54 | @interface LProgressView : UIView 55 | 56 | 57 | @property (assign, nonatomic) float progress; 58 | @property (strong, nonatomic) LProgressAppearance *progressAppearance; 59 | 60 | 61 | @end 62 | 63 | 64 | @interface LProgressAppearance : NSObject 65 | 66 | 67 | @property (assign, nonatomic) LProgressType type; 68 | //percentage supported for LProgressTypeAnnular and LProgressTypeCircle 69 | @property (assign, nonatomic) BOOL showPercentage; 70 | 71 | //setting schemeColor will set progressTintColor, backgroundTintColor and percentageTextColor 72 | @property (strong, nonatomic) UIColor *schemeColor; 73 | @property (strong, nonatomic) UIColor *progressTintColor; 74 | @property (strong, nonatomic) UIColor *backgroundTintColor; 75 | @property (strong, nonatomic) UIColor *percentageTextColor; 76 | 77 | @property (strong, nonatomic) UIFont *percentageTextFont; 78 | @property (assign, nonatomic) CGPoint percentageTextOffset; 79 | 80 | 81 | + (LProgressAppearance *)sharedProgressAppearance; 82 | 83 | 84 | @end 85 | 86 | 87 | @interface LRequestSettings : NSObject 88 | 89 | 90 | @property (assign, nonatomic) ASICachePolicy cachePolicy; 91 | @property (assign, nonatomic) ASICacheStoragePolicy cacheStoragePolicy; 92 | @property (weak, nonatomic) id cacheDelegate; 93 | @property (assign, nonatomic) NSUInteger secondsToCache; 94 | @property (assign, nonatomic) NSUInteger timeOutSeconds; 95 | 96 | 97 | + (LRequestSettings *)sharedRequestSettings; 98 | 99 | 100 | @end 101 | 102 | 103 | @interface LASIImageViewAppearance : NSObject 104 | 105 | 106 | @property (strong, nonatomic) UIImage *placeholderImage; 107 | @property (strong, nonatomic) NSString *placeholderImageName; 108 | @property (strong, nonatomic) UIImage *downloadFailedImage; 109 | @property (strong, nonatomic) NSString *downloadFailedImageName; 110 | 111 | 112 | + (LASIImageViewAppearance *)sharedASIImageViewAppearance; 113 | 114 | 115 | @end -------------------------------------------------------------------------------- /LASIImageView/Classes/LASIImageView/LASIImageView.m: -------------------------------------------------------------------------------- 1 | #import "LASIImageView.h" 2 | #import 3 | 4 | 5 | @implementation LASIImageView 6 | 7 | 8 | #pragma mark - init & dealloc 9 | 10 | 11 | - (id)init 12 | { 13 | self = [super init]; 14 | if (self) 15 | { 16 | [self initialize]; 17 | } 18 | return self; 19 | } 20 | 21 | 22 | - (id)initWithFrame:(CGRect)frame 23 | { 24 | self = [super initWithFrame:frame]; 25 | if (self) 26 | { 27 | [self initialize]; 28 | } 29 | return self; 30 | } 31 | 32 | 33 | - (id)initWithImage:(UIImage *)image 34 | { 35 | self = [super initWithImage:image]; 36 | if (self) 37 | { 38 | [self initialize]; 39 | } 40 | return self; 41 | } 42 | 43 | 44 | - (id)initWithImage:(UIImage *)image highlightedImage:(UIImage *)highlightedImage 45 | { 46 | self = [super initWithImage:image highlightedImage:highlightedImage]; 47 | if (self) 48 | { 49 | [self initialize]; 50 | } 51 | return self; 52 | } 53 | 54 | 55 | - (id)initWithCoder:(NSCoder *)aDecoder 56 | { 57 | self = [super initWithCoder:aDecoder]; 58 | if (self) 59 | { 60 | [self initialize]; 61 | } 62 | return self; 63 | } 64 | 65 | 66 | - (void)initialize 67 | { 68 | 69 | } 70 | 71 | 72 | - (void)dealloc 73 | { 74 | [self freeAll]; 75 | } 76 | 77 | 78 | #pragma mark - layoutSubviews 79 | 80 | 81 | - (void)layoutSubviews 82 | { 83 | _progressView.frame = CGRectMake(floorf(self.frame.size.width/2 - _progressView.frame.size.width/2), floorf(self.frame.size.height/2 - _progressView.frame.size.height/2), _progressView.frame.size.width, _progressView.frame.size.height); 84 | } 85 | 86 | 87 | #pragma mark - Progress view 88 | 89 | 90 | - (void)loadProgressView 91 | { 92 | [self freeProgressView]; 93 | 94 | LProgressView *progressView = [[LProgressView alloc] initWithFrame:CGRectMake(0, 0, 37, 37)]; 95 | 96 | if (_progressAppearance) 97 | progressView.progressAppearance = _progressAppearance; 98 | 99 | _progressView = progressView; 100 | 101 | [self addSubview:_progressView]; 102 | } 103 | 104 | 105 | #pragma mark - downloadImage 106 | 107 | 108 | - (void)downloadImage 109 | { 110 | [self freeAll]; 111 | 112 | NSURL *imageURL = [NSURL URLWithString:_imageUrl]; 113 | 114 | if (!imageURL) 115 | { 116 | [self requestFailed:nil]; 117 | return; 118 | } 119 | 120 | _request = [ASIHTTPRequest requestWithURL:imageURL usingCache:self.requestSettings.cacheDelegate andCachePolicy:self.requestSettings.cachePolicy]; 121 | _request.cacheStoragePolicy = self.requestSettings.cacheStoragePolicy; 122 | _request.secondsToCache = self.requestSettings.secondsToCache; 123 | _request.timeOutSeconds = self.requestSettings.timeOutSeconds; 124 | _request.downloadProgressDelegate = self; 125 | 126 | __weak typeof(self) weakSelf = self; 127 | __weak ASIHTTPRequest *weakReq = _request; 128 | 129 | [_request setCompletionBlock:^{ 130 | [weakSelf requestFinished:weakReq]; 131 | }]; 132 | 133 | [_request setFailedBlock:^{ 134 | [weakSelf requestFailed:weakReq]; 135 | }]; 136 | 137 | if ([[ASIDownloadCache sharedCache] isCachedDataCurrentForRequest:_request]) 138 | { 139 | [self loadCachedImage]; 140 | } 141 | else 142 | { 143 | [self loadProgressView]; 144 | [_request startAsynchronous]; 145 | } 146 | } 147 | 148 | 149 | - (void)loadCachedImage 150 | { 151 | NSString *filePath = [[ASIDownloadCache sharedCache] pathToStoreCachedResponseDataForRequest:_request]; 152 | 153 | if (filePath != nil && [[NSFileManager defaultManager] fileExistsAtPath:filePath]) 154 | { 155 | UIImage *cachedImage = [UIImage imageWithContentsOfFile:filePath]; 156 | 157 | if (cachedImage) 158 | super.image = cachedImage; 159 | } 160 | } 161 | 162 | 163 | - (void)loadPlaceholderImage 164 | { 165 | if (!self.image) 166 | { 167 | if (self.asiImageViewAppearance.placeholderImage) 168 | self.image = self.asiImageViewAppearance.placeholderImage; 169 | else if (self.asiImageViewAppearance.placeholderImageName) 170 | self.image = [UIImage imageNamed:self.asiImageViewAppearance.placeholderImageName]; 171 | } 172 | } 173 | 174 | 175 | - (void)loadDownloadFailedImage 176 | { 177 | [self loadCachedImage]; 178 | 179 | if (!self.image) 180 | { 181 | if (self.asiImageViewAppearance.downloadFailedImage) 182 | self.image = self.asiImageViewAppearance.downloadFailedImage; 183 | else if (self.asiImageViewAppearance.downloadFailedImageName) 184 | self.image = [UIImage imageNamed:self.asiImageViewAppearance.downloadFailedImageName]; 185 | } 186 | } 187 | 188 | 189 | - (void)cancelImageDownload 190 | { 191 | [self freeAll]; 192 | } 193 | 194 | 195 | #pragma mark - ASIHTTPRequestDelegate 196 | 197 | 198 | - (void)requestFinished:(ASIHTTPRequest *)request 199 | { 200 | UIImage *downloadedImage = [UIImage imageWithData:request.responseData]; 201 | 202 | if (downloadedImage) 203 | { 204 | self.image = downloadedImage; 205 | [self freeAll]; 206 | 207 | if (_finishedBlock) 208 | _finishedBlock(self, request); 209 | } 210 | else 211 | { 212 | [self requestFailed:nil]; 213 | } 214 | } 215 | 216 | 217 | - (void)requestFailed:(ASIHTTPRequest *)request 218 | { 219 | [self loadDownloadFailedImage]; 220 | [self freeAll]; 221 | 222 | if (_failedBlock) 223 | _failedBlock(self, request); 224 | } 225 | 226 | 227 | #pragma mark - ASIProgressDelegate 228 | 229 | 230 | - (void)setProgress:(float)newProgress 231 | { 232 | _progressView.progress = newProgress; 233 | } 234 | 235 | 236 | #pragma mark - Free 237 | 238 | 239 | - (void)freeRequest 240 | { 241 | if (_request) 242 | { 243 | [_request clearDelegatesAndCancel]; 244 | _request = nil; 245 | } 246 | } 247 | 248 | 249 | - (void)freeProgressView 250 | { 251 | if (_progressView) 252 | { 253 | if (_progressView.superview) 254 | [_progressView removeFromSuperview]; 255 | 256 | _progressView = nil; 257 | } 258 | } 259 | 260 | 261 | - (void)freeAll 262 | { 263 | [self freeRequest]; 264 | [self freeProgressView]; 265 | } 266 | 267 | 268 | #pragma mark - Setters 269 | 270 | 271 | - (void)setImage:(UIImage *)image 272 | { 273 | [self cancelImageDownload]; 274 | 275 | [super setImage:image]; 276 | } 277 | 278 | 279 | - (void)setImageUrl:(NSString *)imageUrl 280 | { 281 | _imageUrl = imageUrl; 282 | 283 | self.image = nil; 284 | 285 | [self downloadImage]; 286 | } 287 | 288 | 289 | - (void)setProgressAppearance:(LProgressAppearance *)progressAppearance 290 | { 291 | _progressAppearance = progressAppearance; 292 | 293 | if (_progressView) 294 | _progressView.progressAppearance = _progressAppearance; 295 | } 296 | 297 | 298 | #pragma mark - Getters 299 | 300 | 301 | - (LProgressAppearance *)progressAppearance 302 | { 303 | @synchronized(self) 304 | { 305 | if (_progressAppearance) 306 | return _progressAppearance; 307 | 308 | return [LProgressAppearance sharedProgressAppearance]; 309 | } 310 | } 311 | 312 | 313 | - (LRequestSettings *)requestSettings 314 | { 315 | @synchronized(self) 316 | { 317 | if (_requestSettings) 318 | return _requestSettings; 319 | 320 | return [LRequestSettings sharedRequestSettings]; 321 | } 322 | } 323 | 324 | 325 | - (LASIImageViewAppearance *)asiImageViewAppearance 326 | { 327 | @synchronized(self) 328 | { 329 | if (_asiImageViewAppearance) 330 | return _asiImageViewAppearance; 331 | 332 | return [LASIImageViewAppearance sharedASIImageViewAppearance]; 333 | } 334 | } 335 | 336 | 337 | + (LProgressAppearance *)sharedProgressAppearance 338 | { 339 | return [LProgressAppearance sharedProgressAppearance]; 340 | } 341 | 342 | 343 | + (LRequestSettings *)sharedRequestSettings 344 | { 345 | return [LRequestSettings sharedRequestSettings]; 346 | } 347 | 348 | 349 | + (LASIImageViewAppearance *)sharedASIImageViewAppearance 350 | { 351 | return [LASIImageViewAppearance sharedASIImageViewAppearance]; 352 | } 353 | 354 | 355 | #pragma mark - 356 | 357 | 358 | @end 359 | 360 | 361 | #pragma mark - LRoundProgressView 362 | 363 | 364 | @implementation LProgressView 365 | 366 | 367 | - (LProgressAppearance *)progressAppearance 368 | { 369 | @synchronized(self) 370 | { 371 | if (_progressAppearance) 372 | return _progressAppearance; 373 | 374 | return [LProgressAppearance sharedProgressAppearance]; 375 | } 376 | } 377 | 378 | 379 | #pragma mark - init & dealloc 380 | 381 | 382 | - (id)init 383 | { 384 | return [self initWithFrame:CGRectMake(0.f, 0.f, 37.f, 37.f)]; 385 | } 386 | 387 | 388 | - (id)initWithFrame:(CGRect)frame 389 | { 390 | self = [super initWithFrame:frame]; 391 | if (self) 392 | { 393 | self.backgroundColor = [UIColor clearColor]; 394 | self.opaque = NO; 395 | _progress = 0.f; 396 | [self registerForKVO]; 397 | } 398 | return self; 399 | } 400 | 401 | 402 | - (void)dealloc 403 | { 404 | [self unregisterFromKVO]; 405 | } 406 | 407 | 408 | #pragma mark - Drawing 409 | 410 | 411 | - (void)drawRect:(CGRect)rect 412 | { 413 | CGRect allRect = self.bounds; 414 | CGContextRef context = UIGraphicsGetCurrentContext(); 415 | 416 | LProgressAppearance *appearance = self.progressAppearance; 417 | 418 | if (appearance.type == LProgressTypeAnnular) 419 | { 420 | CGFloat lineWidth = 5.f; 421 | UIBezierPath *processBackgroundPath = [UIBezierPath bezierPath]; 422 | processBackgroundPath.lineWidth = lineWidth; 423 | processBackgroundPath.lineCapStyle = kCGLineCapRound; 424 | CGPoint center = CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2); 425 | CGFloat radius = (self.bounds.size.width - lineWidth)/2; 426 | CGFloat startAngle = - ((float)M_PI / 2); 427 | CGFloat endAngle = (2 * (float)M_PI) + startAngle; 428 | [processBackgroundPath addArcWithCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES]; 429 | [appearance.backgroundTintColor set]; 430 | [processBackgroundPath stroke]; 431 | 432 | UIBezierPath *processPath = [UIBezierPath bezierPath]; 433 | processPath.lineCapStyle = kCGLineCapRound; 434 | processPath.lineWidth = lineWidth; 435 | endAngle = (self.progress * 2 * (float)M_PI) + startAngle; 436 | [processPath addArcWithCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES]; 437 | [appearance.progressTintColor set]; 438 | [processPath stroke]; 439 | 440 | if (appearance.showPercentage) 441 | [self drawTextInContext:context]; 442 | } 443 | else if (appearance.type == LProgressTypeCircle) 444 | { 445 | CGColorRef colorBackAlpha = CGColorCreateCopyWithAlpha(appearance.backgroundTintColor. CGColor, 0.05f); 446 | CGColorRef colorProgressAlpha = CGColorCreateCopyWithAlpha(appearance.progressTintColor. CGColor, 0.2f); 447 | 448 | CGRect allRect = rect; 449 | CGRect circleRect = CGRectMake(allRect.origin.x + 2, allRect.origin.y + 2, allRect.size.width - 4, allRect.size.height - 4); 450 | float x = allRect.origin.x + (allRect.size.width / 2); 451 | float y = allRect.origin.y + (allRect.size.height / 2); 452 | float angle = (_progress) * 360.0f; 453 | 454 | CGContextSaveGState(context); 455 | CGContextSetStrokeColorWithColor(context, colorProgressAlpha); 456 | CGContextSetFillColorWithColor(context, colorBackAlpha); 457 | CGContextSetLineWidth(context, 2.0); 458 | CGContextFillEllipseInRect(context, circleRect); 459 | CGContextStrokeEllipseInRect(context, circleRect); 460 | 461 | CGContextSetRGBFillColor(context, 1.0, 0.0, 1.0, 1.0); 462 | CGContextMoveToPoint(context, x, y); 463 | CGContextAddArc(context, x, y, (allRect.size.width + 4) / 2, -M_PI / 2, (angle * M_PI) / 180.0f - M_PI / 2, 0); 464 | CGContextClip(context); 465 | 466 | CGContextSetStrokeColorWithColor(context, appearance.progressTintColor.CGColor); 467 | CGContextSetFillColorWithColor(context, appearance.backgroundTintColor.CGColor); 468 | CGContextSetLineWidth(context, 2.0); 469 | CGContextFillEllipseInRect(context, circleRect); 470 | CGContextStrokeEllipseInRect(context, circleRect); 471 | CGContextRestoreGState(context); 472 | 473 | if (appearance.showPercentage) 474 | [self drawTextInContext:context]; 475 | } 476 | else 477 | { 478 | CGRect circleRect = CGRectInset(allRect, 2.0f, 2.0f); 479 | 480 | CGColorRef colorBackAlpha = CGColorCreateCopyWithAlpha(appearance.backgroundTintColor. CGColor, 0.1f); 481 | 482 | [appearance.progressTintColor setStroke]; 483 | CGContextSetFillColorWithColor(context, colorBackAlpha); 484 | 485 | CGContextSetLineWidth(context, 2.0f); 486 | CGContextFillEllipseInRect(context, circleRect); 487 | CGContextStrokeEllipseInRect(context, circleRect); 488 | 489 | CGPoint center = CGPointMake(allRect.size.width / 2, allRect.size.height / 2); 490 | CGFloat radius = (allRect.size.width - 4) / 2 - 3; 491 | CGFloat startAngle = - ((float)M_PI / 2); 492 | CGFloat endAngle = (self.progress * 2 * (float)M_PI) + startAngle; 493 | [appearance.progressTintColor setFill]; 494 | CGContextMoveToPoint(context, center.x, center.y); 495 | CGContextAddArc(context, center.x, center.y, radius, startAngle, endAngle, 0); 496 | CGContextClosePath(context); 497 | CGContextFillPath(context); 498 | } 499 | } 500 | 501 | 502 | - (void)drawTextInContext:(CGContextRef)context 503 | { 504 | LProgressAppearance *appearance = self.progressAppearance; 505 | 506 | CGRect allRect = self.bounds; 507 | 508 | UIFont *font = appearance.percentageTextFont; 509 | NSString *text = [NSString stringWithFormat:@"%i%%", (int)(_progress * 100.0f)]; 510 | 511 | CGSize textSize = [text sizeWithFont:font constrainedToSize:CGSizeMake(30000, 13)]; 512 | 513 | float x = floorf(allRect.size.width / 2) + 3 + appearance.percentageTextOffset.x; 514 | float y = floorf(allRect.size.height / 2) - 6 + appearance.percentageTextOffset.y; 515 | 516 | CGContextSetFillColorWithColor(context, appearance.percentageTextColor.CGColor); 517 | [text drawAtPoint:CGPointMake(x - textSize.width / 2.0, y) withFont:font]; 518 | } 519 | 520 | 521 | #pragma mark - KVO 522 | 523 | 524 | - (void)registerForKVO 525 | { 526 | for (NSString *keyPath in [self observableKeypaths]) 527 | { 528 | [self addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:NULL]; 529 | } 530 | } 531 | 532 | 533 | - (void)unregisterFromKVO 534 | { 535 | for (NSString *keyPath in [self observableKeypaths]) 536 | { 537 | [self removeObserver:self forKeyPath:keyPath]; 538 | } 539 | } 540 | 541 | 542 | - (NSArray *)observableKeypaths 543 | { 544 | return [NSArray arrayWithObjects:@"progressAppearance", @"progress", nil]; 545 | } 546 | 547 | 548 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 549 | { 550 | [self setNeedsDisplay]; 551 | } 552 | 553 | 554 | #pragma mark - 555 | 556 | 557 | @end 558 | 559 | 560 | @implementation LProgressAppearance 561 | 562 | 563 | static LProgressAppearance *sharedProgressAppearanceInstance = nil; 564 | 565 | 566 | + (LProgressAppearance *)sharedProgressAppearance 567 | { 568 | @synchronized(self) 569 | { 570 | if (sharedProgressAppearanceInstance) 571 | return sharedProgressAppearanceInstance; 572 | 573 | return sharedProgressAppearanceInstance = [LProgressAppearance new]; 574 | } 575 | } 576 | 577 | 578 | #pragma mark - init 579 | 580 | 581 | - (id)init 582 | { 583 | self = [super init]; 584 | if (self) 585 | { 586 | self.schemeColor = [UIColor whiteColor]; 587 | _percentageTextFont = [UIFont systemFontOfSize:10]; 588 | _percentageTextOffset = CGPointZero; 589 | _type = 0; 590 | _showPercentage = YES; 591 | } 592 | return self; 593 | } 594 | 595 | 596 | #pragma mark - Setters 597 | 598 | 599 | - (void)setSchemeColor:(UIColor *)schemeColor 600 | { 601 | _schemeColor = schemeColor; 602 | 603 | _progressTintColor = [UIColor colorWithCGColor:CGColorCreateCopyWithAlpha(schemeColor.CGColor, 1)]; 604 | _backgroundTintColor = [UIColor colorWithCGColor:CGColorCreateCopyWithAlpha(schemeColor.CGColor, 0.1)]; 605 | _percentageTextColor = [UIColor colorWithCGColor:CGColorCreateCopyWithAlpha(schemeColor.CGColor, 1)]; 606 | } 607 | 608 | 609 | #pragma mark - 610 | 611 | 612 | @end 613 | 614 | 615 | @implementation LRequestSettings 616 | 617 | 618 | #pragma mark - LRequestSettings 619 | 620 | 621 | static LRequestSettings *sharedRequestSettingsInstance = nil; 622 | 623 | 624 | + (LRequestSettings *)sharedRequestSettings 625 | { 626 | @synchronized(self) 627 | { 628 | if (sharedRequestSettingsInstance) 629 | return sharedRequestSettingsInstance; 630 | 631 | return sharedRequestSettingsInstance = [LRequestSettings new]; 632 | } 633 | } 634 | 635 | 636 | - (id)init 637 | { 638 | self = [super init]; 639 | if (self) 640 | { 641 | _secondsToCache = 900; 642 | _timeOutSeconds = 8; 643 | _cacheDelegate = [ASIDownloadCache sharedCache]; 644 | _cacheStoragePolicy = ASICachePermanentlyCacheStoragePolicy; 645 | _cachePolicy = ASIAskServerIfModifiedWhenStaleCachePolicy; 646 | } 647 | return self; 648 | } 649 | 650 | 651 | @end 652 | 653 | 654 | @implementation LASIImageViewAppearance 655 | 656 | 657 | #pragma mark - LASIImageViewAppearance 658 | 659 | 660 | static LASIImageViewAppearance *sharedImageViewAppearanceInstance = nil; 661 | 662 | 663 | + (LASIImageViewAppearance *)sharedASIImageViewAppearance 664 | { 665 | @synchronized(self) 666 | { 667 | if (sharedImageViewAppearanceInstance) 668 | return sharedImageViewAppearanceInstance; 669 | 670 | return sharedImageViewAppearanceInstance = [LASIImageViewAppearance new]; 671 | } 672 | } 673 | 674 | 675 | @end -------------------------------------------------------------------------------- /LASIImageView/Classes/ViewControler/ViewController.h: -------------------------------------------------------------------------------- 1 | #import "LASIImageView.h" 2 | 3 | 4 | @interface ViewController : UIViewController 5 | { 6 | __weak IBOutlet LASIImageView *_imageView; 7 | __weak IBOutlet LASIImageView *_imageView2; 8 | __weak IBOutlet LASIImageView *_imageView3; 9 | } 10 | 11 | 12 | @end -------------------------------------------------------------------------------- /LASIImageView/Classes/ViewControler/ViewController.m: -------------------------------------------------------------------------------- 1 | #import "ViewController.h" 2 | 3 | 4 | @implementation ViewController 5 | 6 | 7 | - (void)viewDidLoad 8 | { 9 | [super viewDidLoad]; 10 | 11 | [[LASIImageView sharedProgressAppearance] setType:LProgressTypeAnnular]; 12 | [[LASIImageView sharedProgressAppearance] setSchemeColor:[UIColor whiteColor]]; 13 | [[LASIImageView sharedRequestSettings] setSecondsToCache:5]; 14 | 15 | _imageView.imageUrl = @"http://farm9.staticflickr.com/8190/8148007408_8fbac75988_o.jpg"; 16 | 17 | LRequestSettings *reqSettings = [LRequestSettings new]; 18 | reqSettings.secondsToCache = 20; 19 | 20 | LProgressAppearance *progressAppearance = [LProgressAppearance new]; 21 | progressAppearance.schemeColor = [UIColor redColor]; 22 | 23 | _imageView2.requestSettings = reqSettings; 24 | _imageView2.progressAppearance = progressAppearance; 25 | _imageView2.imageUrl = @"http://www.fromparis.com/panoramas_quicktime_vr/hand-held_panorama_in_3_mnts/hand-held_panorama_in_3_mnts_5000.jpg"; 26 | 27 | _imageView3.imageUrl = @"http://www.larkinweb.co.uk/panoramas/lake_placid/Lake_Placid_south_medium_res_panorama.jpg"; 28 | } 29 | 30 | 31 | @end -------------------------------------------------------------------------------- /LASIImageView/Classes/ViewControler/ViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /LASIImageView/External/ASIHTTPRequest/ASIAuthenticationDialog.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASIAuthenticationDialog.h 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 21/08/2009. 6 | // Copyright 2009 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | @class ASIHTTPRequest; 12 | 13 | typedef enum _ASIAuthenticationType { 14 | ASIStandardAuthenticationType = 0, 15 | ASIProxyAuthenticationType = 1 16 | } ASIAuthenticationType; 17 | 18 | @interface ASIAutorotatingViewController : UIViewController 19 | @end 20 | 21 | @interface ASIAuthenticationDialog : ASIAutorotatingViewController { 22 | ASIHTTPRequest *request; 23 | ASIAuthenticationType type; 24 | UITableView *tableView; 25 | UIViewController *presentingController; 26 | BOOL didEnableRotationNotifications; 27 | } 28 | + (void)presentAuthenticationDialogForRequest:(ASIHTTPRequest *)request; 29 | + (void)dismiss; 30 | 31 | @property (retain) ASIHTTPRequest *request; 32 | @property (assign) ASIAuthenticationType type; 33 | @property (assign) BOOL didEnableRotationNotifications; 34 | @property (retain, nonatomic) UIViewController *presentingController; 35 | @end 36 | -------------------------------------------------------------------------------- /LASIImageView/External/ASIHTTPRequest/ASIAuthenticationDialog.m: -------------------------------------------------------------------------------- 1 | // 2 | // ASIAuthenticationDialog.m 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 21/08/2009. 6 | // Copyright 2009 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import "ASIAuthenticationDialog.h" 10 | #import "ASIHTTPRequest.h" 11 | #import 12 | 13 | static ASIAuthenticationDialog *sharedDialog = nil; 14 | BOOL isDismissing = NO; 15 | static NSMutableArray *requestsNeedingAuthentication = nil; 16 | 17 | static const NSUInteger kUsernameRow = 0; 18 | static const NSUInteger kUsernameSection = 0; 19 | static const NSUInteger kPasswordRow = 1; 20 | static const NSUInteger kPasswordSection = 0; 21 | static const NSUInteger kDomainRow = 0; 22 | static const NSUInteger kDomainSection = 1; 23 | 24 | 25 | @implementation ASIAutorotatingViewController 26 | 27 | - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation 28 | { 29 | return YES; 30 | } 31 | 32 | @end 33 | 34 | 35 | @interface ASIAuthenticationDialog () 36 | - (void)showTitle; 37 | - (void)show; 38 | - (NSArray *)requestsRequiringTheseCredentials; 39 | - (void)presentNextDialog; 40 | - (void)keyboardWillShow:(NSNotification *)notification; 41 | - (void)orientationChanged:(NSNotification *)notification; 42 | - (void)cancelAuthenticationFromDialog:(id)sender; 43 | - (void)loginWithCredentialsFromDialog:(id)sender; 44 | @property (retain) UITableView *tableView; 45 | @end 46 | 47 | @implementation ASIAuthenticationDialog 48 | 49 | #pragma mark init / dealloc 50 | 51 | + (void)initialize 52 | { 53 | if (self == [ASIAuthenticationDialog class]) { 54 | requestsNeedingAuthentication = [[NSMutableArray array] retain]; 55 | } 56 | } 57 | 58 | + (void)presentAuthenticationDialogForRequest:(ASIHTTPRequest *)theRequest 59 | { 60 | // No need for a lock here, this will always be called on the main thread 61 | if (!sharedDialog) { 62 | sharedDialog = [[self alloc] init]; 63 | [sharedDialog setRequest:theRequest]; 64 | if ([theRequest authenticationNeeded] == ASIProxyAuthenticationNeeded) { 65 | [sharedDialog setType:ASIProxyAuthenticationType]; 66 | } else { 67 | [sharedDialog setType:ASIStandardAuthenticationType]; 68 | } 69 | [sharedDialog show]; 70 | } else { 71 | [requestsNeedingAuthentication addObject:theRequest]; 72 | } 73 | } 74 | 75 | - (id)init 76 | { 77 | if ((self = [self initWithNibName:nil bundle:nil])) { 78 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; 79 | 80 | #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2 81 | if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) { 82 | #endif 83 | if (![UIDevice currentDevice].generatesDeviceOrientationNotifications) { 84 | [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; 85 | [self setDidEnableRotationNotifications:YES]; 86 | } 87 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:nil]; 88 | #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2 89 | } 90 | #endif 91 | } 92 | return self; 93 | } 94 | 95 | - (void)dealloc 96 | { 97 | if ([self didEnableRotationNotifications]) { 98 | [[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil]; 99 | } 100 | [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil]; 101 | 102 | [request release]; 103 | [tableView release]; 104 | [presentingController.view removeFromSuperview]; 105 | [presentingController release]; 106 | [super dealloc]; 107 | } 108 | 109 | #pragma mark keyboard notifications 110 | 111 | - (void)keyboardWillShow:(NSNotification *)notification 112 | { 113 | #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2 114 | if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) { 115 | #endif 116 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_3_2 117 | NSValue *keyboardBoundsValue = [[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey]; 118 | #else 119 | NSValue *keyboardBoundsValue = [[notification userInfo] objectForKey:UIKeyboardBoundsUserInfoKey]; 120 | #endif 121 | CGRect keyboardBounds; 122 | [keyboardBoundsValue getValue:&keyboardBounds]; 123 | UIEdgeInsets e = UIEdgeInsetsMake(0, 0, keyboardBounds.size.height, 0); 124 | [[self tableView] setScrollIndicatorInsets:e]; 125 | [[self tableView] setContentInset:e]; 126 | #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2 127 | } 128 | #endif 129 | } 130 | 131 | // Manually handles orientation changes on iPhone 132 | - (void)orientationChanged:(NSNotification *)notification 133 | { 134 | [self showTitle]; 135 | 136 | UIInterfaceOrientation o = (UIInterfaceOrientation)[[UIApplication sharedApplication] statusBarOrientation]; 137 | CGFloat angle = 0; 138 | switch (o) { 139 | case UIDeviceOrientationLandscapeLeft: angle = 90; break; 140 | case UIDeviceOrientationLandscapeRight: angle = -90; break; 141 | case UIDeviceOrientationPortraitUpsideDown: angle = 180; break; 142 | default: break; 143 | } 144 | 145 | CGRect f = [[UIScreen mainScreen] applicationFrame]; 146 | 147 | // Swap the frame height and width if necessary 148 | if (UIDeviceOrientationIsLandscape(o)) { 149 | CGFloat t; 150 | t = f.size.width; 151 | f.size.width = f.size.height; 152 | f.size.height = t; 153 | } 154 | 155 | CGAffineTransform previousTransform = self.view.layer.affineTransform; 156 | CGAffineTransform newTransform = CGAffineTransformMakeRotation((CGFloat)(angle * M_PI / 180.0)); 157 | 158 | // Reset the transform so we can set the size 159 | self.view.layer.affineTransform = CGAffineTransformIdentity; 160 | self.view.frame = (CGRect){ { 0, 0 }, f.size}; 161 | 162 | // Revert to the previous transform for correct animation 163 | self.view.layer.affineTransform = previousTransform; 164 | 165 | [UIView beginAnimations:nil context:NULL]; 166 | [UIView setAnimationDuration:0.3]; 167 | 168 | // Set the new transform 169 | self.view.layer.affineTransform = newTransform; 170 | 171 | // Fix the view origin 172 | self.view.frame = (CGRect){ { f.origin.x, f.origin.y },self.view.frame.size}; 173 | [UIView commitAnimations]; 174 | } 175 | 176 | #pragma mark utilities 177 | 178 | - (UIViewController *)presentingController 179 | { 180 | if (!presentingController) { 181 | presentingController = [[ASIAutorotatingViewController alloc] initWithNibName:nil bundle:nil]; 182 | 183 | // Attach to the window, but don't interfere. 184 | UIWindow *window = [[[UIApplication sharedApplication] windows] objectAtIndex:0]; 185 | [window addSubview:[presentingController view]]; 186 | [[presentingController view] setFrame:CGRectZero]; 187 | [[presentingController view] setUserInteractionEnabled:NO]; 188 | } 189 | 190 | return presentingController; 191 | } 192 | 193 | - (UITextField *)textFieldInRow:(NSUInteger)row section:(NSUInteger)section 194 | { 195 | return [[[[[self tableView] cellForRowAtIndexPath: 196 | [NSIndexPath indexPathForRow:row inSection:section]] 197 | contentView] subviews] objectAtIndex:0]; 198 | } 199 | 200 | - (UITextField *)usernameField 201 | { 202 | return [self textFieldInRow:kUsernameRow section:kUsernameSection]; 203 | } 204 | 205 | - (UITextField *)passwordField 206 | { 207 | return [self textFieldInRow:kPasswordRow section:kPasswordSection]; 208 | } 209 | 210 | - (UITextField *)domainField 211 | { 212 | return [self textFieldInRow:kDomainRow section:kDomainSection]; 213 | } 214 | 215 | #pragma mark show / dismiss 216 | 217 | + (void)dismiss 218 | { 219 | if ([sharedDialog respondsToSelector:@selector(presentingViewController)]) 220 | [[sharedDialog presentingViewController] dismissModalViewControllerAnimated:YES]; 221 | else 222 | [[sharedDialog parentViewController] dismissModalViewControllerAnimated:YES]; 223 | } 224 | 225 | - (void)viewDidDisappear:(BOOL)animated 226 | { 227 | [self retain]; 228 | [sharedDialog release]; 229 | sharedDialog = nil; 230 | [self performSelector:@selector(presentNextDialog) withObject:nil afterDelay:0]; 231 | [self release]; 232 | } 233 | 234 | - (void)dismiss 235 | { 236 | if (self == sharedDialog) { 237 | [[self class] dismiss]; 238 | } else { 239 | if ([self respondsToSelector:@selector(presentingViewController)]) 240 | [[self presentingViewController] dismissModalViewControllerAnimated:YES]; 241 | else 242 | [[self parentViewController] dismissModalViewControllerAnimated:YES]; 243 | } 244 | } 245 | 246 | - (void)showTitle 247 | { 248 | UINavigationBar *navigationBar = [[[self view] subviews] objectAtIndex:0]; 249 | UINavigationItem *navItem = [[navigationBar items] objectAtIndex:0]; 250 | if (UIInterfaceOrientationIsPortrait([[UIDevice currentDevice] orientation])) { 251 | // Setup the title 252 | if ([self type] == ASIProxyAuthenticationType) { 253 | [navItem setPrompt:@"Login to this secure proxy server."]; 254 | } else { 255 | [navItem setPrompt:@"Login to this secure server."]; 256 | } 257 | } else { 258 | [navItem setPrompt:nil]; 259 | } 260 | [navigationBar sizeToFit]; 261 | CGRect f = [[self view] bounds]; 262 | f.origin.y = [navigationBar frame].size.height; 263 | f.size.height -= f.origin.y; 264 | [[self tableView] setFrame:f]; 265 | } 266 | 267 | - (void)show 268 | { 269 | // Remove all subviews 270 | UIView *v; 271 | while ((v = [[[self view] subviews] lastObject])) { 272 | [v removeFromSuperview]; 273 | } 274 | 275 | // Setup toolbar 276 | UINavigationBar *bar = [[[UINavigationBar alloc] init] autorelease]; 277 | [bar setAutoresizingMask:UIViewAutoresizingFlexibleWidth]; 278 | 279 | UINavigationItem *navItem = [[[UINavigationItem alloc] init] autorelease]; 280 | bar.items = [NSArray arrayWithObject:navItem]; 281 | 282 | [[self view] addSubview:bar]; 283 | 284 | [self showTitle]; 285 | 286 | // Setup toolbar buttons 287 | if ([self type] == ASIProxyAuthenticationType) { 288 | [navItem setTitle:[[self request] proxyHost]]; 289 | } else { 290 | [navItem setTitle:[[[self request] url] host]]; 291 | } 292 | 293 | [navItem setLeftBarButtonItem:[[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancelAuthenticationFromDialog:)] autorelease]]; 294 | [navItem setRightBarButtonItem:[[[UIBarButtonItem alloc] initWithTitle:@"Login" style:UIBarButtonItemStyleDone target:self action:@selector(loginWithCredentialsFromDialog:)] autorelease]]; 295 | 296 | // We show the login form in a table view, similar to Safari's authentication dialog 297 | [bar sizeToFit]; 298 | CGRect f = [[self view] bounds]; 299 | f.origin.y = [bar frame].size.height; 300 | f.size.height -= f.origin.y; 301 | 302 | [self setTableView:[[[UITableView alloc] initWithFrame:f style:UITableViewStyleGrouped] autorelease]]; 303 | [[self tableView] setDelegate:self]; 304 | [[self tableView] setDataSource:self]; 305 | [[self tableView] setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight]; 306 | [[self view] addSubview:[self tableView]]; 307 | 308 | // Force reload the table content, and focus the first field to show the keyboard 309 | [[self tableView] reloadData]; 310 | [[[[[self tableView] cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]].contentView subviews] objectAtIndex:0] becomeFirstResponder]; 311 | 312 | #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2 313 | if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { 314 | [self setModalPresentationStyle:UIModalPresentationFormSheet]; 315 | } 316 | #endif 317 | 318 | [[self presentingController] presentModalViewController:self animated:YES]; 319 | } 320 | 321 | #pragma mark button callbacks 322 | 323 | - (void)cancelAuthenticationFromDialog:(id)sender 324 | { 325 | for (ASIHTTPRequest *theRequest in [self requestsRequiringTheseCredentials]) { 326 | [theRequest cancelAuthentication]; 327 | [requestsNeedingAuthentication removeObject:theRequest]; 328 | } 329 | [self dismiss]; 330 | } 331 | 332 | - (NSArray *)requestsRequiringTheseCredentials 333 | { 334 | NSMutableArray *requestsRequiringTheseCredentials = [NSMutableArray array]; 335 | NSURL *requestURL = [[self request] url]; 336 | for (ASIHTTPRequest *otherRequest in requestsNeedingAuthentication) { 337 | NSURL *theURL = [otherRequest url]; 338 | 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]]))) { 339 | [requestsRequiringTheseCredentials addObject:otherRequest]; 340 | } 341 | } 342 | [requestsRequiringTheseCredentials addObject:[self request]]; 343 | return requestsRequiringTheseCredentials; 344 | } 345 | 346 | - (void)presentNextDialog 347 | { 348 | if ([requestsNeedingAuthentication count]) { 349 | ASIHTTPRequest *nextRequest = [requestsNeedingAuthentication objectAtIndex:0]; 350 | [requestsNeedingAuthentication removeObjectAtIndex:0]; 351 | [[self class] presentAuthenticationDialogForRequest:nextRequest]; 352 | } 353 | } 354 | 355 | 356 | - (void)loginWithCredentialsFromDialog:(id)sender 357 | { 358 | for (ASIHTTPRequest *theRequest in [self requestsRequiringTheseCredentials]) { 359 | 360 | NSString *username = [[self usernameField] text]; 361 | NSString *password = [[self passwordField] text]; 362 | 363 | if (username == nil) { username = @""; } 364 | if (password == nil) { password = @""; } 365 | 366 | if ([self type] == ASIProxyAuthenticationType) { 367 | [theRequest setProxyUsername:username]; 368 | [theRequest setProxyPassword:password]; 369 | } else { 370 | [theRequest setUsername:username]; 371 | [theRequest setPassword:password]; 372 | } 373 | 374 | // Handle NTLM domains 375 | NSString *scheme = ([self type] == ASIStandardAuthenticationType) ? [[self request] authenticationScheme] : [[self request] proxyAuthenticationScheme]; 376 | if ([scheme isEqualToString:(NSString *)kCFHTTPAuthenticationSchemeNTLM]) { 377 | NSString *domain = [[self domainField] text]; 378 | if ([self type] == ASIProxyAuthenticationType) { 379 | [theRequest setProxyDomain:domain]; 380 | } else { 381 | [theRequest setDomain:domain]; 382 | } 383 | } 384 | 385 | [theRequest retryUsingSuppliedCredentials]; 386 | [requestsNeedingAuthentication removeObject:theRequest]; 387 | } 388 | [self dismiss]; 389 | } 390 | 391 | #pragma mark table view data source 392 | 393 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)aTableView 394 | { 395 | NSString *scheme = ([self type] == ASIStandardAuthenticationType) ? [[self request] authenticationScheme] : [[self request] proxyAuthenticationScheme]; 396 | if ([scheme isEqualToString:(NSString *)kCFHTTPAuthenticationSchemeNTLM]) { 397 | return 2; 398 | } 399 | return 1; 400 | } 401 | 402 | - (CGFloat)tableView:(UITableView *)aTableView heightForFooterInSection:(NSInteger)section 403 | { 404 | if (section == [self numberOfSectionsInTableView:aTableView]-1) { 405 | return 30; 406 | } 407 | return 0; 408 | } 409 | 410 | - (CGFloat)tableView:(UITableView *)aTableView heightForHeaderInSection:(NSInteger)section 411 | { 412 | if (section == 0) { 413 | #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2 414 | if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { 415 | return 54; 416 | } 417 | #endif 418 | return 30; 419 | } 420 | return 0; 421 | } 422 | 423 | - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section 424 | { 425 | if (section == 0) { 426 | return [[self request] authenticationRealm]; 427 | } 428 | return nil; 429 | } 430 | 431 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 432 | { 433 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_3_0 434 | UITableViewCell *cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil] autorelease]; 435 | #else 436 | UITableViewCell *cell = [[[UITableViewCell alloc] initWithFrame:CGRectMake(0,0,0,0) reuseIdentifier:nil] autorelease]; 437 | #endif 438 | 439 | [cell setSelectionStyle:UITableViewCellSelectionStyleNone]; 440 | 441 | CGRect f = CGRectInset([cell bounds], 10, 10); 442 | UITextField *textField = [[[UITextField alloc] initWithFrame:f] autorelease]; 443 | [textField setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight]; 444 | [textField setAutocapitalizationType:UITextAutocapitalizationTypeNone]; 445 | [textField setAutocorrectionType:UITextAutocorrectionTypeNo]; 446 | 447 | NSUInteger s = [indexPath section]; 448 | NSUInteger r = [indexPath row]; 449 | 450 | if (s == kUsernameSection && r == kUsernameRow) { 451 | [textField setPlaceholder:@"User"]; 452 | } else if (s == kPasswordSection && r == kPasswordRow) { 453 | [textField setPlaceholder:@"Password"]; 454 | [textField setSecureTextEntry:YES]; 455 | } else if (s == kDomainSection && r == kDomainRow) { 456 | [textField setPlaceholder:@"Domain"]; 457 | } 458 | [cell.contentView addSubview:textField]; 459 | 460 | return cell; 461 | } 462 | 463 | - (NSInteger)tableView:(UITableView *)aTableView numberOfRowsInSection:(NSInteger)section 464 | { 465 | if (section == 0) { 466 | return 2; 467 | } else { 468 | return 1; 469 | } 470 | } 471 | 472 | - (NSString *)tableView:(UITableView *)aTableView titleForFooterInSection:(NSInteger)section 473 | { 474 | if (section == [self numberOfSectionsInTableView:aTableView]-1) { 475 | // If we're using Basic authentication and the connection is not using SSL, we'll show the plain text message 476 | if ([[[self request] authenticationScheme] isEqualToString:(NSString *)kCFHTTPAuthenticationSchemeBasic] && ![[[[self request] url] scheme] isEqualToString:@"https"]) { 477 | return @"Password will be sent in the clear."; 478 | // We are using Digest, NTLM, or any scheme over SSL 479 | } else { 480 | return @"Password will be sent securely."; 481 | } 482 | } 483 | return nil; 484 | } 485 | 486 | #pragma mark - 487 | 488 | @synthesize request; 489 | @synthesize type; 490 | @synthesize tableView; 491 | @synthesize didEnableRotationNotifications; 492 | @synthesize presentingController; 493 | @end 494 | -------------------------------------------------------------------------------- /LASIImageView/External/ASIHTTPRequest/ASICacheDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASICacheDelegate.h 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 01/05/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import 10 | @class ASIHTTPRequest; 11 | 12 | // Cache policies control the behaviour of a cache and how requests use the cache 13 | // When setting a cache policy, you can use a combination of these values as a bitmask 14 | // For example: [request setCachePolicy:ASIAskServerIfModifiedCachePolicy|ASIFallbackToCacheIfLoadFailsCachePolicy|ASIDoNotWriteToCacheCachePolicy]; 15 | // Note that some of the behaviours below are mutally exclusive - you cannot combine ASIAskServerIfModifiedWhenStaleCachePolicy and ASIAskServerIfModifiedCachePolicy, for example. 16 | typedef enum _ASICachePolicy { 17 | 18 | // The default cache policy. When you set a request to use this, it will use the cache's defaultCachePolicy 19 | // ASIDownloadCache's default cache policy is 'ASIAskServerIfModifiedWhenStaleCachePolicy' 20 | ASIUseDefaultCachePolicy = 0, 21 | 22 | // Tell the request not to read from the cache 23 | ASIDoNotReadFromCacheCachePolicy = 1, 24 | 25 | // The the request not to write to the cache 26 | ASIDoNotWriteToCacheCachePolicy = 2, 27 | 28 | // Ask the server if there is an updated version of this resource (using a conditional GET) ONLY when the cached data is stale 29 | ASIAskServerIfModifiedWhenStaleCachePolicy = 4, 30 | 31 | // Always ask the server if there is an updated version of this resource (using a conditional GET) 32 | ASIAskServerIfModifiedCachePolicy = 8, 33 | 34 | // 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 35 | ASIOnlyLoadIfNotCachedCachePolicy = 16, 36 | 37 | // 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) 38 | ASIDontLoadCachePolicy = 32, 39 | 40 | // 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. 41 | ASIFallbackToCacheIfLoadFailsCachePolicy = 64 42 | } ASICachePolicy; 43 | 44 | // Cache storage policies control whether cached data persists between application launches (ASICachePermanentlyCacheStoragePolicy) or not (ASICacheForSessionDurationCacheStoragePolicy) 45 | // Calling [ASIHTTPRequest clearSession] will remove any data stored using ASICacheForSessionDurationCacheStoragePolicy 46 | typedef enum _ASICacheStoragePolicy { 47 | ASICacheForSessionDurationCacheStoragePolicy = 0, 48 | ASICachePermanentlyCacheStoragePolicy = 1 49 | } ASICacheStoragePolicy; 50 | 51 | 52 | @protocol ASICacheDelegate 53 | 54 | @required 55 | 56 | // Should return the cache policy that will be used when requests have their cache policy set to ASIUseDefaultCachePolicy 57 | - (ASICachePolicy)defaultCachePolicy; 58 | 59 | // Returns the date a cached response should expire on. Pass a non-zero max age to specify a custom date. 60 | - (NSDate *)expiryDateForRequest:(ASIHTTPRequest *)request maxAge:(NSTimeInterval)maxAge; 61 | 62 | // Updates cached response headers with a new expiry date. Pass a non-zero max age to specify a custom date. 63 | - (void)updateExpiryForRequest:(ASIHTTPRequest *)request maxAge:(NSTimeInterval)maxAge; 64 | 65 | // Looks at the request's cache policy and any cached headers to determine if the cache data is still valid 66 | - (BOOL)canUseCachedDataForRequest:(ASIHTTPRequest *)request; 67 | 68 | // Removes cached data for a particular request 69 | - (void)removeCachedDataForRequest:(ASIHTTPRequest *)request; 70 | 71 | // Should return YES if the cache considers its cached response current for the request 72 | // Should return NO is the data is not cached, or (for example) if the cached headers state the request should have expired 73 | - (BOOL)isCachedDataCurrentForRequest:(ASIHTTPRequest *)request; 74 | 75 | // Should store the response for the passed request in the cache 76 | // When a non-zero maxAge is passed, it should be used as the expiry time for the cached response 77 | - (void)storeResponseForRequest:(ASIHTTPRequest *)request maxAge:(NSTimeInterval)maxAge; 78 | 79 | // Removes cached data for a particular url 80 | - (void)removeCachedDataForURL:(NSURL *)url; 81 | 82 | // Should return an NSDictionary of cached headers for the passed URL, if it is stored in the cache 83 | - (NSDictionary *)cachedResponseHeadersForURL:(NSURL *)url; 84 | 85 | // Should return the cached body of a response for the passed URL, if it is stored in the cache 86 | - (NSData *)cachedResponseDataForURL:(NSURL *)url; 87 | 88 | // Returns a path to the cached response data, if it exists 89 | - (NSString *)pathToCachedResponseDataForURL:(NSURL *)url; 90 | 91 | // Returns a path to the cached response headers, if they url 92 | - (NSString *)pathToCachedResponseHeadersForURL:(NSURL *)url; 93 | 94 | // Returns the location to use to store cached response headers for a particular request 95 | - (NSString *)pathToStoreCachedResponseHeadersForRequest:(ASIHTTPRequest *)request; 96 | 97 | // Returns the location to use to store a cached response body for a particular request 98 | - (NSString *)pathToStoreCachedResponseDataForRequest:(ASIHTTPRequest *)request; 99 | 100 | // Clear cached data stored for the passed storage policy 101 | - (void)clearCachedResponsesForStoragePolicy:(ASICacheStoragePolicy)cachePolicy; 102 | 103 | @end 104 | -------------------------------------------------------------------------------- /LASIImageView/External/ASIHTTPRequest/ASIDataCompressor.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASIDataCompressor.h 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 17/08/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | // This is a helper class used by ASIHTTPRequest to handle deflating (compressing) data in memory and on disk 10 | // You may also find it helpful if you need to deflate data and files yourself - see the class methods below 11 | // Most of the zlib stuff is based on the sample code by Mark Adler available at http://zlib.net 12 | 13 | #import 14 | #import 15 | 16 | @interface ASIDataCompressor : NSObject { 17 | BOOL streamReady; 18 | z_stream zStream; 19 | } 20 | 21 | // Convenience constructor will call setupStream for you 22 | + (id)compressor; 23 | 24 | // Compress the passed chunk of data 25 | // Passing YES for shouldFinish will finalize the deflated data - you must pass YES when you are on the last chunk of data 26 | - (NSData *)compressBytes:(Bytef *)bytes length:(NSUInteger)length error:(NSError **)err shouldFinish:(BOOL)shouldFinish; 27 | 28 | // Convenience method - pass it some data, and you'll get deflated data back 29 | + (NSData *)compressData:(NSData*)uncompressedData error:(NSError **)err; 30 | 31 | // Convenience method - pass it a file containing the data to compress in sourcePath, and it will write deflated data to destinationPath 32 | + (BOOL)compressDataFromFile:(NSString *)sourcePath toFile:(NSString *)destinationPath error:(NSError **)err; 33 | 34 | // Sets up zlib to handle the inflating. You only need to call this yourself if you aren't using the convenience constructor 'compressor' 35 | - (NSError *)setupStream; 36 | 37 | // Tells zlib to clean up. You need to call this if you need to cancel deflating part way through 38 | // If deflating finishes or fails, this method will be called automatically 39 | - (NSError *)closeStream; 40 | 41 | @property (assign, readonly) BOOL streamReady; 42 | @end 43 | -------------------------------------------------------------------------------- /LASIImageView/External/ASIHTTPRequest/ASIDataCompressor.m: -------------------------------------------------------------------------------- 1 | // 2 | // ASIDataCompressor.m 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 17/08/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import "ASIDataCompressor.h" 10 | #import "ASIHTTPRequest.h" 11 | 12 | #define DATA_CHUNK_SIZE 262144 // Deal with gzipped data in 256KB chunks 13 | #define COMPRESSION_AMOUNT Z_DEFAULT_COMPRESSION 14 | 15 | @interface ASIDataCompressor () 16 | + (NSError *)deflateErrorWithCode:(int)code; 17 | @end 18 | 19 | @implementation ASIDataCompressor 20 | 21 | + (id)compressor 22 | { 23 | ASIDataCompressor *compressor = [[[self alloc] init] autorelease]; 24 | [compressor setupStream]; 25 | return compressor; 26 | } 27 | 28 | - (void)dealloc 29 | { 30 | if (streamReady) { 31 | [self closeStream]; 32 | } 33 | [super dealloc]; 34 | } 35 | 36 | - (NSError *)setupStream 37 | { 38 | if (streamReady) { 39 | return nil; 40 | } 41 | // Setup the inflate stream 42 | zStream.zalloc = Z_NULL; 43 | zStream.zfree = Z_NULL; 44 | zStream.opaque = Z_NULL; 45 | zStream.avail_in = 0; 46 | zStream.next_in = 0; 47 | int status = deflateInit2(&zStream, COMPRESSION_AMOUNT, Z_DEFLATED, (15+16), 8, Z_DEFAULT_STRATEGY); 48 | if (status != Z_OK) { 49 | return [[self class] deflateErrorWithCode:status]; 50 | } 51 | streamReady = YES; 52 | return nil; 53 | } 54 | 55 | - (NSError *)closeStream 56 | { 57 | if (!streamReady) { 58 | return nil; 59 | } 60 | // Close the deflate stream 61 | streamReady = NO; 62 | int status = deflateEnd(&zStream); 63 | if (status != Z_OK) { 64 | return [[self class] deflateErrorWithCode:status]; 65 | } 66 | return nil; 67 | } 68 | 69 | - (NSData *)compressBytes:(Bytef *)bytes length:(NSUInteger)length error:(NSError **)err shouldFinish:(BOOL)shouldFinish 70 | { 71 | if (length == 0) return nil; 72 | 73 | NSUInteger halfLength = length/2; 74 | 75 | // 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 76 | NSMutableData *outputData = [NSMutableData dataWithLength:length/2]; 77 | 78 | int status; 79 | 80 | zStream.next_in = bytes; 81 | zStream.avail_in = (unsigned int)length; 82 | zStream.avail_out = 0; 83 | 84 | NSInteger bytesProcessedAlready = zStream.total_out; 85 | while (zStream.avail_out == 0) { 86 | 87 | if (zStream.total_out-bytesProcessedAlready >= [outputData length]) { 88 | [outputData increaseLengthBy:halfLength]; 89 | } 90 | 91 | zStream.next_out = (Bytef*)[outputData mutableBytes] + zStream.total_out-bytesProcessedAlready; 92 | zStream.avail_out = (unsigned int)([outputData length] - (zStream.total_out-bytesProcessedAlready)); 93 | status = deflate(&zStream, shouldFinish ? Z_FINISH : Z_NO_FLUSH); 94 | 95 | if (status == Z_STREAM_END) { 96 | break; 97 | } else if (status != Z_OK) { 98 | if (err) { 99 | *err = [[self class] deflateErrorWithCode:status]; 100 | } 101 | return NO; 102 | } 103 | } 104 | 105 | // Set real length 106 | [outputData setLength: zStream.total_out-bytesProcessedAlready]; 107 | return outputData; 108 | } 109 | 110 | 111 | + (NSData *)compressData:(NSData*)uncompressedData error:(NSError **)err 112 | { 113 | NSError *theError = nil; 114 | NSData *outputData = [[ASIDataCompressor compressor] compressBytes:(Bytef *)[uncompressedData bytes] length:[uncompressedData length] error:&theError shouldFinish:YES]; 115 | if (theError) { 116 | if (err) { 117 | *err = theError; 118 | } 119 | return nil; 120 | } 121 | return outputData; 122 | } 123 | 124 | 125 | 126 | + (BOOL)compressDataFromFile:(NSString *)sourcePath toFile:(NSString *)destinationPath error:(NSError **)err 127 | { 128 | NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease]; 129 | 130 | // Create an empty file at the destination path 131 | if (![fileManager createFileAtPath:destinationPath contents:[NSData data] attributes:nil]) { 132 | if (err) { 133 | *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]]; 134 | } 135 | return NO; 136 | } 137 | 138 | // Ensure the source file exists 139 | if (![fileManager fileExistsAtPath:sourcePath]) { 140 | if (err) { 141 | *err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Compression of %@ failed the file does not exist",sourcePath],NSLocalizedDescriptionKey,nil]]; 142 | } 143 | return NO; 144 | } 145 | 146 | UInt8 inputData[DATA_CHUNK_SIZE]; 147 | NSData *outputData; 148 | NSInteger readLength; 149 | NSError *theError = nil; 150 | 151 | ASIDataCompressor *compressor = [ASIDataCompressor compressor]; 152 | 153 | NSInputStream *inputStream = [NSInputStream inputStreamWithFileAtPath:sourcePath]; 154 | [inputStream open]; 155 | NSOutputStream *outputStream = [NSOutputStream outputStreamToFileAtPath:destinationPath append:NO]; 156 | [outputStream open]; 157 | 158 | while ([compressor streamReady]) { 159 | 160 | // Read some data from the file 161 | readLength = [inputStream read:inputData maxLength:DATA_CHUNK_SIZE]; 162 | 163 | // Make sure nothing went wrong 164 | if ([inputStream streamStatus] == NSStreamStatusError) { 165 | if (err) { 166 | *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]]; 167 | } 168 | [compressor closeStream]; 169 | return NO; 170 | } 171 | // Have we reached the end of the input data? 172 | if (!readLength) { 173 | break; 174 | } 175 | 176 | // Attempt to deflate the chunk of data 177 | outputData = [compressor compressBytes:inputData length:readLength error:&theError shouldFinish:readLength < DATA_CHUNK_SIZE ]; 178 | if (theError) { 179 | if (err) { 180 | *err = theError; 181 | } 182 | [compressor closeStream]; 183 | return NO; 184 | } 185 | 186 | // Write the deflated data out to the destination file 187 | [outputStream write:(const uint8_t *)[outputData bytes] maxLength:[outputData length]]; 188 | 189 | // Make sure nothing went wrong 190 | if ([inputStream streamStatus] == NSStreamStatusError) { 191 | if (err) { 192 | *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]]; 193 | } 194 | [compressor closeStream]; 195 | return NO; 196 | } 197 | 198 | } 199 | [inputStream close]; 200 | [outputStream close]; 201 | 202 | NSError *error = [compressor closeStream]; 203 | if (error) { 204 | if (err) { 205 | *err = error; 206 | } 207 | return NO; 208 | } 209 | 210 | return YES; 211 | } 212 | 213 | + (NSError *)deflateErrorWithCode:(int)code 214 | { 215 | return [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Compression of data failed with code %d",code],NSLocalizedDescriptionKey,nil]]; 216 | } 217 | 218 | @synthesize streamReady; 219 | @end 220 | -------------------------------------------------------------------------------- /LASIImageView/External/ASIHTTPRequest/ASIDataDecompressor.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASIDataDecompressor.h 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 17/08/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | // This is a helper class used by ASIHTTPRequest to handle inflating (decompressing) data in memory and on disk 10 | // You may also find it helpful if you need to inflate data and files yourself - see the class methods below 11 | // Most of the zlib stuff is based on the sample code by Mark Adler available at http://zlib.net 12 | 13 | #import 14 | #import 15 | 16 | @interface ASIDataDecompressor : NSObject { 17 | BOOL streamReady; 18 | z_stream zStream; 19 | } 20 | 21 | // Convenience constructor will call setupStream for you 22 | + (id)decompressor; 23 | 24 | // Uncompress the passed chunk of data 25 | - (NSData *)uncompressBytes:(Bytef *)bytes length:(NSUInteger)length error:(NSError **)err; 26 | 27 | // Convenience method - pass it some deflated data, and you'll get inflated data back 28 | + (NSData *)uncompressData:(NSData*)compressedData error:(NSError **)err; 29 | 30 | // Convenience method - pass it a file containing deflated data in sourcePath, and it will write inflated data to destinationPath 31 | + (BOOL)uncompressDataFromFile:(NSString *)sourcePath toFile:(NSString *)destinationPath error:(NSError **)err; 32 | 33 | // Sets up zlib to handle the inflating. You only need to call this yourself if you aren't using the convenience constructor 'decompressor' 34 | - (NSError *)setupStream; 35 | 36 | // Tells zlib to clean up. You need to call this if you need to cancel inflating part way through 37 | // If inflating finishes or fails, this method will be called automatically 38 | - (NSError *)closeStream; 39 | 40 | @property (assign, readonly) BOOL streamReady; 41 | @end 42 | -------------------------------------------------------------------------------- /LASIImageView/External/ASIHTTPRequest/ASIDataDecompressor.m: -------------------------------------------------------------------------------- 1 | // 2 | // ASIDataDecompressor.m 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 17/08/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import "ASIDataDecompressor.h" 10 | #import "ASIHTTPRequest.h" 11 | 12 | #define DATA_CHUNK_SIZE 262144 // Deal with gzipped data in 256KB chunks 13 | 14 | @interface ASIDataDecompressor () 15 | + (NSError *)inflateErrorWithCode:(int)code; 16 | @end; 17 | 18 | @implementation ASIDataDecompressor 19 | 20 | + (id)decompressor 21 | { 22 | ASIDataDecompressor *decompressor = [[[self alloc] init] autorelease]; 23 | [decompressor setupStream]; 24 | return decompressor; 25 | } 26 | 27 | - (void)dealloc 28 | { 29 | if (streamReady) { 30 | [self closeStream]; 31 | } 32 | [super dealloc]; 33 | } 34 | 35 | - (NSError *)setupStream 36 | { 37 | if (streamReady) { 38 | return nil; 39 | } 40 | // Setup the inflate stream 41 | zStream.zalloc = Z_NULL; 42 | zStream.zfree = Z_NULL; 43 | zStream.opaque = Z_NULL; 44 | zStream.avail_in = 0; 45 | zStream.next_in = 0; 46 | int status = inflateInit2(&zStream, (15+32)); 47 | if (status != Z_OK) { 48 | return [[self class] inflateErrorWithCode:status]; 49 | } 50 | streamReady = YES; 51 | return nil; 52 | } 53 | 54 | - (NSError *)closeStream 55 | { 56 | if (!streamReady) { 57 | return nil; 58 | } 59 | // Close the inflate stream 60 | streamReady = NO; 61 | int status = inflateEnd(&zStream); 62 | if (status != Z_OK) { 63 | return [[self class] inflateErrorWithCode:status]; 64 | } 65 | return nil; 66 | } 67 | 68 | - (NSData *)uncompressBytes:(Bytef *)bytes length:(NSUInteger)length error:(NSError **)err 69 | { 70 | if (length == 0) return nil; 71 | 72 | NSUInteger halfLength = length/2; 73 | NSMutableData *outputData = [NSMutableData dataWithLength:length+halfLength]; 74 | 75 | int status; 76 | 77 | zStream.next_in = bytes; 78 | zStream.avail_in = (unsigned int)length; 79 | zStream.avail_out = 0; 80 | 81 | NSInteger bytesProcessedAlready = zStream.total_out; 82 | while (zStream.avail_in != 0) { 83 | 84 | if (zStream.total_out-bytesProcessedAlready >= [outputData length]) { 85 | [outputData increaseLengthBy:halfLength]; 86 | } 87 | 88 | zStream.next_out = (Bytef*)[outputData mutableBytes] + zStream.total_out-bytesProcessedAlready; 89 | zStream.avail_out = (unsigned int)([outputData length] - (zStream.total_out-bytesProcessedAlready)); 90 | 91 | status = inflate(&zStream, Z_NO_FLUSH); 92 | 93 | if (status == Z_STREAM_END) { 94 | break; 95 | } else if (status != Z_OK) { 96 | if (err) { 97 | *err = [[self class] inflateErrorWithCode:status]; 98 | } 99 | return nil; 100 | } 101 | } 102 | 103 | // Set real length 104 | [outputData setLength: zStream.total_out-bytesProcessedAlready]; 105 | return outputData; 106 | } 107 | 108 | 109 | + (NSData *)uncompressData:(NSData*)compressedData error:(NSError **)err 110 | { 111 | NSError *theError = nil; 112 | NSData *outputData = [[ASIDataDecompressor decompressor] uncompressBytes:(Bytef *)[compressedData bytes] length:[compressedData length] error:&theError]; 113 | if (theError) { 114 | if (err) { 115 | *err = theError; 116 | } 117 | return nil; 118 | } 119 | return outputData; 120 | } 121 | 122 | + (BOOL)uncompressDataFromFile:(NSString *)sourcePath toFile:(NSString *)destinationPath error:(NSError **)err 123 | { 124 | NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease]; 125 | 126 | // Create an empty file at the destination path 127 | if (![fileManager createFileAtPath:destinationPath contents:[NSData data] attributes:nil]) { 128 | if (err) { 129 | *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]]; 130 | } 131 | return NO; 132 | } 133 | 134 | // Ensure the source file exists 135 | if (![fileManager fileExistsAtPath:sourcePath]) { 136 | if (err) { 137 | *err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Decompression of %@ failed the file does not exist",sourcePath],NSLocalizedDescriptionKey,nil]]; 138 | } 139 | return NO; 140 | } 141 | 142 | UInt8 inputData[DATA_CHUNK_SIZE]; 143 | NSData *outputData; 144 | NSInteger readLength; 145 | NSError *theError = nil; 146 | 147 | 148 | ASIDataDecompressor *decompressor = [ASIDataDecompressor decompressor]; 149 | 150 | NSInputStream *inputStream = [NSInputStream inputStreamWithFileAtPath:sourcePath]; 151 | [inputStream open]; 152 | NSOutputStream *outputStream = [NSOutputStream outputStreamToFileAtPath:destinationPath append:NO]; 153 | [outputStream open]; 154 | 155 | while ([decompressor streamReady]) { 156 | 157 | // Read some data from the file 158 | readLength = [inputStream read:inputData maxLength:DATA_CHUNK_SIZE]; 159 | 160 | // Make sure nothing went wrong 161 | if ([inputStream streamStatus] == NSStreamStatusError) { 162 | if (err) { 163 | *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]]; 164 | } 165 | [decompressor closeStream]; 166 | return NO; 167 | } 168 | // Have we reached the end of the input data? 169 | if (!readLength) { 170 | break; 171 | } 172 | 173 | // Attempt to inflate the chunk of data 174 | outputData = [decompressor uncompressBytes:inputData length:readLength error:&theError]; 175 | if (theError) { 176 | if (err) { 177 | *err = theError; 178 | } 179 | [decompressor closeStream]; 180 | return NO; 181 | } 182 | 183 | // Write the inflated data out to the destination file 184 | [outputStream write:(Bytef*)[outputData bytes] maxLength:[outputData length]]; 185 | 186 | // Make sure nothing went wrong 187 | if ([inputStream streamStatus] == NSStreamStatusError) { 188 | if (err) { 189 | *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]]; 190 | } 191 | [decompressor closeStream]; 192 | return NO; 193 | } 194 | 195 | } 196 | 197 | [inputStream close]; 198 | [outputStream close]; 199 | 200 | NSError *error = [decompressor closeStream]; 201 | if (error) { 202 | if (err) { 203 | *err = error; 204 | } 205 | return NO; 206 | } 207 | 208 | return YES; 209 | } 210 | 211 | 212 | + (NSError *)inflateErrorWithCode:(int)code 213 | { 214 | return [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Decompression of data failed with code %d",code],NSLocalizedDescriptionKey,nil]]; 215 | } 216 | 217 | @synthesize streamReady; 218 | @end 219 | -------------------------------------------------------------------------------- /LASIImageView/External/ASIHTTPRequest/ASIDownloadCache.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASIDownloadCache.h 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 01/05/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ASICacheDelegate.h" 11 | 12 | @interface ASIDownloadCache : NSObject { 13 | 14 | // The default cache policy for this cache 15 | // Requests that store data in the cache will use this cache policy if their cache policy is set to ASIUseDefaultCachePolicy 16 | // Defaults to ASIAskServerIfModifiedWhenStaleCachePolicy 17 | ASICachePolicy defaultCachePolicy; 18 | 19 | // The directory in which cached data will be stored 20 | // Defaults to a directory called 'ASIHTTPRequestCache' in the temporary directory 21 | NSString *storagePath; 22 | 23 | // Mediates access to the cache 24 | NSRecursiveLock *accessLock; 25 | 26 | // When YES, the cache will look for cache-control / pragma: no-cache headers, and won't reuse store responses if it finds them 27 | BOOL shouldRespectCacheControlHeaders; 28 | } 29 | 30 | // Returns a static instance of an ASIDownloadCache 31 | // In most circumstances, it will make sense to use this as a global cache, rather than creating your own cache 32 | // To make ASIHTTPRequests use it automatically, use [ASIHTTPRequest setDefaultCache:[ASIDownloadCache sharedCache]]; 33 | + (id)sharedCache; 34 | 35 | // A helper function that determines if the server has requested data should not be cached by looking at the request's response headers 36 | + (BOOL)serverAllowsResponseCachingForRequest:(ASIHTTPRequest *)request; 37 | 38 | // A list of file extensions that we know won't be readable by a webview when accessed locally 39 | // If we're asking for a path to cache a particular url and it has one of these extensions, we change it to '.html' 40 | + (NSArray *)fileExtensionsToHandleAsHTML; 41 | 42 | @property (assign, nonatomic) ASICachePolicy defaultCachePolicy; 43 | @property (retain, nonatomic) NSString *storagePath; 44 | @property (retain) NSRecursiveLock *accessLock; 45 | @property (assign) BOOL shouldRespectCacheControlHeaders; 46 | @end 47 | -------------------------------------------------------------------------------- /LASIImageView/External/ASIHTTPRequest/ASIDownloadCache.m: -------------------------------------------------------------------------------- 1 | // 2 | // ASIDownloadCache.m 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 01/05/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import "ASIDownloadCache.h" 10 | #import "ASIHTTPRequest.h" 11 | #import 12 | 13 | static ASIDownloadCache *sharedCache = nil; 14 | 15 | static NSString *sessionCacheFolder = @"SessionStore"; 16 | static NSString *permanentCacheFolder = @"PermanentStore"; 17 | static NSArray *fileExtensionsToHandleAsHTML = nil; 18 | 19 | @interface ASIDownloadCache () 20 | + (NSString *)keyForURL:(NSURL *)url; 21 | - (NSString *)pathToFile:(NSString *)file; 22 | @end 23 | 24 | @implementation ASIDownloadCache 25 | 26 | + (void)initialize 27 | { 28 | if (self == [ASIDownloadCache class]) { 29 | // 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 30 | // I imagine many web developers probably use url rewriting anyway 31 | fileExtensionsToHandleAsHTML = [[NSArray alloc] initWithObjects:@"asp",@"aspx",@"jsp",@"php",@"rb",@"py",@"pl",@"cgi", nil]; 32 | } 33 | } 34 | 35 | - (id)init 36 | { 37 | self = [super init]; 38 | [self setShouldRespectCacheControlHeaders:YES]; 39 | [self setDefaultCachePolicy:ASIUseDefaultCachePolicy]; 40 | [self setAccessLock:[[[NSRecursiveLock alloc] init] autorelease]]; 41 | return self; 42 | } 43 | 44 | + (id)sharedCache 45 | { 46 | if (!sharedCache) { 47 | @synchronized(self) { 48 | if (!sharedCache) { 49 | sharedCache = [[self alloc] init]; 50 | [sharedCache setStoragePath:[[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:@"ASIHTTPRequestCache"]]; 51 | } 52 | } 53 | } 54 | return sharedCache; 55 | } 56 | 57 | - (void)dealloc 58 | { 59 | [storagePath release]; 60 | [accessLock release]; 61 | [super dealloc]; 62 | } 63 | 64 | - (NSString *)storagePath 65 | { 66 | [[self accessLock] lock]; 67 | NSString *p = [[storagePath retain] autorelease]; 68 | [[self accessLock] unlock]; 69 | return p; 70 | } 71 | 72 | 73 | - (void)setStoragePath:(NSString *)path 74 | { 75 | [[self accessLock] lock]; 76 | [self clearCachedResponsesForStoragePolicy:ASICacheForSessionDurationCacheStoragePolicy]; 77 | [storagePath release]; 78 | storagePath = [path retain]; 79 | 80 | NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease]; 81 | 82 | BOOL isDirectory = NO; 83 | NSArray *directories = [NSArray arrayWithObjects:path,[path stringByAppendingPathComponent:sessionCacheFolder],[path stringByAppendingPathComponent:permanentCacheFolder],nil]; 84 | for (NSString *directory in directories) { 85 | BOOL exists = [fileManager fileExistsAtPath:directory isDirectory:&isDirectory]; 86 | if (exists && !isDirectory) { 87 | [[self accessLock] unlock]; 88 | [NSException raise:@"FileExistsAtCachePath" format:@"Cannot create a directory for the cache at '%@', because a file already exists",directory]; 89 | } else if (!exists) { 90 | [fileManager createDirectoryAtPath:directory withIntermediateDirectories:NO attributes:nil error:nil]; 91 | if (![fileManager fileExistsAtPath:directory]) { 92 | [[self accessLock] unlock]; 93 | [NSException raise:@"FailedToCreateCacheDirectory" format:@"Failed to create a directory for the cache at '%@'",directory]; 94 | } 95 | } 96 | } 97 | [self clearCachedResponsesForStoragePolicy:ASICacheForSessionDurationCacheStoragePolicy]; 98 | [[self accessLock] unlock]; 99 | } 100 | 101 | - (void)updateExpiryForRequest:(ASIHTTPRequest *)request maxAge:(NSTimeInterval)maxAge 102 | { 103 | NSString *headerPath = [self pathToStoreCachedResponseHeadersForRequest:request]; 104 | NSMutableDictionary *cachedHeaders = [NSMutableDictionary dictionaryWithContentsOfFile:headerPath]; 105 | if (!cachedHeaders) { 106 | return; 107 | } 108 | NSDate *expires = [self expiryDateForRequest:request maxAge:maxAge]; 109 | if (!expires) { 110 | return; 111 | } 112 | [cachedHeaders setObject:[NSNumber numberWithDouble:[expires timeIntervalSince1970]] forKey:@"X-ASIHTTPRequest-Expires"]; 113 | [cachedHeaders writeToFile:headerPath atomically:NO]; 114 | } 115 | 116 | - (NSDate *)expiryDateForRequest:(ASIHTTPRequest *)request maxAge:(NSTimeInterval)maxAge 117 | { 118 | return [ASIHTTPRequest expiryDateForRequest:request maxAge:maxAge]; 119 | } 120 | 121 | - (void)storeResponseForRequest:(ASIHTTPRequest *)request maxAge:(NSTimeInterval)maxAge 122 | { 123 | [[self accessLock] lock]; 124 | 125 | if ([request error] || ![request responseHeaders] || ([request cachePolicy] & ASIDoNotWriteToCacheCachePolicy)) { 126 | [[self accessLock] unlock]; 127 | return; 128 | } 129 | 130 | // We only cache 200/OK or redirect reponses (redirect responses are cached so the cache works better with no internet connection) 131 | int responseCode = [request responseStatusCode]; 132 | if (responseCode != 200 && responseCode != 301 && responseCode != 302 && responseCode != 303 && responseCode != 307) { 133 | [[self accessLock] unlock]; 134 | return; 135 | } 136 | 137 | if ([self shouldRespectCacheControlHeaders] && ![[self class] serverAllowsResponseCachingForRequest:request]) { 138 | [[self accessLock] unlock]; 139 | return; 140 | } 141 | 142 | NSString *headerPath = [self pathToStoreCachedResponseHeadersForRequest:request]; 143 | NSString *dataPath = [self pathToStoreCachedResponseDataForRequest:request]; 144 | 145 | NSMutableDictionary *responseHeaders = [NSMutableDictionary dictionaryWithDictionary:[request responseHeaders]]; 146 | if ([request isResponseCompressed]) { 147 | [responseHeaders removeObjectForKey:@"Content-Encoding"]; 148 | } 149 | 150 | // Create a special 'X-ASIHTTPRequest-Expires' header 151 | // This is what we use for deciding if cached data is current, rather than parsing the expires / max-age headers individually each time 152 | // We store this as a timestamp to make reading it easier as NSDateFormatter is quite expensive 153 | 154 | NSDate *expires = [self expiryDateForRequest:request maxAge:maxAge]; 155 | if (expires) { 156 | [responseHeaders setObject:[NSNumber numberWithDouble:[expires timeIntervalSince1970]] forKey:@"X-ASIHTTPRequest-Expires"]; 157 | } 158 | 159 | // Store the response code in a custom header so we can reuse it later 160 | 161 | // We'll change 304/Not Modified to 200/OK because this is likely to be us updating the cached headers with a conditional GET 162 | int statusCode = [request responseStatusCode]; 163 | if (statusCode == 304) { 164 | statusCode = 200; 165 | } 166 | [responseHeaders setObject:[NSNumber numberWithInt:statusCode] forKey:@"X-ASIHTTPRequest-Response-Status-Code"]; 167 | 168 | [responseHeaders writeToFile:headerPath atomically:NO]; 169 | 170 | if ([request responseData]) { 171 | [[request responseData] writeToFile:dataPath atomically:NO]; 172 | } else if ([request downloadDestinationPath] && ![[request downloadDestinationPath] isEqualToString:dataPath]) { 173 | NSError *error = nil; 174 | NSFileManager* manager = [[NSFileManager alloc] init]; 175 | if ([manager fileExistsAtPath:dataPath]) { 176 | [manager removeItemAtPath:dataPath error:&error]; 177 | } 178 | [manager copyItemAtPath:[request downloadDestinationPath] toPath:dataPath error:&error]; 179 | [manager release]; 180 | } 181 | [[self accessLock] unlock]; 182 | } 183 | 184 | - (NSDictionary *)cachedResponseHeadersForURL:(NSURL *)url 185 | { 186 | NSString *path = [self pathToCachedResponseHeadersForURL:url]; 187 | if (path) { 188 | return [NSDictionary dictionaryWithContentsOfFile:path]; 189 | } 190 | return nil; 191 | } 192 | 193 | - (NSData *)cachedResponseDataForURL:(NSURL *)url 194 | { 195 | NSString *path = [self pathToCachedResponseDataForURL:url]; 196 | if (path) { 197 | return [NSData dataWithContentsOfFile:path]; 198 | } 199 | return nil; 200 | } 201 | 202 | - (NSString *)pathToCachedResponseDataForURL:(NSURL *)url 203 | { 204 | // 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 205 | NSString *extension = [[url path] pathExtension]; 206 | 207 | // If the url doesn't have an extension, we'll add one so a webview can read it when locally cached 208 | // 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 209 | if (![extension length] || [[[self class] fileExtensionsToHandleAsHTML] containsObject:[extension lowercaseString]]) { 210 | extension = @"html"; 211 | } 212 | return [self pathToFile:[[[self class] keyForURL:url] stringByAppendingPathExtension:extension]]; 213 | } 214 | 215 | + (NSArray *)fileExtensionsToHandleAsHTML 216 | { 217 | return fileExtensionsToHandleAsHTML; 218 | } 219 | 220 | 221 | - (NSString *)pathToCachedResponseHeadersForURL:(NSURL *)url 222 | { 223 | return [self pathToFile:[[[self class] keyForURL:url] stringByAppendingPathExtension:@"cachedheaders"]]; 224 | } 225 | 226 | - (NSString *)pathToFile:(NSString *)file 227 | { 228 | [[self accessLock] lock]; 229 | if (![self storagePath]) { 230 | [[self accessLock] unlock]; 231 | return nil; 232 | } 233 | 234 | NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease]; 235 | 236 | // Look in the session store 237 | NSString *dataPath = [[[self storagePath] stringByAppendingPathComponent:sessionCacheFolder] stringByAppendingPathComponent:file]; 238 | if ([fileManager fileExistsAtPath:dataPath]) { 239 | [[self accessLock] unlock]; 240 | return dataPath; 241 | } 242 | // Look in the permanent store 243 | dataPath = [[[self storagePath] stringByAppendingPathComponent:permanentCacheFolder] stringByAppendingPathComponent:file]; 244 | if ([fileManager fileExistsAtPath:dataPath]) { 245 | [[self accessLock] unlock]; 246 | return dataPath; 247 | } 248 | [[self accessLock] unlock]; 249 | return nil; 250 | } 251 | 252 | 253 | - (NSString *)pathToStoreCachedResponseDataForRequest:(ASIHTTPRequest *)request 254 | { 255 | [[self accessLock] lock]; 256 | if (![self storagePath]) { 257 | [[self accessLock] unlock]; 258 | return nil; 259 | } 260 | 261 | NSString *path = [[self storagePath] stringByAppendingPathComponent:([request cacheStoragePolicy] == ASICacheForSessionDurationCacheStoragePolicy ? sessionCacheFolder : permanentCacheFolder)]; 262 | 263 | // 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 264 | NSString *extension = [[[request url] path] pathExtension]; 265 | 266 | // If the url doesn't have an extension, we'll add one so a webview can read it when locally cached 267 | // 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 268 | if (![extension length] || [[[self class] fileExtensionsToHandleAsHTML] containsObject:[extension lowercaseString]]) { 269 | extension = @"html"; 270 | } 271 | path = [path stringByAppendingPathComponent:[[[self class] keyForURL:[request url]] stringByAppendingPathExtension:extension]]; 272 | [[self accessLock] unlock]; 273 | return path; 274 | } 275 | 276 | - (NSString *)pathToStoreCachedResponseHeadersForRequest:(ASIHTTPRequest *)request 277 | { 278 | [[self accessLock] lock]; 279 | if (![self storagePath]) { 280 | [[self accessLock] unlock]; 281 | return nil; 282 | } 283 | NSString *path = [[self storagePath] stringByAppendingPathComponent:([request cacheStoragePolicy] == ASICacheForSessionDurationCacheStoragePolicy ? sessionCacheFolder : permanentCacheFolder)]; 284 | path = [path stringByAppendingPathComponent:[[[self class] keyForURL:[request url]] stringByAppendingPathExtension:@"cachedheaders"]]; 285 | [[self accessLock] unlock]; 286 | return path; 287 | } 288 | 289 | - (void)removeCachedDataForURL:(NSURL *)url 290 | { 291 | [[self accessLock] lock]; 292 | if (![self storagePath]) { 293 | [[self accessLock] unlock]; 294 | return; 295 | } 296 | NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease]; 297 | 298 | NSString *path = [self pathToCachedResponseHeadersForURL:url]; 299 | if (path) { 300 | [fileManager removeItemAtPath:path error:NULL]; 301 | } 302 | 303 | path = [self pathToCachedResponseDataForURL:url]; 304 | if (path) { 305 | [fileManager removeItemAtPath:path error:NULL]; 306 | } 307 | [[self accessLock] unlock]; 308 | } 309 | 310 | - (void)removeCachedDataForRequest:(ASIHTTPRequest *)request 311 | { 312 | [self removeCachedDataForURL:[request url]]; 313 | } 314 | 315 | - (BOOL)isCachedDataCurrentForRequest:(ASIHTTPRequest *)request 316 | { 317 | [[self accessLock] lock]; 318 | if (![self storagePath]) { 319 | [[self accessLock] unlock]; 320 | return NO; 321 | } 322 | NSDictionary *cachedHeaders = [self cachedResponseHeadersForURL:[request url]]; 323 | if (!cachedHeaders) { 324 | [[self accessLock] unlock]; 325 | return NO; 326 | } 327 | NSString *dataPath = [self pathToCachedResponseDataForURL:[request url]]; 328 | if (!dataPath) { 329 | [[self accessLock] unlock]; 330 | return NO; 331 | } 332 | 333 | // New content is not different 334 | if ([request responseStatusCode] == 304) { 335 | [[self accessLock] unlock]; 336 | return YES; 337 | } 338 | 339 | // If we already have response headers for this request, check to see if the new content is different 340 | // We check [request complete] so that we don't end up comparing response headers from a redirection with these 341 | if ([request responseHeaders] && [request complete]) { 342 | 343 | // If the Etag or Last-Modified date are different from the one we have, we'll have to fetch this resource again 344 | NSArray *headersToCompare = [NSArray arrayWithObjects:@"Etag",@"Last-Modified",nil]; 345 | for (NSString *header in headersToCompare) { 346 | if (![[[request responseHeaders] objectForKey:header] isEqualToString:[cachedHeaders objectForKey:header]]) { 347 | [[self accessLock] unlock]; 348 | return NO; 349 | } 350 | } 351 | } 352 | 353 | if ([self shouldRespectCacheControlHeaders]) { 354 | 355 | // Look for X-ASIHTTPRequest-Expires header to see if the content is out of date 356 | NSNumber *expires = [cachedHeaders objectForKey:@"X-ASIHTTPRequest-Expires"]; 357 | if (expires) { 358 | if ([[NSDate dateWithTimeIntervalSince1970:[expires doubleValue]] timeIntervalSinceNow] >= 0) { 359 | [[self accessLock] unlock]; 360 | return YES; 361 | } 362 | } 363 | 364 | // No explicit expiration time sent by the server 365 | [[self accessLock] unlock]; 366 | return NO; 367 | } 368 | 369 | 370 | [[self accessLock] unlock]; 371 | return YES; 372 | } 373 | 374 | - (ASICachePolicy)defaultCachePolicy 375 | { 376 | [[self accessLock] lock]; 377 | ASICachePolicy cp = defaultCachePolicy; 378 | [[self accessLock] unlock]; 379 | return cp; 380 | } 381 | 382 | 383 | - (void)setDefaultCachePolicy:(ASICachePolicy)cachePolicy 384 | { 385 | [[self accessLock] lock]; 386 | if (!cachePolicy) { 387 | defaultCachePolicy = ASIAskServerIfModifiedWhenStaleCachePolicy; 388 | } else { 389 | defaultCachePolicy = cachePolicy; 390 | } 391 | [[self accessLock] unlock]; 392 | } 393 | 394 | - (void)clearCachedResponsesForStoragePolicy:(ASICacheStoragePolicy)storagePolicy 395 | { 396 | [[self accessLock] lock]; 397 | if (![self storagePath]) { 398 | [[self accessLock] unlock]; 399 | return; 400 | } 401 | NSString *path = [[self storagePath] stringByAppendingPathComponent:(storagePolicy == ASICacheForSessionDurationCacheStoragePolicy ? sessionCacheFolder : permanentCacheFolder)]; 402 | 403 | NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease]; 404 | 405 | BOOL isDirectory = NO; 406 | BOOL exists = [fileManager fileExistsAtPath:path isDirectory:&isDirectory]; 407 | if (!exists || !isDirectory) { 408 | [[self accessLock] unlock]; 409 | return; 410 | } 411 | NSError *error = nil; 412 | NSArray *cacheFiles = [fileManager contentsOfDirectoryAtPath:path error:&error]; 413 | if (error) { 414 | [[self accessLock] unlock]; 415 | [NSException raise:@"FailedToTraverseCacheDirectory" format:@"Listing cache directory failed at path '%@'",path]; 416 | } 417 | for (NSString *file in cacheFiles) { 418 | [fileManager removeItemAtPath:[path stringByAppendingPathComponent:file] error:&error]; 419 | if (error) { 420 | [[self accessLock] unlock]; 421 | [NSException raise:@"FailedToRemoveCacheFile" format:@"Failed to remove cached data at path '%@'",path]; 422 | } 423 | } 424 | [[self accessLock] unlock]; 425 | } 426 | 427 | + (BOOL)serverAllowsResponseCachingForRequest:(ASIHTTPRequest *)request 428 | { 429 | NSString *cacheControl = [[[request responseHeaders] objectForKey:@"Cache-Control"] lowercaseString]; 430 | if (cacheControl) { 431 | if ([cacheControl isEqualToString:@"no-cache"] || [cacheControl isEqualToString:@"no-store"]) { 432 | return NO; 433 | } 434 | } 435 | NSString *pragma = [[[request responseHeaders] objectForKey:@"Pragma"] lowercaseString]; 436 | if (pragma) { 437 | if ([pragma isEqualToString:@"no-cache"]) { 438 | return NO; 439 | } 440 | } 441 | return YES; 442 | } 443 | 444 | + (NSString *)keyForURL:(NSURL *)url 445 | { 446 | NSString *urlString = [url absoluteString]; 447 | if ([urlString length] == 0) { 448 | return nil; 449 | } 450 | 451 | // Strip trailing slashes so http://allseeing-i.com/ASIHTTPRequest/ is cached the same as http://allseeing-i.com/ASIHTTPRequest 452 | if ([[urlString substringFromIndex:[urlString length]-1] isEqualToString:@"/"]) { 453 | urlString = [urlString substringToIndex:[urlString length]-1]; 454 | } 455 | 456 | // Borrowed from: http://stackoverflow.com/questions/652300/using-md5-hash-on-a-string-in-cocoa 457 | const char *cStr = [urlString UTF8String]; 458 | unsigned char result[16]; 459 | CC_MD5(cStr, (CC_LONG)strlen(cStr), result); 460 | 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]]; 461 | } 462 | 463 | - (BOOL)canUseCachedDataForRequest:(ASIHTTPRequest *)request 464 | { 465 | // Ensure the request is allowed to read from the cache 466 | if ([request cachePolicy] & ASIDoNotReadFromCacheCachePolicy) { 467 | return NO; 468 | 469 | // If we don't want to load the request whatever happens, always pretend we have cached data even if we don't 470 | } else if ([request cachePolicy] & ASIDontLoadCachePolicy) { 471 | return YES; 472 | } 473 | 474 | NSDictionary *headers = [self cachedResponseHeadersForURL:[request url]]; 475 | if (!headers) { 476 | return NO; 477 | } 478 | NSString *dataPath = [self pathToCachedResponseDataForURL:[request url]]; 479 | if (!dataPath) { 480 | return NO; 481 | } 482 | 483 | // If we get here, we have cached data 484 | 485 | // If we have cached data, we can use it 486 | if ([request cachePolicy] & ASIOnlyLoadIfNotCachedCachePolicy) { 487 | return YES; 488 | 489 | // If we want to fallback to the cache after an error 490 | } else if ([request complete] && [request cachePolicy] & ASIFallbackToCacheIfLoadFailsCachePolicy) { 491 | return YES; 492 | 493 | // If we have cached data that is current, we can use it 494 | } else if ([request cachePolicy] & ASIAskServerIfModifiedWhenStaleCachePolicy) { 495 | if ([self isCachedDataCurrentForRequest:request]) { 496 | return YES; 497 | } 498 | 499 | // If we've got headers from a conditional GET and the cached data is still current, we can use it 500 | } else if ([request cachePolicy] & ASIAskServerIfModifiedCachePolicy) { 501 | if (![request responseHeaders]) { 502 | return NO; 503 | } else if ([self isCachedDataCurrentForRequest:request]) { 504 | return YES; 505 | } 506 | } 507 | return NO; 508 | } 509 | 510 | @synthesize storagePath; 511 | @synthesize defaultCachePolicy; 512 | @synthesize accessLock; 513 | @synthesize shouldRespectCacheControlHeaders; 514 | @end 515 | -------------------------------------------------------------------------------- /LASIImageView/External/ASIHTTPRequest/ASIFormDataRequest.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASIFormDataRequest.h 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 07/11/2008. 6 | // Copyright 2008-2009 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ASIHTTPRequest.h" 11 | #import "ASIHTTPRequestConfig.h" 12 | 13 | typedef enum _ASIPostFormat { 14 | ASIMultipartFormDataPostFormat = 0, 15 | ASIURLEncodedPostFormat = 1 16 | 17 | } ASIPostFormat; 18 | 19 | @interface ASIFormDataRequest : ASIHTTPRequest { 20 | 21 | // Parameters that will be POSTed to the url 22 | NSMutableArray *postData; 23 | 24 | // Files that will be POSTed to the url 25 | NSMutableArray *fileData; 26 | 27 | ASIPostFormat postFormat; 28 | 29 | NSStringEncoding stringEncoding; 30 | 31 | #if DEBUG_FORM_DATA_REQUEST 32 | // 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 33 | NSString *debugBodyString; 34 | #endif 35 | 36 | } 37 | 38 | #pragma mark utilities 39 | - (NSString*)encodeURL:(NSString *)string; 40 | 41 | #pragma mark setup request 42 | 43 | // Add a POST variable to the request 44 | - (void)addPostValue:(id )value forKey:(NSString *)key; 45 | 46 | // Set a POST variable for this request, clearing any others with the same key 47 | - (void)setPostValue:(id )value forKey:(NSString *)key; 48 | 49 | // Add the contents of a local file to the request 50 | - (void)addFile:(NSString *)filePath forKey:(NSString *)key; 51 | 52 | // Same as above, but you can specify the content-type and file name 53 | - (void)addFile:(NSString *)filePath withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key; 54 | 55 | // Add the contents of a local file to the request, clearing any others with the same key 56 | - (void)setFile:(NSString *)filePath forKey:(NSString *)key; 57 | 58 | // Same as above, but you can specify the content-type and file name 59 | - (void)setFile:(NSString *)filePath withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key; 60 | 61 | // Add the contents of an NSData object to the request 62 | - (void)addData:(NSData *)data forKey:(NSString *)key; 63 | 64 | // Same as above, but you can specify the content-type and file name 65 | - (void)addData:(id)data withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key; 66 | 67 | // Add the contents of an NSData object to the request, clearing any others with the same key 68 | - (void)setData:(NSData *)data forKey:(NSString *)key; 69 | 70 | // Same as above, but you can specify the content-type and file name 71 | - (void)setData:(id)data withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key; 72 | 73 | 74 | @property (assign) ASIPostFormat postFormat; 75 | @property (assign) NSStringEncoding stringEncoding; 76 | @end 77 | -------------------------------------------------------------------------------- /LASIImageView/External/ASIHTTPRequest/ASIFormDataRequest.m: -------------------------------------------------------------------------------- 1 | // 2 | // ASIFormDataRequest.m 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 07/11/2008. 6 | // Copyright 2008-2009 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import "ASIFormDataRequest.h" 10 | 11 | 12 | // Private stuff 13 | @interface ASIFormDataRequest () 14 | - (void)buildMultipartFormDataPostBody; 15 | - (void)buildURLEncodedPostBody; 16 | - (void)appendPostString:(NSString *)string; 17 | 18 | @property (retain) NSMutableArray *postData; 19 | @property (retain) NSMutableArray *fileData; 20 | 21 | #if DEBUG_FORM_DATA_REQUEST 22 | - (void)addToDebugBody:(NSString *)string; 23 | @property (retain, nonatomic) NSString *debugBodyString; 24 | #endif 25 | 26 | @end 27 | 28 | @implementation ASIFormDataRequest 29 | 30 | #pragma mark utilities 31 | - (NSString*)encodeURL:(NSString *)string 32 | { 33 | NSString *newString = [NSMakeCollectable(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)string, NULL, CFSTR(":/?#[]@!$ &'()*+,;=\"<>%{}|\\^~`"), CFStringConvertNSStringEncodingToEncoding([self stringEncoding]))) autorelease]; 34 | if (newString) { 35 | return newString; 36 | } 37 | return @""; 38 | } 39 | 40 | #pragma mark init / dealloc 41 | 42 | + (id)requestWithURL:(NSURL *)newURL 43 | { 44 | return [[[self alloc] initWithURL:newURL] autorelease]; 45 | } 46 | 47 | - (id)initWithURL:(NSURL *)newURL 48 | { 49 | self = [super initWithURL:newURL]; 50 | [self setPostFormat:ASIURLEncodedPostFormat]; 51 | [self setStringEncoding:NSUTF8StringEncoding]; 52 | [self setRequestMethod:@"POST"]; 53 | return self; 54 | } 55 | 56 | - (void)dealloc 57 | { 58 | #if DEBUG_FORM_DATA_REQUEST 59 | [debugBodyString release]; 60 | #endif 61 | 62 | [postData release]; 63 | [fileData release]; 64 | [super dealloc]; 65 | } 66 | 67 | #pragma mark setup request 68 | 69 | - (void)addPostValue:(id )value forKey:(NSString *)key 70 | { 71 | if (!key) { 72 | return; 73 | } 74 | if (![self postData]) { 75 | [self setPostData:[NSMutableArray array]]; 76 | } 77 | NSMutableDictionary *keyValuePair = [NSMutableDictionary dictionaryWithCapacity:2]; 78 | [keyValuePair setValue:key forKey:@"key"]; 79 | [keyValuePair setValue:[value description] forKey:@"value"]; 80 | [[self postData] addObject:keyValuePair]; 81 | } 82 | 83 | - (void)setPostValue:(id )value forKey:(NSString *)key 84 | { 85 | // Remove any existing value 86 | NSUInteger i; 87 | for (i=0; i<[[self postData] count]; i++) { 88 | NSDictionary *val = [[self postData] objectAtIndex:i]; 89 | if ([[val objectForKey:@"key"] isEqualToString:key]) { 90 | [[self postData] removeObjectAtIndex:i]; 91 | i--; 92 | } 93 | } 94 | [self addPostValue:value forKey:key]; 95 | } 96 | 97 | 98 | - (void)addFile:(NSString *)filePath forKey:(NSString *)key 99 | { 100 | [self addFile:filePath withFileName:nil andContentType:nil forKey:key]; 101 | } 102 | 103 | - (void)addFile:(NSString *)filePath withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key 104 | { 105 | BOOL isDirectory = NO; 106 | BOOL fileExists = [[[[NSFileManager alloc] init] autorelease] fileExistsAtPath:filePath isDirectory:&isDirectory]; 107 | if (!fileExists || isDirectory) { 108 | [self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIInternalErrorWhileBuildingRequestType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"No file exists at %@",filePath],NSLocalizedDescriptionKey,nil]]]; 109 | } 110 | 111 | // If the caller didn't specify a custom file name, we'll use the file name of the file we were passed 112 | if (!fileName) { 113 | fileName = [filePath lastPathComponent]; 114 | } 115 | 116 | // 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 117 | if (!contentType) { 118 | contentType = [ASIHTTPRequest mimeTypeForFileAtPath:filePath]; 119 | } 120 | [self addData:filePath withFileName:fileName andContentType:contentType forKey:key]; 121 | } 122 | 123 | - (void)setFile:(NSString *)filePath forKey:(NSString *)key 124 | { 125 | [self setFile:filePath withFileName:nil andContentType:nil forKey:key]; 126 | } 127 | 128 | - (void)setFile:(id)data withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key 129 | { 130 | // Remove any existing value 131 | NSUInteger i; 132 | for (i=0; i<[[self fileData] count]; i++) { 133 | NSDictionary *val = [[self fileData] objectAtIndex:i]; 134 | if ([[val objectForKey:@"key"] isEqualToString:key]) { 135 | [[self fileData] removeObjectAtIndex:i]; 136 | i--; 137 | } 138 | } 139 | [self addFile:data withFileName:fileName andContentType:contentType forKey:key]; 140 | } 141 | 142 | - (void)addData:(NSData *)data forKey:(NSString *)key 143 | { 144 | [self addData:data withFileName:@"file" andContentType:nil forKey:key]; 145 | } 146 | 147 | - (void)addData:(id)data withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key 148 | { 149 | if (![self fileData]) { 150 | [self setFileData:[NSMutableArray array]]; 151 | } 152 | if (!contentType) { 153 | contentType = @"application/octet-stream"; 154 | } 155 | 156 | NSMutableDictionary *fileInfo = [NSMutableDictionary dictionaryWithCapacity:4]; 157 | [fileInfo setValue:key forKey:@"key"]; 158 | [fileInfo setValue:fileName forKey:@"fileName"]; 159 | [fileInfo setValue:contentType forKey:@"contentType"]; 160 | [fileInfo setValue:data forKey:@"data"]; 161 | 162 | [[self fileData] addObject:fileInfo]; 163 | } 164 | 165 | - (void)setData:(NSData *)data forKey:(NSString *)key 166 | { 167 | [self setData:data withFileName:@"file" andContentType:nil forKey:key]; 168 | } 169 | 170 | - (void)setData:(id)data withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key 171 | { 172 | // Remove any existing value 173 | NSUInteger i; 174 | for (i=0; i<[[self fileData] count]; i++) { 175 | NSDictionary *val = [[self fileData] objectAtIndex:i]; 176 | if ([[val objectForKey:@"key"] isEqualToString:key]) { 177 | [[self fileData] removeObjectAtIndex:i]; 178 | i--; 179 | } 180 | } 181 | [self addData:data withFileName:fileName andContentType:contentType forKey:key]; 182 | } 183 | 184 | - (void)buildPostBody 185 | { 186 | if ([self haveBuiltPostBody]) { 187 | return; 188 | } 189 | 190 | #if DEBUG_FORM_DATA_REQUEST 191 | [self setDebugBodyString:@""]; 192 | #endif 193 | 194 | if (![self postData] && ![self fileData]) { 195 | [super buildPostBody]; 196 | return; 197 | } 198 | if ([[self fileData] count] > 0) { 199 | [self setShouldStreamPostDataFromDisk:YES]; 200 | } 201 | 202 | if ([self postFormat] == ASIURLEncodedPostFormat) { 203 | [self buildURLEncodedPostBody]; 204 | } else { 205 | [self buildMultipartFormDataPostBody]; 206 | } 207 | 208 | [super buildPostBody]; 209 | 210 | #if DEBUG_FORM_DATA_REQUEST 211 | ASI_DEBUG_LOG(@"%@",[self debugBodyString]); 212 | [self setDebugBodyString:nil]; 213 | #endif 214 | } 215 | 216 | 217 | - (void)buildMultipartFormDataPostBody 218 | { 219 | #if DEBUG_FORM_DATA_REQUEST 220 | [self addToDebugBody:@"\r\n==== Building a multipart/form-data body ====\r\n"]; 221 | #endif 222 | 223 | NSString *charset = (NSString *)CFStringConvertEncodingToIANACharSetName(CFStringConvertNSStringEncodingToEncoding([self stringEncoding])); 224 | 225 | // We don't bother to check if post data contains the boundary, since it's pretty unlikely that it does. 226 | CFUUIDRef uuid = CFUUIDCreate(nil); 227 | NSString *uuidString = [(NSString*)CFUUIDCreateString(nil, uuid) autorelease]; 228 | CFRelease(uuid); 229 | NSString *stringBoundary = [NSString stringWithFormat:@"0xKhTmLbOuNdArY-%@",uuidString]; 230 | 231 | [self addRequestHeader:@"Content-Type" value:[NSString stringWithFormat:@"multipart/form-data; charset=%@; boundary=%@", charset, stringBoundary]]; 232 | 233 | [self appendPostString:[NSString stringWithFormat:@"--%@\r\n",stringBoundary]]; 234 | 235 | // Adds post data 236 | NSString *endItemBoundary = [NSString stringWithFormat:@"\r\n--%@\r\n",stringBoundary]; 237 | NSUInteger i=0; 238 | for (NSDictionary *val in [self postData]) { 239 | [self appendPostString:[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n",[val objectForKey:@"key"]]]; 240 | [self appendPostString:[val objectForKey:@"value"]]; 241 | i++; 242 | if (i != [[self postData] count] || [[self fileData] count] > 0) { //Only add the boundary if this is not the last item in the post body 243 | [self appendPostString:endItemBoundary]; 244 | } 245 | } 246 | 247 | // Adds files to upload 248 | i=0; 249 | for (NSDictionary *val in [self fileData]) { 250 | 251 | [self appendPostString:[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", [val objectForKey:@"key"], [val objectForKey:@"fileName"]]]; 252 | [self appendPostString:[NSString stringWithFormat:@"Content-Type: %@\r\n\r\n", [val objectForKey:@"contentType"]]]; 253 | 254 | id data = [val objectForKey:@"data"]; 255 | if ([data isKindOfClass:[NSString class]]) { 256 | [self appendPostDataFromFile:data]; 257 | } else { 258 | [self appendPostData:data]; 259 | } 260 | i++; 261 | // Only add the boundary if this is not the last item in the post body 262 | if (i != [[self fileData] count]) { 263 | [self appendPostString:endItemBoundary]; 264 | } 265 | } 266 | 267 | [self appendPostString:[NSString stringWithFormat:@"\r\n--%@--\r\n",stringBoundary]]; 268 | 269 | #if DEBUG_FORM_DATA_REQUEST 270 | [self addToDebugBody:@"==== End of multipart/form-data body ====\r\n"]; 271 | #endif 272 | } 273 | 274 | - (void)buildURLEncodedPostBody 275 | { 276 | 277 | // We can't post binary data using application/x-www-form-urlencoded 278 | if ([[self fileData] count] > 0) { 279 | [self setPostFormat:ASIMultipartFormDataPostFormat]; 280 | [self buildMultipartFormDataPostBody]; 281 | return; 282 | } 283 | 284 | #if DEBUG_FORM_DATA_REQUEST 285 | [self addToDebugBody:@"\r\n==== Building an application/x-www-form-urlencoded body ====\r\n"]; 286 | #endif 287 | 288 | 289 | NSString *charset = (NSString *)CFStringConvertEncodingToIANACharSetName(CFStringConvertNSStringEncodingToEncoding([self stringEncoding])); 290 | 291 | [self addRequestHeader:@"Content-Type" value:[NSString stringWithFormat:@"application/x-www-form-urlencoded; charset=%@",charset]]; 292 | 293 | 294 | NSUInteger i=0; 295 | NSUInteger count = [[self postData] count]-1; 296 | for (NSDictionary *val in [self postData]) { 297 | NSString *data = [NSString stringWithFormat:@"%@=%@%@", [self encodeURL:[val objectForKey:@"key"]], [self encodeURL:[val objectForKey:@"value"]],(i http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 14/12/2009. 6 | // Copyright 2009 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | 10 | // ====== 11 | // Debug output configuration options 12 | // ====== 13 | 14 | // If defined will use the specified function for debug logging 15 | // Otherwise use NSLog 16 | #ifndef ASI_DEBUG_LOG 17 | #define ASI_DEBUG_LOG NSLog 18 | #endif 19 | 20 | // When set to 1 ASIHTTPRequests will print information about what a request is doing 21 | #ifndef DEBUG_REQUEST_STATUS 22 | #define DEBUG_REQUEST_STATUS 0 23 | #endif 24 | 25 | // When set to 1, ASIFormDataRequests will print information about the request body to the console 26 | #ifndef DEBUG_FORM_DATA_REQUEST 27 | #define DEBUG_FORM_DATA_REQUEST 0 28 | #endif 29 | 30 | // When set to 1, ASIHTTPRequests will print information about bandwidth throttling to the console 31 | #ifndef DEBUG_THROTTLING 32 | #define DEBUG_THROTTLING 0 33 | #endif 34 | 35 | // When set to 1, ASIHTTPRequests will print information about persistent connections to the console 36 | #ifndef DEBUG_PERSISTENT_CONNECTIONS 37 | #define DEBUG_PERSISTENT_CONNECTIONS 0 38 | #endif 39 | 40 | // When set to 1, ASIHTTPRequests will print information about HTTP authentication (Basic, Digest or NTLM) to the console 41 | #ifndef DEBUG_HTTP_AUTHENTICATION 42 | #define DEBUG_HTTP_AUTHENTICATION 0 43 | #endif 44 | -------------------------------------------------------------------------------- /LASIImageView/External/ASIHTTPRequest/ASIHTTPRequestDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASIHTTPRequestDelegate.h 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 13/04/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | @class ASIHTTPRequest; 10 | 11 | @protocol ASIHTTPRequestDelegate 12 | 13 | @optional 14 | 15 | // These are the default delegate methods for request status 16 | // You can use different ones by setting didStartSelector / didFinishSelector / didFailSelector 17 | - (void)requestStarted:(ASIHTTPRequest *)request; 18 | - (void)request:(ASIHTTPRequest *)request didReceiveResponseHeaders:(NSDictionary *)responseHeaders; 19 | - (void)request:(ASIHTTPRequest *)request willRedirectToURL:(NSURL *)newURL; 20 | - (void)requestFinished:(ASIHTTPRequest *)request; 21 | - (void)requestFailed:(ASIHTTPRequest *)request; 22 | - (void)requestRedirected:(ASIHTTPRequest *)request; 23 | 24 | // When a delegate implements this method, it is expected to process all incoming data itself 25 | // This means that responseData / responseString / downloadDestinationPath etc are ignored 26 | // You can have the request call a different method by setting didReceiveDataSelector 27 | - (void)request:(ASIHTTPRequest *)request didReceiveData:(NSData *)data; 28 | 29 | // If a delegate implements one of these, it will be asked to supply credentials when none are available 30 | // The delegate can then either restart the request ([request retryUsingSuppliedCredentials]) once credentials have been set 31 | // or cancel it ([request cancelAuthentication]) 32 | - (void)authenticationNeededForRequest:(ASIHTTPRequest *)request; 33 | - (void)proxyAuthenticationNeededForRequest:(ASIHTTPRequest *)request; 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /LASIImageView/External/ASIHTTPRequest/ASIInputStream.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASIInputStream.h 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 10/08/2009. 6 | // Copyright 2009 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class ASIHTTPRequest; 12 | 13 | // This is a wrapper for NSInputStream that pretends to be an NSInputStream itself 14 | // Subclassing NSInputStream seems to be tricky, and may involve overriding undocumented methods, so we'll cheat instead. 15 | // It is used by ASIHTTPRequest whenever we have a request body, and handles measuring and throttling the bandwidth used for uploading 16 | 17 | @interface ASIInputStream : NSObject { 18 | NSInputStream *stream; 19 | ASIHTTPRequest *request; 20 | } 21 | + (id)inputStreamWithFileAtPath:(NSString *)path request:(ASIHTTPRequest *)request; 22 | + (id)inputStreamWithData:(NSData *)data request:(ASIHTTPRequest *)request; 23 | 24 | @property (retain, nonatomic) NSInputStream *stream; 25 | @property (assign, nonatomic) ASIHTTPRequest *request; 26 | @end 27 | -------------------------------------------------------------------------------- /LASIImageView/External/ASIHTTPRequest/ASIInputStream.m: -------------------------------------------------------------------------------- 1 | // 2 | // ASIInputStream.m 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 10/08/2009. 6 | // Copyright 2009 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import "ASIInputStream.h" 10 | #import "ASIHTTPRequest.h" 11 | 12 | // Used to ensure only one request can read data at once 13 | static NSLock *readLock = nil; 14 | 15 | @implementation ASIInputStream 16 | 17 | + (void)initialize 18 | { 19 | if (self == [ASIInputStream class]) { 20 | readLock = [[NSLock alloc] init]; 21 | } 22 | } 23 | 24 | + (id)inputStreamWithFileAtPath:(NSString *)path request:(ASIHTTPRequest *)theRequest 25 | { 26 | ASIInputStream *theStream = [[[self alloc] init] autorelease]; 27 | [theStream setRequest:theRequest]; 28 | [theStream setStream:[NSInputStream inputStreamWithFileAtPath:path]]; 29 | return theStream; 30 | } 31 | 32 | + (id)inputStreamWithData:(NSData *)data request:(ASIHTTPRequest *)theRequest 33 | { 34 | ASIInputStream *theStream = [[[self alloc] init] autorelease]; 35 | [theStream setRequest:theRequest]; 36 | [theStream setStream:[NSInputStream inputStreamWithData:data]]; 37 | return theStream; 38 | } 39 | 40 | - (void)dealloc 41 | { 42 | [stream release]; 43 | [super dealloc]; 44 | } 45 | 46 | // Called when CFNetwork wants to read more of our request body 47 | // When throttling is on, we ask ASIHTTPRequest for the maximum amount of data we can read 48 | - (NSInteger)read:(uint8_t *)buffer maxLength:(NSUInteger)len 49 | { 50 | [readLock lock]; 51 | unsigned long toRead = len; 52 | if ([ASIHTTPRequest isBandwidthThrottled]) { 53 | toRead = [ASIHTTPRequest maxUploadReadLength]; 54 | if (toRead > len) { 55 | toRead = len; 56 | } else if (toRead == 0) { 57 | toRead = 1; 58 | } 59 | [request performThrottling]; 60 | } 61 | [readLock unlock]; 62 | NSInteger rv = [stream read:buffer maxLength:toRead]; 63 | if (rv > 0) 64 | [ASIHTTPRequest incrementBandwidthUsedInLastSecond:rv]; 65 | return rv; 66 | } 67 | 68 | /* 69 | * Implement NSInputStream mandatory methods to make sure they are implemented 70 | * (necessary for MacRuby for example) and avoid the overhead of method 71 | * forwarding for these common methods. 72 | */ 73 | - (void)open 74 | { 75 | [stream open]; 76 | } 77 | 78 | - (void)close 79 | { 80 | [stream close]; 81 | } 82 | 83 | - (id)delegate 84 | { 85 | return [stream delegate]; 86 | } 87 | 88 | - (void)setDelegate:(id)delegate 89 | { 90 | [stream setDelegate:delegate]; 91 | } 92 | 93 | - (void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode 94 | { 95 | [stream scheduleInRunLoop:aRunLoop forMode:mode]; 96 | } 97 | 98 | - (void)removeFromRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode 99 | { 100 | [stream removeFromRunLoop:aRunLoop forMode:mode]; 101 | } 102 | 103 | - (id)propertyForKey:(NSString *)key 104 | { 105 | return [stream propertyForKey:key]; 106 | } 107 | 108 | - (BOOL)setProperty:(id)property forKey:(NSString *)key 109 | { 110 | return [stream setProperty:property forKey:key]; 111 | } 112 | 113 | - (NSStreamStatus)streamStatus 114 | { 115 | return [stream streamStatus]; 116 | } 117 | 118 | - (NSError *)streamError 119 | { 120 | return [stream streamError]; 121 | } 122 | 123 | // If we get asked to perform a method we don't have (probably internal ones), 124 | // we'll just forward the message to our stream 125 | 126 | - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector 127 | { 128 | return [stream methodSignatureForSelector:aSelector]; 129 | } 130 | 131 | - (void)forwardInvocation:(NSInvocation *)anInvocation 132 | { 133 | [anInvocation invokeWithTarget:stream]; 134 | } 135 | 136 | @synthesize stream; 137 | @synthesize request; 138 | @end 139 | -------------------------------------------------------------------------------- /LASIImageView/External/ASIHTTPRequest/ASINetworkQueue.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASINetworkQueue.h 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 07/11/2008. 6 | // Copyright 2008-2009 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ASIHTTPRequestDelegate.h" 11 | #import "ASIProgressDelegate.h" 12 | 13 | @interface ASINetworkQueue : NSOperationQueue { 14 | 15 | // Delegate will get didFail + didFinish messages (if set) 16 | id delegate; 17 | 18 | // Will be called when a request starts with the request as the argument 19 | SEL requestDidStartSelector; 20 | 21 | // Will be called when a request receives response headers 22 | // Should take the form request:didRecieveResponseHeaders:, where the first argument is the request, and the second the headers dictionary 23 | SEL requestDidReceiveResponseHeadersSelector; 24 | 25 | // Will be called when a request is about to redirect 26 | // Should take the form request:willRedirectToURL:, where the first argument is the request, and the second the new url 27 | SEL requestWillRedirectSelector; 28 | 29 | // Will be called when a request completes with the request as the argument 30 | SEL requestDidFinishSelector; 31 | 32 | // Will be called when a request fails with the request as the argument 33 | SEL requestDidFailSelector; 34 | 35 | // Will be called when the queue finishes with the queue as the argument 36 | SEL queueDidFinishSelector; 37 | 38 | // Upload progress indicator, probably an NSProgressIndicator or UIProgressView 39 | id uploadProgressDelegate; 40 | 41 | // Total amount uploaded so far for all requests in this queue 42 | unsigned long long bytesUploadedSoFar; 43 | 44 | // Total amount to be uploaded for all requests in this queue - requests add to this figure as they work out how much data they have to transmit 45 | unsigned long long totalBytesToUpload; 46 | 47 | // Download progress indicator, probably an NSProgressIndicator or UIProgressView 48 | id downloadProgressDelegate; 49 | 50 | // Total amount downloaded so far for all requests in this queue 51 | unsigned long long bytesDownloadedSoFar; 52 | 53 | // Total amount to be downloaded for all requests in this queue - requests add to this figure as they receive Content-Length headers 54 | unsigned long long totalBytesToDownload; 55 | 56 | // When YES, the queue will cancel all requests when a request fails. Default is YES 57 | BOOL shouldCancelAllRequestsOnFailure; 58 | 59 | //Number of real requests (excludes HEAD requests created to manage showAccurateProgress) 60 | int requestsCount; 61 | 62 | // When NO, this request will only update the progress indicator when it completes 63 | // When YES, this request will update the progress indicator according to how much data it has received so far 64 | // When YES, the queue will first perform HEAD requests for all GET requests in the queue, so it can calculate the total download size before it starts 65 | // NO means better performance, because it skips this step for GET requests, and it won't waste time updating the progress indicator until a request completes 66 | // Set to YES if the size of a requests in the queue varies greatly for much more accurate results 67 | // Default for requests in the queue is NO 68 | BOOL showAccurateProgress; 69 | 70 | // Storage container for additional queue information. 71 | NSDictionary *userInfo; 72 | 73 | } 74 | 75 | // Convenience constructor 76 | + (id)queue; 77 | 78 | // Call this to reset a queue - it will cancel all operations, clear delegates, and suspend operation 79 | - (void)reset; 80 | 81 | // Used internally to manage HEAD requests when showAccurateProgress is YES, do not use! 82 | - (void)addHEADOperation:(NSOperation *)operation; 83 | 84 | // All ASINetworkQueues are paused when created so that total size can be calculated before the queue starts 85 | // This method will start the queue 86 | - (void)go; 87 | 88 | @property (assign, nonatomic, setter=setUploadProgressDelegate:) id uploadProgressDelegate; 89 | @property (assign, nonatomic, setter=setDownloadProgressDelegate:) id downloadProgressDelegate; 90 | 91 | @property (assign) SEL requestDidStartSelector; 92 | @property (assign) SEL requestDidReceiveResponseHeadersSelector; 93 | @property (assign) SEL requestWillRedirectSelector; 94 | @property (assign) SEL requestDidFinishSelector; 95 | @property (assign) SEL requestDidFailSelector; 96 | @property (assign) SEL queueDidFinishSelector; 97 | @property (assign) BOOL shouldCancelAllRequestsOnFailure; 98 | @property (assign) id delegate; 99 | @property (assign) BOOL showAccurateProgress; 100 | @property (assign, readonly) int requestsCount; 101 | @property (retain) NSDictionary *userInfo; 102 | 103 | @property (assign) unsigned long long bytesUploadedSoFar; 104 | @property (assign) unsigned long long totalBytesToUpload; 105 | @property (assign) unsigned long long bytesDownloadedSoFar; 106 | @property (assign) unsigned long long totalBytesToDownload; 107 | 108 | @end 109 | -------------------------------------------------------------------------------- /LASIImageView/External/ASIHTTPRequest/ASINetworkQueue.m: -------------------------------------------------------------------------------- 1 | // 2 | // ASINetworkQueue.m 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 07/11/2008. 6 | // Copyright 2008-2009 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | #import "ASINetworkQueue.h" 10 | #import "ASIHTTPRequest.h" 11 | 12 | // Private stuff 13 | @interface ASINetworkQueue () 14 | - (void)resetProgressDelegate:(id *)progressDelegate; 15 | @property (assign) int requestsCount; 16 | @end 17 | 18 | @implementation ASINetworkQueue 19 | 20 | - (id)init 21 | { 22 | self = [super init]; 23 | [self setShouldCancelAllRequestsOnFailure:YES]; 24 | [self setMaxConcurrentOperationCount:4]; 25 | [self setSuspended:YES]; 26 | 27 | return self; 28 | } 29 | 30 | + (id)queue 31 | { 32 | return [[[self alloc] init] autorelease]; 33 | } 34 | 35 | - (void)dealloc 36 | { 37 | //We need to clear the queue on any requests that haven't got around to cleaning up yet, as otherwise they'll try to let us know if something goes wrong, and we'll be long gone by then 38 | for (ASIHTTPRequest *request in [self operations]) { 39 | [request setQueue:nil]; 40 | } 41 | [userInfo release]; 42 | [super dealloc]; 43 | } 44 | 45 | - (void)setSuspended:(BOOL)suspend 46 | { 47 | [super setSuspended:suspend]; 48 | } 49 | 50 | - (void)reset 51 | { 52 | [self cancelAllOperations]; 53 | [self setDelegate:nil]; 54 | [self setDownloadProgressDelegate:nil]; 55 | [self setUploadProgressDelegate:nil]; 56 | [self setRequestDidStartSelector:NULL]; 57 | [self setRequestDidReceiveResponseHeadersSelector:NULL]; 58 | [self setRequestDidFailSelector:NULL]; 59 | [self setRequestDidFinishSelector:NULL]; 60 | [self setQueueDidFinishSelector:NULL]; 61 | [self setSuspended:YES]; 62 | } 63 | 64 | 65 | - (void)go 66 | { 67 | [self setSuspended:NO]; 68 | } 69 | 70 | - (void)cancelAllOperations 71 | { 72 | [self setBytesUploadedSoFar:0]; 73 | [self setTotalBytesToUpload:0]; 74 | [self setBytesDownloadedSoFar:0]; 75 | [self setTotalBytesToDownload:0]; 76 | [super cancelAllOperations]; 77 | } 78 | 79 | - (void)setUploadProgressDelegate:(id)newDelegate 80 | { 81 | uploadProgressDelegate = newDelegate; 82 | [self resetProgressDelegate:&uploadProgressDelegate]; 83 | 84 | } 85 | 86 | - (void)setDownloadProgressDelegate:(id)newDelegate 87 | { 88 | downloadProgressDelegate = newDelegate; 89 | [self resetProgressDelegate:&downloadProgressDelegate]; 90 | } 91 | 92 | - (void)resetProgressDelegate:(id *)progressDelegate 93 | { 94 | #if !TARGET_OS_IPHONE 95 | // If the uploadProgressDelegate is an NSProgressIndicator, we set its MaxValue to 1.0 so we can treat it similarly to UIProgressViews 96 | SEL selector = @selector(setMaxValue:); 97 | if ([*progressDelegate respondsToSelector:selector]) { 98 | double max = 1.0; 99 | [ASIHTTPRequest performSelector:selector onTarget:progressDelegate withObject:nil amount:&max callerToRetain:nil]; 100 | } 101 | selector = @selector(setDoubleValue:); 102 | if ([*progressDelegate respondsToSelector:selector]) { 103 | double value = 0.0; 104 | [ASIHTTPRequest performSelector:selector onTarget:progressDelegate withObject:nil amount:&value callerToRetain:nil]; 105 | } 106 | #else 107 | SEL selector = @selector(setProgress:); 108 | if ([*progressDelegate respondsToSelector:selector]) { 109 | float value = 0.0f; 110 | [ASIHTTPRequest performSelector:selector onTarget:progressDelegate withObject:nil amount:&value callerToRetain:nil]; 111 | } 112 | #endif 113 | } 114 | 115 | - (void)addHEADOperation:(NSOperation *)operation 116 | { 117 | if ([operation isKindOfClass:[ASIHTTPRequest class]]) { 118 | 119 | ASIHTTPRequest *request = (ASIHTTPRequest *)operation; 120 | [request setRequestMethod:@"HEAD"]; 121 | [request setQueuePriority:10]; 122 | [request setShowAccurateProgress:YES]; 123 | [request setQueue:self]; 124 | 125 | // Important - we are calling NSOperation's add method - we don't want to add this as a normal request! 126 | [super addOperation:request]; 127 | } 128 | } 129 | 130 | // Only add ASIHTTPRequests to this queue!! 131 | - (void)addOperation:(NSOperation *)operation 132 | { 133 | if (![operation isKindOfClass:[ASIHTTPRequest class]]) { 134 | [NSException raise:@"AttemptToAddInvalidRequest" format:@"Attempted to add an object that was not an ASIHTTPRequest to an ASINetworkQueue"]; 135 | } 136 | 137 | [self setRequestsCount:[self requestsCount]+1]; 138 | 139 | ASIHTTPRequest *request = (ASIHTTPRequest *)operation; 140 | 141 | if ([self showAccurateProgress]) { 142 | 143 | // Force the request to build its body (this may change requestMethod) 144 | [request buildPostBody]; 145 | 146 | // If this is a GET request and we want accurate progress, perform a HEAD request first to get the content-length 147 | // We'll only do this before the queue is started 148 | // If requests are added after the queue is started they will probably move the overall progress backwards anyway, so there's no value performing the HEAD requests first 149 | // Instead, they'll update the total progress if and when they receive a content-length header 150 | if ([[request requestMethod] isEqualToString:@"GET"]) { 151 | if ([self isSuspended]) { 152 | ASIHTTPRequest *HEADRequest = [request HEADRequest]; 153 | [self addHEADOperation:HEADRequest]; 154 | [request addDependency:HEADRequest]; 155 | if ([request shouldResetDownloadProgress]) { 156 | [self resetProgressDelegate:&downloadProgressDelegate]; 157 | [request setShouldResetDownloadProgress:NO]; 158 | } 159 | } 160 | } 161 | [request buildPostBody]; 162 | [self request:nil incrementUploadSizeBy:[request postLength]]; 163 | 164 | 165 | } else { 166 | [self request:nil incrementDownloadSizeBy:1]; 167 | [self request:nil incrementUploadSizeBy:1]; 168 | } 169 | // Tell the request not to increment the upload size when it starts, as we've already added its length 170 | if ([request shouldResetUploadProgress]) { 171 | [self resetProgressDelegate:&uploadProgressDelegate]; 172 | [request setShouldResetUploadProgress:NO]; 173 | } 174 | 175 | [request setShowAccurateProgress:[self showAccurateProgress]]; 176 | 177 | [request setQueue:self]; 178 | [super addOperation:request]; 179 | 180 | } 181 | 182 | - (void)requestStarted:(ASIHTTPRequest *)request 183 | { 184 | if ([self requestDidStartSelector]) { 185 | [[self delegate] performSelector:[self requestDidStartSelector] withObject:request]; 186 | } 187 | } 188 | 189 | - (void)request:(ASIHTTPRequest *)request didReceiveResponseHeaders:(NSDictionary *)responseHeaders 190 | { 191 | if ([self requestDidReceiveResponseHeadersSelector]) { 192 | [[self delegate] performSelector:[self requestDidReceiveResponseHeadersSelector] withObject:request withObject:responseHeaders]; 193 | } 194 | } 195 | 196 | - (void)request:(ASIHTTPRequest *)request willRedirectToURL:(NSURL *)newURL 197 | { 198 | if ([self requestWillRedirectSelector]) { 199 | [[self delegate] performSelector:[self requestWillRedirectSelector] withObject:request withObject:newURL]; 200 | } 201 | } 202 | 203 | - (void)requestFinished:(ASIHTTPRequest *)request 204 | { 205 | [self setRequestsCount:[self requestsCount]-1]; 206 | if ([self requestDidFinishSelector]) { 207 | [[self delegate] performSelector:[self requestDidFinishSelector] withObject:request]; 208 | } 209 | if ([self requestsCount] == 0) { 210 | if ([self queueDidFinishSelector]) { 211 | [[self delegate] performSelector:[self queueDidFinishSelector] withObject:self]; 212 | } 213 | } 214 | } 215 | 216 | - (void)requestFailed:(ASIHTTPRequest *)request 217 | { 218 | [self setRequestsCount:[self requestsCount]-1]; 219 | if ([self requestDidFailSelector]) { 220 | [[self delegate] performSelector:[self requestDidFailSelector] withObject:request]; 221 | } 222 | if ([self requestsCount] == 0) { 223 | if ([self queueDidFinishSelector]) { 224 | [[self delegate] performSelector:[self queueDidFinishSelector] withObject:self]; 225 | } 226 | } 227 | if ([self shouldCancelAllRequestsOnFailure] && [self requestsCount] > 0) { 228 | [self cancelAllOperations]; 229 | } 230 | 231 | } 232 | 233 | 234 | - (void)request:(ASIHTTPRequest *)request didReceiveBytes:(long long)bytes 235 | { 236 | [self setBytesDownloadedSoFar:[self bytesDownloadedSoFar]+bytes]; 237 | if ([self downloadProgressDelegate]) { 238 | [ASIHTTPRequest updateProgressIndicator:&downloadProgressDelegate withProgress:[self bytesDownloadedSoFar] ofTotal:[self totalBytesToDownload]]; 239 | } 240 | } 241 | 242 | - (void)request:(ASIHTTPRequest *)request didSendBytes:(long long)bytes 243 | { 244 | [self setBytesUploadedSoFar:[self bytesUploadedSoFar]+bytes]; 245 | if ([self uploadProgressDelegate]) { 246 | [ASIHTTPRequest updateProgressIndicator:&uploadProgressDelegate withProgress:[self bytesUploadedSoFar] ofTotal:[self totalBytesToUpload]]; 247 | } 248 | } 249 | 250 | - (void)request:(ASIHTTPRequest *)request incrementDownloadSizeBy:(long long)newLength 251 | { 252 | [self setTotalBytesToDownload:[self totalBytesToDownload]+newLength]; 253 | } 254 | 255 | - (void)request:(ASIHTTPRequest *)request incrementUploadSizeBy:(long long)newLength 256 | { 257 | [self setTotalBytesToUpload:[self totalBytesToUpload]+newLength]; 258 | } 259 | 260 | 261 | // Since this queue takes over as the delegate for all requests it contains, it should forward authorisation requests to its own delegate 262 | - (void)authenticationNeededForRequest:(ASIHTTPRequest *)request 263 | { 264 | if ([[self delegate] respondsToSelector:@selector(authenticationNeededForRequest:)]) { 265 | [[self delegate] performSelector:@selector(authenticationNeededForRequest:) withObject:request]; 266 | } 267 | } 268 | 269 | - (void)proxyAuthenticationNeededForRequest:(ASIHTTPRequest *)request 270 | { 271 | if ([[self delegate] respondsToSelector:@selector(proxyAuthenticationNeededForRequest:)]) { 272 | [[self delegate] performSelector:@selector(proxyAuthenticationNeededForRequest:) withObject:request]; 273 | } 274 | } 275 | 276 | 277 | - (BOOL)respondsToSelector:(SEL)selector 278 | { 279 | // We handle certain methods differently because whether our delegate implements them or not can affect how the request should behave 280 | 281 | // If the delegate implements this, the request will stop to wait for credentials 282 | if (selector == @selector(authenticationNeededForRequest:)) { 283 | if ([[self delegate] respondsToSelector:@selector(authenticationNeededForRequest:)]) { 284 | return YES; 285 | } 286 | return NO; 287 | 288 | // If the delegate implements this, the request will to wait for credentials 289 | } else if (selector == @selector(proxyAuthenticationNeededForRequest:)) { 290 | if ([[self delegate] respondsToSelector:@selector(proxyAuthenticationNeededForRequest:)]) { 291 | return YES; 292 | } 293 | return NO; 294 | 295 | // If the delegate implements requestWillRedirectSelector, the request will stop to allow the delegate to change the url 296 | } else if (selector == @selector(request:willRedirectToURL:)) { 297 | if ([self requestWillRedirectSelector] && [[self delegate] respondsToSelector:[self requestWillRedirectSelector]]) { 298 | return YES; 299 | } 300 | return NO; 301 | } 302 | return [super respondsToSelector:selector]; 303 | } 304 | 305 | #pragma mark NSCopying 306 | 307 | - (id)copyWithZone:(NSZone *)zone 308 | { 309 | ASINetworkQueue *newQueue = [[[self class] alloc] init]; 310 | [newQueue setDelegate:[self delegate]]; 311 | [newQueue setRequestDidStartSelector:[self requestDidStartSelector]]; 312 | [newQueue setRequestWillRedirectSelector:[self requestWillRedirectSelector]]; 313 | [newQueue setRequestDidReceiveResponseHeadersSelector:[self requestDidReceiveResponseHeadersSelector]]; 314 | [newQueue setRequestDidFinishSelector:[self requestDidFinishSelector]]; 315 | [newQueue setRequestDidFailSelector:[self requestDidFailSelector]]; 316 | [newQueue setQueueDidFinishSelector:[self queueDidFinishSelector]]; 317 | [newQueue setUploadProgressDelegate:[self uploadProgressDelegate]]; 318 | [newQueue setDownloadProgressDelegate:[self downloadProgressDelegate]]; 319 | [newQueue setShouldCancelAllRequestsOnFailure:[self shouldCancelAllRequestsOnFailure]]; 320 | [newQueue setShowAccurateProgress:[self showAccurateProgress]]; 321 | [newQueue setUserInfo:[[[self userInfo] copyWithZone:zone] autorelease]]; 322 | return newQueue; 323 | } 324 | 325 | 326 | @synthesize requestsCount; 327 | @synthesize bytesUploadedSoFar; 328 | @synthesize totalBytesToUpload; 329 | @synthesize bytesDownloadedSoFar; 330 | @synthesize totalBytesToDownload; 331 | @synthesize shouldCancelAllRequestsOnFailure; 332 | @synthesize uploadProgressDelegate; 333 | @synthesize downloadProgressDelegate; 334 | @synthesize requestDidStartSelector; 335 | @synthesize requestDidReceiveResponseHeadersSelector; 336 | @synthesize requestWillRedirectSelector; 337 | @synthesize requestDidFinishSelector; 338 | @synthesize requestDidFailSelector; 339 | @synthesize queueDidFinishSelector; 340 | @synthesize delegate; 341 | @synthesize showAccurateProgress; 342 | @synthesize userInfo; 343 | @end 344 | -------------------------------------------------------------------------------- /LASIImageView/External/ASIHTTPRequest/ASIProgressDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // ASIProgressDelegate.h 3 | // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest 4 | // 5 | // Created by Ben Copsey on 13/04/2010. 6 | // Copyright 2010 All-Seeing Interactive. All rights reserved. 7 | // 8 | 9 | @class ASIHTTPRequest; 10 | 11 | @protocol ASIProgressDelegate 12 | 13 | @optional 14 | 15 | // These methods are used to update UIProgressViews (iPhone OS) or NSProgressIndicators (Mac OS X) 16 | // If you are using a custom progress delegate, you may find it easier to implement didReceiveBytes / didSendBytes instead 17 | #if TARGET_OS_IPHONE 18 | - (void)setProgress:(float)newProgress; 19 | #else 20 | - (void)setDoubleValue:(double)newProgress; 21 | - (void)setMaxValue:(double)newMax; 22 | #endif 23 | 24 | // Called when the request receives some data - bytes is the length of that data 25 | - (void)request:(ASIHTTPRequest *)request didReceiveBytes:(long long)bytes; 26 | 27 | // Called when the request sends some data 28 | // The first 32KB (128KB on older platforms) of data sent is not included in this amount because of limitations with the CFNetwork API 29 | // bytes may be less than zero if a request needs to remove upload progress (probably because the request needs to run again) 30 | - (void)request:(ASIHTTPRequest *)request didSendBytes:(long long)bytes; 31 | 32 | // Called when a request needs to change the length of the content to download 33 | - (void)request:(ASIHTTPRequest *)request incrementDownloadSizeBy:(long long)newLength; 34 | 35 | // Called when a request needs to change the length of the content to upload 36 | // newLength may be less than zero when a request needs to remove the size of the internal buffer from progress tracking 37 | - (void)request:(ASIHTTPRequest *)request incrementUploadSizeBy:(long long)newLength; 38 | @end 39 | -------------------------------------------------------------------------------- /LASIImageView/External/Reachability/Reachability.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | File: Reachability.h 4 | Abstract: Basic demonstration of how to use the SystemConfiguration Reachablity APIs. 5 | 6 | Version: 2.0.4ddg 7 | */ 8 | 9 | /* 10 | Significant additions made by Andrew W. Donoho, August 11, 2009. 11 | This is a derived work of Apple's Reachability v2.0 class. 12 | 13 | The below license is the new BSD license with the OSI recommended personalizations. 14 | 15 | 16 | Extensions Copyright (C) 2009 Donoho Design Group, LLC. All Rights Reserved. 17 | 18 | Redistribution and use in source and binary forms, with or without 19 | modification, are permitted provided that the following conditions are 20 | met: 21 | 22 | * Redistributions of source code must retain the above copyright notice, 23 | this list of conditions and the following disclaimer. 24 | 25 | * Redistributions in binary form must reproduce the above copyright 26 | notice, this list of conditions and the following disclaimer in the 27 | documentation and/or other materials provided with the distribution. 28 | 29 | * Neither the name of Andrew W. Donoho nor Donoho Design Group, L.L.C. 30 | may be used to endorse or promote products derived from this software 31 | without specific prior written permission. 32 | 33 | THIS SOFTWARE IS PROVIDED BY DONOHO DESIGN GROUP, L.L.C. "AS IS" AND ANY 34 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 35 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 36 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 37 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 38 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 39 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 40 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 41 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 42 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 43 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 44 | 45 | */ 46 | 47 | 48 | /* 49 | 50 | Apple's Original License on Reachability v2.0 51 | 52 | Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. 53 | ("Apple") in consideration of your agreement to the following terms, and your 54 | use, installation, modification or redistribution of this Apple software 55 | constitutes acceptance of these terms. If you do not agree with these terms, 56 | please do not use, install, modify or redistribute this Apple software. 57 | 58 | In consideration of your agreement to abide by the following terms, and subject 59 | to these terms, Apple grants you a personal, non-exclusive license, under 60 | Apple's copyrights in this original Apple software (the "Apple Software"), to 61 | use, reproduce, modify and redistribute the Apple Software, with or without 62 | modifications, in source and/or binary forms; provided that if you redistribute 63 | the Apple Software in its entirety and without modifications, you must retain 64 | this notice and the following text and disclaimers in all such redistributions 65 | of the Apple Software. 66 | 67 | Neither the name, trademarks, service marks or logos of Apple Inc. may be used 68 | to endorse or promote products derived from the Apple Software without specific 69 | prior written permission from Apple. Except as expressly stated in this notice, 70 | no other rights or licenses, express or implied, are granted by Apple herein, 71 | including but not limited to any patent rights that may be infringed by your 72 | derivative works or by other works in which the Apple Software may be 73 | incorporated. 74 | 75 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO 76 | WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED 77 | WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR 78 | PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN 79 | COMBINATION WITH YOUR PRODUCTS. 80 | 81 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR 82 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 83 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 84 | ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR 85 | DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF 86 | CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF 87 | APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 88 | 89 | Copyright (C) 2009 Apple Inc. All Rights Reserved. 90 | 91 | */ 92 | 93 | 94 | /* 95 | DDG extensions include: 96 | Each reachability object now has a copy of the key used to store it in a 97 | dictionary. This allows each observer to quickly determine if the event is 98 | important to them. 99 | 100 | -currentReachabilityStatus also has a significantly different decision criteria than 101 | Apple's code. 102 | 103 | A multiple convenience test methods have been added. 104 | */ 105 | 106 | #import 107 | #import 108 | #import 109 | 110 | #define USE_DDG_EXTENSIONS 1 // Use DDG's Extensions to test network criteria. 111 | // Since NSAssert and NSCAssert are used in this code, 112 | // I recommend you set NS_BLOCK_ASSERTIONS=1 in the release versions of your projects. 113 | 114 | enum { 115 | 116 | // DDG NetworkStatus Constant Names. 117 | kNotReachable = 0, // Apple's code depends upon 'NotReachable' being the same value as 'NO'. 118 | kReachableViaWWAN, // Switched order from Apple's enum. WWAN is active before WiFi. 119 | kReachableViaWiFi 120 | 121 | }; 122 | typedef uint32_t NetworkStatus; 123 | 124 | enum { 125 | 126 | // Apple NetworkStatus Constant Names. 127 | NotReachable = kNotReachable, 128 | ReachableViaWiFi = kReachableViaWiFi, 129 | ReachableViaWWAN = kReachableViaWWAN 130 | 131 | }; 132 | 133 | 134 | extern NSString *const kInternetConnection; 135 | extern NSString *const kLocalWiFiConnection; 136 | extern NSString *const kReachabilityChangedNotification; 137 | 138 | @interface Reachability: NSObject { 139 | 140 | @private 141 | NSString *key_; 142 | SCNetworkReachabilityRef reachabilityRef; 143 | 144 | } 145 | 146 | @property (copy) NSString *key; // Atomic because network operations are asynchronous. 147 | 148 | // Designated Initializer. 149 | - (Reachability *) initWithReachabilityRef: (SCNetworkReachabilityRef) ref; 150 | 151 | // Use to check the reachability of a particular host name. 152 | + (Reachability *) reachabilityWithHostName: (NSString*) hostName; 153 | 154 | // Use to check the reachability of a particular IP address. 155 | + (Reachability *) reachabilityWithAddress: (const struct sockaddr_in*) hostAddress; 156 | 157 | // Use to check whether the default route is available. 158 | // Should be used to, at minimum, establish network connectivity. 159 | + (Reachability *) reachabilityForInternetConnection; 160 | 161 | // Use to check whether a local wifi connection is available. 162 | + (Reachability *) reachabilityForLocalWiFi; 163 | 164 | //Start listening for reachability notifications on the current run loop. 165 | - (BOOL) startNotifier; 166 | - (void) stopNotifier; 167 | 168 | // Comparison routines to enable choosing actions in a notification. 169 | - (BOOL) isEqual: (Reachability *) r; 170 | 171 | // These are the status tests. 172 | - (NetworkStatus) currentReachabilityStatus; 173 | 174 | // The main direct test of reachability. 175 | - (BOOL) isReachable; 176 | 177 | // WWAN may be available, but not active until a connection has been established. 178 | // WiFi may require a connection for VPN on Demand. 179 | - (BOOL) isConnectionRequired; // Identical DDG variant. 180 | - (BOOL) connectionRequired; // Apple's routine. 181 | 182 | // Dynamic, on demand connection? 183 | - (BOOL) isConnectionOnDemand; 184 | 185 | // Is user intervention required? 186 | - (BOOL) isInterventionRequired; 187 | 188 | // Routines for specific connection testing by your app. 189 | - (BOOL) isReachableViaWWAN; 190 | - (BOOL) isReachableViaWiFi; 191 | 192 | - (SCNetworkReachabilityFlags) reachabilityFlags; 193 | 194 | @end 195 | -------------------------------------------------------------------------------- /LASIImageView/External/Reachability/Reachability.m: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | File: Reachability.m 4 | Abstract: Basic demonstration of how to use the SystemConfiguration Reachablity APIs. 5 | 6 | Version: 2.0.4ddg 7 | */ 8 | 9 | /* 10 | Significant additions made by Andrew W. Donoho, August 11, 2009. 11 | This is a derived work of Apple's Reachability v2.0 class. 12 | 13 | The below license is the new BSD license with the OSI recommended personalizations. 14 | 15 | 16 | Extensions Copyright (C) 2009 Donoho Design Group, LLC. All Rights Reserved. 17 | 18 | Redistribution and use in source and binary forms, with or without 19 | modification, are permitted provided that the following conditions are 20 | met: 21 | 22 | * Redistributions of source code must retain the above copyright notice, 23 | this list of conditions and the following disclaimer. 24 | 25 | * Redistributions in binary form must reproduce the above copyright 26 | notice, this list of conditions and the following disclaimer in the 27 | documentation and/or other materials provided with the distribution. 28 | 29 | * Neither the name of Andrew W. Donoho nor Donoho Design Group, L.L.C. 30 | may be used to endorse or promote products derived from this software 31 | without specific prior written permission. 32 | 33 | THIS SOFTWARE IS PROVIDED BY DONOHO DESIGN GROUP, L.L.C. "AS IS" AND ANY 34 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 35 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 36 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 37 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 38 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 39 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 40 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 41 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 42 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 43 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 44 | 45 | */ 46 | 47 | 48 | /* 49 | 50 | Apple's Original License on Reachability v2.0 51 | 52 | Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. 53 | ("Apple") in consideration of your agreement to the following terms, and your 54 | use, installation, modification or redistribution of this Apple software 55 | constitutes acceptance of these terms. If you do not agree with these terms, 56 | please do not use, install, modify or redistribute this Apple software. 57 | 58 | In consideration of your agreement to abide by the following terms, and subject 59 | to these terms, Apple grants you a personal, non-exclusive license, under 60 | Apple's copyrights in this original Apple software (the "Apple Software"), to 61 | use, reproduce, modify and redistribute the Apple Software, with or without 62 | modifications, in source and/or binary forms; provided that if you redistribute 63 | the Apple Software in its entirety and without modifications, you must retain 64 | this notice and the following text and disclaimers in all such redistributions 65 | of the Apple Software. 66 | 67 | Neither the name, trademarks, service marks or logos of Apple Inc. may be used 68 | to endorse or promote products derived from the Apple Software without specific 69 | prior written permission from Apple. Except as expressly stated in this notice, 70 | no other rights or licenses, express or implied, are granted by Apple herein, 71 | including but not limited to any patent rights that may be infringed by your 72 | derivative works or by other works in which the Apple Software may be 73 | incorporated. 74 | 75 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO 76 | WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED 77 | WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR 78 | PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN 79 | COMBINATION WITH YOUR PRODUCTS. 80 | 81 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR 82 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 83 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 84 | ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR 85 | DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF 86 | CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF 87 | APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 88 | 89 | Copyright (C) 2009 Apple Inc. All Rights Reserved. 90 | 91 | */ 92 | 93 | /* 94 | Each reachability object now has a copy of the key used to store it in a dictionary. 95 | This allows each observer to quickly determine if the event is important to them. 96 | */ 97 | 98 | #import 99 | #import 100 | #import 101 | #import 102 | #import 103 | #import 104 | 105 | #import 106 | 107 | #import "Reachability.h" 108 | 109 | NSString *const kInternetConnection = @"InternetConnection"; 110 | NSString *const kLocalWiFiConnection = @"LocalWiFiConnection"; 111 | NSString *const kReachabilityChangedNotification = @"NetworkReachabilityChangedNotification"; 112 | 113 | #define CLASS_DEBUG 1 // Turn on logReachabilityFlags. Must also have a project wide defined DEBUG. 114 | 115 | #if (defined DEBUG && defined CLASS_DEBUG) 116 | #define logReachabilityFlags(flags) (logReachabilityFlags_(__PRETTY_FUNCTION__, __LINE__, flags)) 117 | 118 | static NSString *reachabilityFlags_(SCNetworkReachabilityFlags flags) { 119 | 120 | #if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 30000) // Apple advises you to use the magic number instead of a symbol. 121 | return [NSString stringWithFormat:@"Reachability Flags: %c%c %c%c%c%c%c%c%c", 122 | (flags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-', 123 | (flags & kSCNetworkReachabilityFlagsReachable) ? 'R' : '-', 124 | 125 | (flags & kSCNetworkReachabilityFlagsConnectionRequired) ? 'c' : '-', 126 | (flags & kSCNetworkReachabilityFlagsTransientConnection) ? 't' : '-', 127 | (flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-', 128 | (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) ? 'C' : '-', 129 | (flags & kSCNetworkReachabilityFlagsConnectionOnDemand) ? 'D' : '-', 130 | (flags & kSCNetworkReachabilityFlagsIsLocalAddress) ? 'l' : '-', 131 | (flags & kSCNetworkReachabilityFlagsIsDirect) ? 'd' : '-']; 132 | #else 133 | // Compile out the v3.0 features for v2.2.1 deployment. 134 | return [NSString stringWithFormat:@"Reachability Flags: %c%c %c%c%c%c%c%c", 135 | (flags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-', 136 | (flags & kSCNetworkReachabilityFlagsReachable) ? 'R' : '-', 137 | 138 | (flags & kSCNetworkReachabilityFlagsConnectionRequired) ? 'c' : '-', 139 | (flags & kSCNetworkReachabilityFlagsTransientConnection) ? 't' : '-', 140 | (flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-', 141 | // v3 kSCNetworkReachabilityFlagsConnectionOnTraffic == v2 kSCNetworkReachabilityFlagsConnectionAutomatic 142 | (flags & kSCNetworkReachabilityFlagsConnectionAutomatic) ? 'C' : '-', 143 | // (flags & kSCNetworkReachabilityFlagsConnectionOnDemand) ? 'D' : '-', // No v2 equivalent. 144 | (flags & kSCNetworkReachabilityFlagsIsLocalAddress) ? 'l' : '-', 145 | (flags & kSCNetworkReachabilityFlagsIsDirect) ? 'd' : '-']; 146 | #endif 147 | 148 | } // reachabilityFlags_() 149 | 150 | static void logReachabilityFlags_(const char *name, int line, SCNetworkReachabilityFlags flags) { 151 | 152 | NSLog(@"%s (%d) \n\t%@", name, line, reachabilityFlags_(flags)); 153 | 154 | } // logReachabilityFlags_() 155 | 156 | #define logNetworkStatus(status) (logNetworkStatus_(__PRETTY_FUNCTION__, __LINE__, status)) 157 | 158 | static void logNetworkStatus_(const char *name, int line, NetworkStatus status) { 159 | 160 | NSString *statusString = nil; 161 | 162 | switch (status) { 163 | case kNotReachable: 164 | statusString = @"Not Reachable"; 165 | break; 166 | case kReachableViaWWAN: 167 | statusString = @"Reachable via WWAN"; 168 | break; 169 | case kReachableViaWiFi: 170 | statusString = @"Reachable via WiFi"; 171 | break; 172 | } 173 | 174 | NSLog(@"%s (%d) \n\tNetwork Status: %@", name, line, statusString); 175 | 176 | } // logNetworkStatus_() 177 | 178 | #else 179 | #define logReachabilityFlags(flags) 180 | #define logNetworkStatus(status) 181 | #endif 182 | 183 | @interface Reachability (private) 184 | 185 | - (NetworkStatus) networkStatusForFlags: (SCNetworkReachabilityFlags) flags; 186 | 187 | @end 188 | 189 | @implementation Reachability 190 | 191 | @synthesize key = key_; 192 | 193 | // Preclude direct access to ivars. 194 | + (BOOL) accessInstanceVariablesDirectly { 195 | 196 | return NO; 197 | 198 | } // accessInstanceVariablesDirectly 199 | 200 | 201 | - (void) dealloc { 202 | 203 | [self stopNotifier]; 204 | if(reachabilityRef) { 205 | 206 | CFRelease(reachabilityRef); reachabilityRef = NULL; 207 | 208 | } 209 | 210 | self.key = nil; 211 | 212 | [super dealloc]; 213 | 214 | } // dealloc 215 | 216 | 217 | - (Reachability *) initWithReachabilityRef: (SCNetworkReachabilityRef) ref 218 | { 219 | self = [super init]; 220 | if (self != nil) 221 | { 222 | reachabilityRef = ref; 223 | } 224 | 225 | return self; 226 | 227 | } // initWithReachabilityRef: 228 | 229 | 230 | #if (defined DEBUG && defined CLASS_DEBUG) 231 | - (NSString *) description { 232 | 233 | NSAssert(reachabilityRef, @"-description called with NULL reachabilityRef"); 234 | 235 | SCNetworkReachabilityFlags flags = 0; 236 | 237 | SCNetworkReachabilityGetFlags(reachabilityRef, &flags); 238 | 239 | return [NSString stringWithFormat: @"%@\n\t%@", self.key, reachabilityFlags_(flags)]; 240 | 241 | } // description 242 | #endif 243 | 244 | 245 | #pragma mark - 246 | #pragma mark Notification Management Methods 247 | 248 | 249 | //Start listening for reachability notifications on the current run loop 250 | static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info) { 251 | 252 | #pragma unused (target, flags) 253 | NSCAssert(info, @"info was NULL in ReachabilityCallback"); 254 | NSCAssert([(NSObject*) info isKindOfClass: [Reachability class]], @"info was the wrong class in ReachabilityCallback"); 255 | 256 | //We're on the main RunLoop, so an NSAutoreleasePool is not necessary, but is added defensively 257 | // in case someone uses the Reachablity object in a different thread. 258 | NSAutoreleasePool* pool = [NSAutoreleasePool new]; 259 | 260 | // Post a notification to notify the client that the network reachability changed. 261 | [[NSNotificationCenter defaultCenter] postNotificationName: kReachabilityChangedNotification 262 | object: (Reachability *) info]; 263 | 264 | [pool release]; 265 | 266 | } // ReachabilityCallback() 267 | 268 | 269 | - (BOOL) startNotifier { 270 | 271 | SCNetworkReachabilityContext context = {0, self, NULL, NULL, NULL}; 272 | 273 | if(SCNetworkReachabilitySetCallback(reachabilityRef, ReachabilityCallback, &context)) { 274 | 275 | if(SCNetworkReachabilityScheduleWithRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) { 276 | 277 | return YES; 278 | 279 | } 280 | 281 | } 282 | 283 | return NO; 284 | 285 | } // startNotifier 286 | 287 | 288 | - (void) stopNotifier { 289 | 290 | if(reachabilityRef) { 291 | 292 | SCNetworkReachabilityUnscheduleFromRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); 293 | 294 | } 295 | 296 | } // stopNotifier 297 | 298 | 299 | - (BOOL) isEqual: (Reachability *) r { 300 | 301 | return [r.key isEqualToString: self.key]; 302 | 303 | } // isEqual: 304 | 305 | 306 | #pragma mark - 307 | #pragma mark Reachability Allocation Methods 308 | 309 | 310 | + (Reachability *) reachabilityWithHostName: (NSString *) hostName { 311 | 312 | SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]); 313 | 314 | if (ref) { 315 | 316 | Reachability *r = [[[self alloc] initWithReachabilityRef: ref] autorelease]; 317 | 318 | r.key = hostName; 319 | 320 | return r; 321 | 322 | } 323 | 324 | return nil; 325 | 326 | } // reachabilityWithHostName 327 | 328 | 329 | + (NSString *) makeAddressKey: (in_addr_t) addr { 330 | // addr is assumed to be in network byte order. 331 | 332 | static const int highShift = 24; 333 | static const int highMidShift = 16; 334 | static const int lowMidShift = 8; 335 | static const in_addr_t mask = 0x000000ff; 336 | 337 | addr = ntohl(addr); 338 | 339 | return [NSString stringWithFormat: @"%d.%d.%d.%d", 340 | (addr >> highShift) & mask, 341 | (addr >> highMidShift) & mask, 342 | (addr >> lowMidShift) & mask, 343 | addr & mask]; 344 | 345 | } // makeAddressKey: 346 | 347 | 348 | + (Reachability *) reachabilityWithAddress: (const struct sockaddr_in *) hostAddress { 349 | 350 | SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr*)hostAddress); 351 | 352 | if (ref) { 353 | 354 | Reachability *r = [[[self alloc] initWithReachabilityRef: ref] autorelease]; 355 | 356 | r.key = [self makeAddressKey: hostAddress->sin_addr.s_addr]; 357 | 358 | return r; 359 | 360 | } 361 | 362 | return nil; 363 | 364 | } // reachabilityWithAddress 365 | 366 | 367 | + (Reachability *) reachabilityForInternetConnection { 368 | 369 | struct sockaddr_in zeroAddress; 370 | bzero(&zeroAddress, sizeof(zeroAddress)); 371 | zeroAddress.sin_len = sizeof(zeroAddress); 372 | zeroAddress.sin_family = AF_INET; 373 | 374 | Reachability *r = [self reachabilityWithAddress: &zeroAddress]; 375 | 376 | r.key = kInternetConnection; 377 | 378 | return r; 379 | 380 | } // reachabilityForInternetConnection 381 | 382 | 383 | + (Reachability *) reachabilityForLocalWiFi { 384 | 385 | struct sockaddr_in localWifiAddress; 386 | bzero(&localWifiAddress, sizeof(localWifiAddress)); 387 | localWifiAddress.sin_len = sizeof(localWifiAddress); 388 | localWifiAddress.sin_family = AF_INET; 389 | // IN_LINKLOCALNETNUM is defined in as 169.254.0.0 390 | localWifiAddress.sin_addr.s_addr = htonl(IN_LINKLOCALNETNUM); 391 | 392 | Reachability *r = [self reachabilityWithAddress: &localWifiAddress]; 393 | 394 | r.key = kLocalWiFiConnection; 395 | 396 | return r; 397 | 398 | } // reachabilityForLocalWiFi 399 | 400 | 401 | #pragma mark - 402 | #pragma mark Network Flag Handling Methods 403 | 404 | 405 | #if USE_DDG_EXTENSIONS 406 | // 407 | // iPhone condition codes as reported by a 3GS running iPhone OS v3.0. 408 | // Airplane Mode turned on: Reachability Flag Status: -- ------- 409 | // WWAN Active: Reachability Flag Status: WR -t----- 410 | // WWAN Connection required: Reachability Flag Status: WR ct----- 411 | // WiFi turned on: Reachability Flag Status: -R ------- Reachable. 412 | // Local WiFi turned on: Reachability Flag Status: -R xxxxxxd Reachable. 413 | // WiFi turned on: Reachability Flag Status: -R ct----- Connection down. (Non-intuitive, empirically determined answer.) 414 | const SCNetworkReachabilityFlags kConnectionDown = kSCNetworkReachabilityFlagsConnectionRequired | 415 | kSCNetworkReachabilityFlagsTransientConnection; 416 | // WiFi turned on: Reachability Flag Status: -R ct-i--- Reachable but it will require user intervention (e.g. enter a WiFi password). 417 | // WiFi turned on: Reachability Flag Status: -R -t----- Reachable via VPN. 418 | // 419 | // In the below method, an 'x' in the flag status means I don't care about its value. 420 | // 421 | // This method differs from Apple's by testing explicitly for empirically observed values. 422 | // This gives me more confidence in it's correct behavior. Apple's code covers more cases 423 | // than mine. My code covers the cases that occur. 424 | // 425 | - (NetworkStatus) networkStatusForFlags: (SCNetworkReachabilityFlags) flags { 426 | 427 | if (flags & kSCNetworkReachabilityFlagsReachable) { 428 | 429 | // Local WiFi -- Test derived from Apple's code: -localWiFiStatusForFlags:. 430 | if (self.key == kLocalWiFiConnection) { 431 | 432 | // Reachability Flag Status: xR xxxxxxd Reachable. 433 | return (flags & kSCNetworkReachabilityFlagsIsDirect) ? kReachableViaWiFi : kNotReachable; 434 | 435 | } 436 | 437 | // Observed WWAN Values: 438 | // WWAN Active: Reachability Flag Status: WR -t----- 439 | // WWAN Connection required: Reachability Flag Status: WR ct----- 440 | // 441 | // Test Value: Reachability Flag Status: WR xxxxxxx 442 | if (flags & kSCNetworkReachabilityFlagsIsWWAN) { return kReachableViaWWAN; } 443 | 444 | // Clear moot bits. 445 | flags &= ~kSCNetworkReachabilityFlagsReachable; 446 | flags &= ~kSCNetworkReachabilityFlagsIsDirect; 447 | flags &= ~kSCNetworkReachabilityFlagsIsLocalAddress; // kInternetConnection is local. 448 | 449 | // Reachability Flag Status: -R ct---xx Connection down. 450 | if (flags == kConnectionDown) { return kNotReachable; } 451 | 452 | // Reachability Flag Status: -R -t---xx Reachable. WiFi + VPN(is up) (Thank you Ling Wang) 453 | if (flags & kSCNetworkReachabilityFlagsTransientConnection) { return kReachableViaWiFi; } 454 | 455 | // Reachability Flag Status: -R -----xx Reachable. 456 | if (flags == 0) { return kReachableViaWiFi; } 457 | 458 | // Apple's code tests for dynamic connection types here. I don't. 459 | // If a connection is required, regardless of whether it is on demand or not, it is a WiFi connection. 460 | // If you care whether a connection needs to be brought up, use -isConnectionRequired. 461 | // If you care about whether user intervention is necessary, use -isInterventionRequired. 462 | // If you care about dynamically establishing the connection, use -isConnectionIsOnDemand. 463 | 464 | // Reachability Flag Status: -R cxxxxxx Reachable. 465 | if (flags & kSCNetworkReachabilityFlagsConnectionRequired) { return kReachableViaWiFi; } 466 | 467 | // Required by the compiler. Should never get here. Default to not connected. 468 | #if (defined DEBUG && defined CLASS_DEBUG) 469 | NSAssert1(NO, @"Uncaught reachability test. Flags: %@", reachabilityFlags_(flags)); 470 | #endif 471 | return kNotReachable; 472 | 473 | } 474 | 475 | // Reachability Flag Status: x- xxxxxxx 476 | return kNotReachable; 477 | 478 | } // networkStatusForFlags: 479 | 480 | 481 | - (NetworkStatus) currentReachabilityStatus { 482 | 483 | NSAssert(reachabilityRef, @"currentReachabilityStatus called with NULL reachabilityRef"); 484 | 485 | SCNetworkReachabilityFlags flags = 0; 486 | NetworkStatus status = kNotReachable; 487 | 488 | if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) { 489 | 490 | // logReachabilityFlags(flags); 491 | 492 | status = [self networkStatusForFlags: flags]; 493 | 494 | return status; 495 | 496 | } 497 | 498 | return kNotReachable; 499 | 500 | } // currentReachabilityStatus 501 | 502 | 503 | - (BOOL) isReachable { 504 | 505 | NSAssert(reachabilityRef, @"isReachable called with NULL reachabilityRef"); 506 | 507 | SCNetworkReachabilityFlags flags = 0; 508 | NetworkStatus status = kNotReachable; 509 | 510 | if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) { 511 | 512 | // logReachabilityFlags(flags); 513 | 514 | status = [self networkStatusForFlags: flags]; 515 | 516 | // logNetworkStatus(status); 517 | 518 | return (kNotReachable != status); 519 | 520 | } 521 | 522 | return NO; 523 | 524 | } // isReachable 525 | 526 | 527 | - (BOOL) isConnectionRequired { 528 | 529 | NSAssert(reachabilityRef, @"isConnectionRequired called with NULL reachabilityRef"); 530 | 531 | SCNetworkReachabilityFlags flags; 532 | 533 | if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) { 534 | 535 | logReachabilityFlags(flags); 536 | 537 | return (flags & kSCNetworkReachabilityFlagsConnectionRequired); 538 | 539 | } 540 | 541 | return NO; 542 | 543 | } // isConnectionRequired 544 | 545 | 546 | - (BOOL) connectionRequired { 547 | 548 | return [self isConnectionRequired]; 549 | 550 | } // connectionRequired 551 | #endif 552 | 553 | 554 | #if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 30000) 555 | static const SCNetworkReachabilityFlags kOnDemandConnection = kSCNetworkReachabilityFlagsConnectionOnTraffic | 556 | kSCNetworkReachabilityFlagsConnectionOnDemand; 557 | #else 558 | static const SCNetworkReachabilityFlags kOnDemandConnection = kSCNetworkReachabilityFlagsConnectionAutomatic; 559 | #endif 560 | 561 | - (BOOL) isConnectionOnDemand { 562 | 563 | NSAssert(reachabilityRef, @"isConnectionIsOnDemand called with NULL reachabilityRef"); 564 | 565 | SCNetworkReachabilityFlags flags; 566 | 567 | if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) { 568 | 569 | logReachabilityFlags(flags); 570 | 571 | return ((flags & kSCNetworkReachabilityFlagsConnectionRequired) && 572 | (flags & kOnDemandConnection)); 573 | 574 | } 575 | 576 | return NO; 577 | 578 | } // isConnectionOnDemand 579 | 580 | 581 | - (BOOL) isInterventionRequired { 582 | 583 | NSAssert(reachabilityRef, @"isInterventionRequired called with NULL reachabilityRef"); 584 | 585 | SCNetworkReachabilityFlags flags; 586 | 587 | if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) { 588 | 589 | logReachabilityFlags(flags); 590 | 591 | return ((flags & kSCNetworkReachabilityFlagsConnectionRequired) && 592 | (flags & kSCNetworkReachabilityFlagsInterventionRequired)); 593 | 594 | } 595 | 596 | return NO; 597 | 598 | } // isInterventionRequired 599 | 600 | 601 | - (BOOL) isReachableViaWWAN { 602 | 603 | NSAssert(reachabilityRef, @"isReachableViaWWAN called with NULL reachabilityRef"); 604 | 605 | SCNetworkReachabilityFlags flags = 0; 606 | NetworkStatus status = kNotReachable; 607 | 608 | if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) { 609 | 610 | logReachabilityFlags(flags); 611 | 612 | status = [self networkStatusForFlags: flags]; 613 | 614 | return (kReachableViaWWAN == status); 615 | 616 | } 617 | 618 | return NO; 619 | 620 | } // isReachableViaWWAN 621 | 622 | 623 | - (BOOL) isReachableViaWiFi { 624 | 625 | NSAssert(reachabilityRef, @"isReachableViaWiFi called with NULL reachabilityRef"); 626 | 627 | SCNetworkReachabilityFlags flags = 0; 628 | NetworkStatus status = kNotReachable; 629 | 630 | if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) { 631 | 632 | logReachabilityFlags(flags); 633 | 634 | status = [self networkStatusForFlags: flags]; 635 | 636 | return (kReachableViaWiFi == status); 637 | 638 | } 639 | 640 | return NO; 641 | 642 | } // isReachableViaWiFi 643 | 644 | 645 | - (SCNetworkReachabilityFlags) reachabilityFlags { 646 | 647 | NSAssert(reachabilityRef, @"reachabilityFlags called with NULL reachabilityRef"); 648 | 649 | SCNetworkReachabilityFlags flags = 0; 650 | 651 | if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) { 652 | 653 | logReachabilityFlags(flags); 654 | 655 | return flags; 656 | 657 | } 658 | 659 | return 0; 660 | 661 | } // reachabilityFlags 662 | 663 | 664 | #pragma mark - 665 | #pragma mark Apple's Network Flag Handling Methods 666 | 667 | 668 | #if !USE_DDG_EXTENSIONS 669 | /* 670 | * 671 | * Apple's Network Status testing code. 672 | * The only changes that have been made are to use the new logReachabilityFlags macro and 673 | * test for local WiFi via the key instead of Apple's boolean. Also, Apple's code was for v3.0 only 674 | * iPhone OS. v2.2.1 and earlier conditional compiling is turned on. Hence, to mirror Apple's behavior, 675 | * set your Base SDK to v3.0 or higher. 676 | * 677 | */ 678 | 679 | - (NetworkStatus) localWiFiStatusForFlags: (SCNetworkReachabilityFlags) flags 680 | { 681 | logReachabilityFlags(flags); 682 | 683 | BOOL retVal = NotReachable; 684 | if((flags & kSCNetworkReachabilityFlagsReachable) && (flags & kSCNetworkReachabilityFlagsIsDirect)) 685 | { 686 | retVal = ReachableViaWiFi; 687 | } 688 | return retVal; 689 | } 690 | 691 | 692 | - (NetworkStatus) networkStatusForFlags: (SCNetworkReachabilityFlags) flags 693 | { 694 | logReachabilityFlags(flags); 695 | if (!(flags & kSCNetworkReachabilityFlagsReachable)) 696 | { 697 | // if target host is not reachable 698 | return NotReachable; 699 | } 700 | 701 | BOOL retVal = NotReachable; 702 | 703 | if (!(flags & kSCNetworkReachabilityFlagsConnectionRequired)) 704 | { 705 | // if target host is reachable and no connection is required 706 | // then we'll assume (for now) that your on Wi-Fi 707 | retVal = ReachableViaWiFi; 708 | } 709 | 710 | #if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 30000) // Apple advises you to use the magic number instead of a symbol. 711 | if ((flags & kSCNetworkReachabilityFlagsConnectionOnDemand) || 712 | (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic)) 713 | #else 714 | if (flags & kSCNetworkReachabilityFlagsConnectionAutomatic) 715 | #endif 716 | { 717 | // ... and the connection is on-demand (or on-traffic) if the 718 | // calling application is using the CFSocketStream or higher APIs 719 | 720 | if (!(flags & kSCNetworkReachabilityFlagsInterventionRequired)) 721 | { 722 | // ... and no [user] intervention is needed 723 | retVal = ReachableViaWiFi; 724 | } 725 | } 726 | 727 | if (flags & kSCNetworkReachabilityFlagsIsWWAN) 728 | { 729 | // ... but WWAN connections are OK if the calling application 730 | // is using the CFNetwork (CFSocketStream?) APIs. 731 | retVal = ReachableViaWWAN; 732 | } 733 | return retVal; 734 | } 735 | 736 | 737 | - (NetworkStatus) currentReachabilityStatus 738 | { 739 | NSAssert(reachabilityRef, @"currentReachabilityStatus called with NULL reachabilityRef"); 740 | 741 | NetworkStatus retVal = NotReachable; 742 | SCNetworkReachabilityFlags flags; 743 | if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) 744 | { 745 | if(self.key == kLocalWiFiConnection) 746 | { 747 | retVal = [self localWiFiStatusForFlags: flags]; 748 | } 749 | else 750 | { 751 | retVal = [self networkStatusForFlags: flags]; 752 | } 753 | } 754 | return retVal; 755 | } 756 | 757 | 758 | - (BOOL) isReachable { 759 | 760 | NSAssert(reachabilityRef, @"isReachable called with NULL reachabilityRef"); 761 | 762 | SCNetworkReachabilityFlags flags = 0; 763 | NetworkStatus status = kNotReachable; 764 | 765 | if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) { 766 | 767 | logReachabilityFlags(flags); 768 | 769 | if(self.key == kLocalWiFiConnection) { 770 | 771 | status = [self localWiFiStatusForFlags: flags]; 772 | 773 | } else { 774 | 775 | status = [self networkStatusForFlags: flags]; 776 | 777 | } 778 | 779 | return (kNotReachable != status); 780 | 781 | } 782 | 783 | return NO; 784 | 785 | } // isReachable 786 | 787 | 788 | - (BOOL) isConnectionRequired { 789 | 790 | return [self connectionRequired]; 791 | 792 | } // isConnectionRequired 793 | 794 | 795 | - (BOOL) connectionRequired { 796 | 797 | NSAssert(reachabilityRef, @"connectionRequired called with NULL reachabilityRef"); 798 | 799 | SCNetworkReachabilityFlags flags; 800 | 801 | if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) { 802 | 803 | logReachabilityFlags(flags); 804 | 805 | return (flags & kSCNetworkReachabilityFlagsConnectionRequired); 806 | 807 | } 808 | 809 | return NO; 810 | 811 | } // connectionRequired 812 | #endif 813 | 814 | @end 815 | -------------------------------------------------------------------------------- /LASIImageView/Supporting Files/LASIImageView-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | com.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /LASIImageView/Supporting Files/LASIImageView-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'LASIImageView' target in the 'LASIImageView' project 3 | // 4 | 5 | #import 6 | 7 | #ifndef __IPHONE_4_0 8 | #warning "This project uses features only available in iOS SDK 4.0 and later." 9 | #endif 10 | 11 | #ifdef __OBJC__ 12 | #import 13 | #import 14 | #endif 15 | -------------------------------------------------------------------------------- /LASIImageView/Supporting Files/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // LASIImageView 4 | // 5 | // Created by Luka Gabric on 9/2/13. 6 | // Copyright (c) 2013 Luka Gabric. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "AppDelegate.h" 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | LASIImageView 2 | ============= 3 | 4 | iOS UIImageView subclass - download image with different progress indicators 5 | 6 | Screenshots 7 | ----------- 8 | [![](http://lukagabric.com/wp-content/uploads/2013/09/LASIImageViewSample.png)](http://lukagabric.com/wp-content/uploads/2013/09/LASIImageViewSample.png) 9 | 10 | How to use 11 | ---------- 12 | 13 | Just add LASIImageView class files to the project and set the imageUrl property to download and display the image. 14 | 15 | Progress indicator types 16 | ------------------------ 17 | 18 | Three types of progress indicators are available (as in the screenshot above): 19 | 20 | * LProgressTypeAnnular 21 | * LProgressTypeCircle 22 | * LProgressTypePie 23 | 24 | Appearance 25 | ---------- 26 | 27 | It is possible to set shared appearance. Setting appearance for particular LASIImageView instance will override global appearance. 28 | 29 | [[LASIImageView sharedProgressAppearance] setSchemeColor:[UIColor whiteColor]]; 30 | [[LASIImageView sharedASIImageViewAppearance] setDownloadFailedImageName:@"downloadFailed.png"]; 31 | 32 | Request settings 33 | ---------------- 34 | 35 | @property (assign, nonatomic) ASICachePolicy cachePolicy; 36 | @property (assign, nonatomic) ASICacheStoragePolicy cacheStoragePolicy; 37 | @property (weak, nonatomic) id cacheDelegate; 38 | @property (assign, nonatomic) NSUInteger secondsToCache; 39 | @property (assign, nonatomic) NSUInteger timeOutSeconds; 40 | 41 | Blocks 42 | ------ 43 | 44 | On request finished - success or fail blocks are called (LASIImageViewDownloadFinishedBlock or LASIImageViewDownloadFailedBlock) 45 | --------------------------------------------------------------------------------