├── LICENSE ├── MCDownloadManager.podspec ├── MCDownloadManager.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ ├── M.C.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ │ ├── machao.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ │ └── test.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ ├── M.C.xcuserdatad │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ │ ├── MCDownloadManager.xcscheme │ │ └── xcschememanagement.plist │ ├── machao.xcuserdatad │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ │ ├── MCDownloadManager.xcscheme │ │ └── xcschememanagement.plist │ └── test.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ ├── MCDownloadManager.xcscheme │ └── xcschememanagement.plist ├── MCDownloadManager ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Info.plist ├── MCDownloadManager.entitlements ├── MCDownloadManager │ ├── MCDefine.h │ ├── MCDownloadManager.h │ └── MCDownloadManager.m ├── Networking │ ├── MCURLRequest.h │ ├── MCURLRequest.m │ ├── MCURLRequestCenter.h │ ├── MCURLRequestCenter.m │ ├── MCURLResponse.h │ ├── MCURLResponse.m │ ├── MCURLSessionConfiguration.h │ ├── MCURLSessionConfiguration.m │ ├── MCWiFiManager.h │ └── MCWiFiManager.m ├── QKYDelayButton.h ├── QKYDelayButton.m ├── TableViewCell.h ├── TableViewCell.m ├── TestViewController.h ├── TestViewController.m ├── ViewController.h ├── ViewController.m └── main.m └── README.md /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014-2016 Alamofire Software Foundation (http://alamofire.org/) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /MCDownloadManager.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod spec lint MCDownloadManager.podspec' to ensure this is a 3 | # valid spec and to remove all comments including this before submitting the spec. 4 | # 5 | # To learn more about Podspec attributes see http://docs.cocoapods.org/specification.html 6 | # To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/ 7 | # 8 | 9 | Pod::Spec.new do |s| 10 | 11 | # ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 12 | # 13 | # These will help people to find your library, and whilst it 14 | # can feel like a chore to fill in it's definitely to your advantage. The 15 | # summary should be tweet-length, and the description more in depth. 16 | # 17 | 18 | s.name = "MCDownloadManager" 19 | s.version = "1.0.3" 20 | s.summary = "A simple and convenient multi task download manager" 21 | 22 | # This description is used to generate tags and improve search results. 23 | # * Think: What does it do? Why did you write it? What is the focus? 24 | # * Try to keep it short, snappy and to the point. 25 | # * Write the description between the DESC delimiters below. 26 | # * Finally, don't worry about the indent, CocoaPods strips it! 27 | # s.description = <<-DESC 28 | # A simple and convenient multi task download manager 29 | # DESC 30 | 31 | s.homepage = "https://github.com/agelessman/MCDownloadManager" 32 | # s.screenshots = "www.example.com/screenshots_1.gif", "www.example.com/screenshots_2.gif" 33 | 34 | 35 | # ――― Spec License ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 36 | # 37 | # Licensing your code is important. See http://choosealicense.com for more info. 38 | # CocoaPods will detect a license file if there is a named LICENSE* 39 | # Popular ones are 'MIT', 'BSD' and 'Apache License, Version 2.0'. 40 | # 41 | 42 | s.license = "MIT" 43 | # s.license = { :type => "MIT", :file => "FILE_LICENSE" } 44 | 45 | 46 | # ――― Author Metadata ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 47 | # 48 | # Specify the authors of the library, with email addresses. Email addresses 49 | # of the authors are extracted from the SCM log. E.g. $ git log. CocoaPods also 50 | # accepts just a name if you'd rather not provide an email address. 51 | # 52 | # Specify a social_media_url where others can refer to, for example a twitter 53 | # profile URL. 54 | # 55 | 56 | s.author = { "machao" => "714080794@qq.com" } 57 | # Or just: s.author = "machao" 58 | # s.authors = { "machao" => "714080794@qq.com" } 59 | # s.social_media_url = "http://twitter.com/machao" 60 | 61 | # ――― Platform Specifics ――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 62 | # 63 | # If this Pod runs only on iOS or OS X, then specify the platform and 64 | # the deployment target. You can optionally include the target after the platform. 65 | # 66 | 67 | # s.platform = :ios 68 | s.platform = :ios, "7.0" 69 | 70 | # When using multiple platforms 71 | # s.ios.deployment_target = "5.0" 72 | # s.osx.deployment_target = "10.7" 73 | # s.watchos.deployment_target = "2.0" 74 | # s.tvos.deployment_target = "9.0" 75 | 76 | 77 | # ――― Source Location ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 78 | # 79 | # Specify the location from where the source should be retrieved. 80 | # Supports git, hg, bzr, svn and HTTP. 81 | # 82 | 83 | s.source = { :git => "https://github.com/agelessman/MCDownloadManager.git", :tag => "#{s.version}" } 84 | 85 | 86 | # ――― Source Code ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 87 | # 88 | # CocoaPods is smart about how it includes source code. For source files 89 | # giving a folder will include any swift, h, m, mm, c & cpp files. 90 | # For header files it will include any header in the folder. 91 | # Not including the public_header_files will make all headers public. 92 | # 93 | 94 | s.source_files = "MCDownloadManager/MCDownloadManager/*.{h,m}" 95 | s.exclude_files = "Classes/Exclude" 96 | 97 | # s.public_header_files = "Classes/**/*.h" 98 | 99 | 100 | # ――― Resources ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 101 | # 102 | # A list of resources included with the Pod. These are copied into the 103 | # target bundle with a build phase script. Anything else will be cleaned. 104 | # You can preserve files from being cleaned, please don't preserve 105 | # non-essential files like tests, examples and documentation. 106 | # 107 | 108 | # s.resource = "icon.png" 109 | # s.resources = "Resources/*.png" 110 | 111 | # s.preserve_paths = "FilesToSave", "MoreFilesToSave" 112 | 113 | 114 | # ――― Project Linking ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 115 | # 116 | # Link your library with frameworks, or libraries. Libraries do not include 117 | # the lib prefix of their name. 118 | # 119 | 120 | s.framework = "Foundation", "UIKit" 121 | # s.frameworks = "Foundation", "UIKit" 122 | 123 | # s.library = "iconv" 124 | # s.libraries = "iconv", "xml2" 125 | 126 | 127 | # ――― Project Settings ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 128 | # 129 | # If your library depends on compiler flags you can set them in the xcconfig hash 130 | # where they will only apply to your library. If you depend on other Podspecs 131 | # you can include multiple dependencies to ensure it works. 132 | 133 | # s.requires_arc = true 134 | 135 | # s.xcconfig = { "HEADER_SEARCH_PATHS" => "$(SDKROOT)/usr/include/libxml2" } 136 | # s.dependency "JSONKit", "~> 1.4" 137 | 138 | end 139 | -------------------------------------------------------------------------------- /MCDownloadManager.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 9B0E8D281D825CDC00452963 /* QKYDelayButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B0E8D271D825CDC00452963 /* QKYDelayButton.m */; }; 11 | 9B24E5C41D7D44D300AA2ECC /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B24E5C31D7D44D300AA2ECC /* main.m */; }; 12 | 9B24E5C71D7D44D300AA2ECC /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B24E5C61D7D44D300AA2ECC /* AppDelegate.m */; }; 13 | 9B24E5CA1D7D44D300AA2ECC /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B24E5C91D7D44D300AA2ECC /* ViewController.m */; }; 14 | 9B24E5CD1D7D44D300AA2ECC /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9B24E5CB1D7D44D300AA2ECC /* Main.storyboard */; }; 15 | 9B24E5CF1D7D44D300AA2ECC /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9B24E5CE1D7D44D300AA2ECC /* Assets.xcassets */; }; 16 | 9B24E5D21D7D44D300AA2ECC /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9B24E5D01D7D44D300AA2ECC /* LaunchScreen.storyboard */; }; 17 | 9B24E5DC1D7D453B00AA2ECC /* MCDownloadManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B24E5DB1D7D453B00AA2ECC /* MCDownloadManager.m */; }; 18 | 9B48434E1D7EC00E00A2CBBE /* TableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B48434D1D7EC00E00A2CBBE /* TableViewCell.m */; }; 19 | E78B54CB1E66C5C100C28612 /* TestViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E78B54CA1E66C5C100C28612 /* TestViewController.m */; }; 20 | E78B54D51E69214900C28612 /* MCURLRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = E78B54CE1E69214900C28612 /* MCURLRequest.m */; }; 21 | E78B54D61E69214900C28612 /* MCURLRequestCenter.m in Sources */ = {isa = PBXBuildFile; fileRef = E78B54D01E69214900C28612 /* MCURLRequestCenter.m */; }; 22 | E78B54D71E69214900C28612 /* MCURLResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = E78B54D21E69214900C28612 /* MCURLResponse.m */; }; 23 | E78B54D81E69214900C28612 /* MCURLSessionConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = E78B54D41E69214900C28612 /* MCURLSessionConfiguration.m */; }; 24 | E78B54DB1E693B3B00C28612 /* MCWiFiManager.m in Sources */ = {isa = PBXBuildFile; fileRef = E78B54DA1E693B3B00C28612 /* MCWiFiManager.m */; }; 25 | /* End PBXBuildFile section */ 26 | 27 | /* Begin PBXFileReference section */ 28 | 521970A81DF69503009C7D65 /* MCDefine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCDefine.h; sourceTree = ""; }; 29 | 9B0E8D261D825CDC00452963 /* QKYDelayButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QKYDelayButton.h; sourceTree = ""; }; 30 | 9B0E8D271D825CDC00452963 /* QKYDelayButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QKYDelayButton.m; sourceTree = ""; }; 31 | 9B24E5BF1D7D44D300AA2ECC /* MCDownloadManager.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MCDownloadManager.app; sourceTree = BUILT_PRODUCTS_DIR; }; 32 | 9B24E5C31D7D44D300AA2ECC /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 33 | 9B24E5C51D7D44D300AA2ECC /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 34 | 9B24E5C61D7D44D300AA2ECC /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 35 | 9B24E5C81D7D44D300AA2ECC /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 36 | 9B24E5C91D7D44D300AA2ECC /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 37 | 9B24E5CC1D7D44D300AA2ECC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 38 | 9B24E5CE1D7D44D300AA2ECC /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 39 | 9B24E5D11D7D44D300AA2ECC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 40 | 9B24E5D31D7D44D300AA2ECC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 41 | 9B24E5DA1D7D453B00AA2ECC /* MCDownloadManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCDownloadManager.h; sourceTree = ""; }; 42 | 9B24E5DB1D7D453B00AA2ECC /* MCDownloadManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MCDownloadManager.m; sourceTree = ""; }; 43 | 9B48434C1D7EC00E00A2CBBE /* TableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TableViewCell.h; sourceTree = ""; }; 44 | 9B48434D1D7EC00E00A2CBBE /* TableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TableViewCell.m; sourceTree = ""; }; 45 | E78B54C91E66C5C100C28612 /* TestViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestViewController.h; sourceTree = ""; }; 46 | E78B54CA1E66C5C100C28612 /* TestViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TestViewController.m; sourceTree = ""; }; 47 | E78B54CD1E69214900C28612 /* MCURLRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCURLRequest.h; sourceTree = ""; }; 48 | E78B54CE1E69214900C28612 /* MCURLRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MCURLRequest.m; sourceTree = ""; }; 49 | E78B54CF1E69214900C28612 /* MCURLRequestCenter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCURLRequestCenter.h; sourceTree = ""; }; 50 | E78B54D01E69214900C28612 /* MCURLRequestCenter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MCURLRequestCenter.m; sourceTree = ""; }; 51 | E78B54D11E69214900C28612 /* MCURLResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCURLResponse.h; sourceTree = ""; }; 52 | E78B54D21E69214900C28612 /* MCURLResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MCURLResponse.m; sourceTree = ""; }; 53 | E78B54D31E69214900C28612 /* MCURLSessionConfiguration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCURLSessionConfiguration.h; sourceTree = ""; }; 54 | E78B54D41E69214900C28612 /* MCURLSessionConfiguration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MCURLSessionConfiguration.m; sourceTree = ""; }; 55 | E78B54D91E693B3B00C28612 /* MCWiFiManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCWiFiManager.h; sourceTree = ""; }; 56 | E78B54DA1E693B3B00C28612 /* MCWiFiManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MCWiFiManager.m; sourceTree = ""; }; 57 | E797F6CB1E78ECD300F5631B /* MCDownloadManager.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = MCDownloadManager.entitlements; sourceTree = ""; }; 58 | /* End PBXFileReference section */ 59 | 60 | /* Begin PBXFrameworksBuildPhase section */ 61 | 9B24E5BC1D7D44D300AA2ECC /* Frameworks */ = { 62 | isa = PBXFrameworksBuildPhase; 63 | buildActionMask = 2147483647; 64 | files = ( 65 | ); 66 | runOnlyForDeploymentPostprocessing = 0; 67 | }; 68 | /* End PBXFrameworksBuildPhase section */ 69 | 70 | /* Begin PBXGroup section */ 71 | 9B24E5B61D7D44D300AA2ECC = { 72 | isa = PBXGroup; 73 | children = ( 74 | 9B24E5C11D7D44D300AA2ECC /* MCDownloadManager */, 75 | 9B24E5C01D7D44D300AA2ECC /* Products */, 76 | E797F6C81E78ECD300F5631B /* Frameworks */, 77 | ); 78 | sourceTree = ""; 79 | }; 80 | 9B24E5C01D7D44D300AA2ECC /* Products */ = { 81 | isa = PBXGroup; 82 | children = ( 83 | 9B24E5BF1D7D44D300AA2ECC /* MCDownloadManager.app */, 84 | ); 85 | name = Products; 86 | sourceTree = ""; 87 | }; 88 | 9B24E5C11D7D44D300AA2ECC /* MCDownloadManager */ = { 89 | isa = PBXGroup; 90 | children = ( 91 | E797F6CB1E78ECD300F5631B /* MCDownloadManager.entitlements */, 92 | E78B54CC1E69214900C28612 /* Networking */, 93 | 9B24E5D91D7D451200AA2ECC /* MCDownloadManager */, 94 | 9B24E5C51D7D44D300AA2ECC /* AppDelegate.h */, 95 | 9B24E5C61D7D44D300AA2ECC /* AppDelegate.m */, 96 | 9B24E5C81D7D44D300AA2ECC /* ViewController.h */, 97 | 9B24E5C91D7D44D300AA2ECC /* ViewController.m */, 98 | E78B54C91E66C5C100C28612 /* TestViewController.h */, 99 | E78B54CA1E66C5C100C28612 /* TestViewController.m */, 100 | 9B48434C1D7EC00E00A2CBBE /* TableViewCell.h */, 101 | 9B48434D1D7EC00E00A2CBBE /* TableViewCell.m */, 102 | 9B0E8D261D825CDC00452963 /* QKYDelayButton.h */, 103 | 9B0E8D271D825CDC00452963 /* QKYDelayButton.m */, 104 | 9B24E5CB1D7D44D300AA2ECC /* Main.storyboard */, 105 | 9B24E5CE1D7D44D300AA2ECC /* Assets.xcassets */, 106 | 9B24E5D01D7D44D300AA2ECC /* LaunchScreen.storyboard */, 107 | 9B24E5D31D7D44D300AA2ECC /* Info.plist */, 108 | 9B24E5C21D7D44D300AA2ECC /* Supporting Files */, 109 | ); 110 | path = MCDownloadManager; 111 | sourceTree = ""; 112 | }; 113 | 9B24E5C21D7D44D300AA2ECC /* Supporting Files */ = { 114 | isa = PBXGroup; 115 | children = ( 116 | 9B24E5C31D7D44D300AA2ECC /* main.m */, 117 | ); 118 | name = "Supporting Files"; 119 | sourceTree = ""; 120 | }; 121 | 9B24E5D91D7D451200AA2ECC /* MCDownloadManager */ = { 122 | isa = PBXGroup; 123 | children = ( 124 | 521970A81DF69503009C7D65 /* MCDefine.h */, 125 | 9B24E5DA1D7D453B00AA2ECC /* MCDownloadManager.h */, 126 | 9B24E5DB1D7D453B00AA2ECC /* MCDownloadManager.m */, 127 | ); 128 | path = MCDownloadManager; 129 | sourceTree = ""; 130 | }; 131 | E78B54CC1E69214900C28612 /* Networking */ = { 132 | isa = PBXGroup; 133 | children = ( 134 | E78B54D91E693B3B00C28612 /* MCWiFiManager.h */, 135 | E78B54DA1E693B3B00C28612 /* MCWiFiManager.m */, 136 | E78B54CD1E69214900C28612 /* MCURLRequest.h */, 137 | E78B54CE1E69214900C28612 /* MCURLRequest.m */, 138 | E78B54CF1E69214900C28612 /* MCURLRequestCenter.h */, 139 | E78B54D01E69214900C28612 /* MCURLRequestCenter.m */, 140 | E78B54D11E69214900C28612 /* MCURLResponse.h */, 141 | E78B54D21E69214900C28612 /* MCURLResponse.m */, 142 | E78B54D31E69214900C28612 /* MCURLSessionConfiguration.h */, 143 | E78B54D41E69214900C28612 /* MCURLSessionConfiguration.m */, 144 | ); 145 | path = Networking; 146 | sourceTree = ""; 147 | }; 148 | E797F6C81E78ECD300F5631B /* Frameworks */ = { 149 | isa = PBXGroup; 150 | children = ( 151 | ); 152 | name = Frameworks; 153 | sourceTree = ""; 154 | }; 155 | /* End PBXGroup section */ 156 | 157 | /* Begin PBXNativeTarget section */ 158 | 9B24E5BE1D7D44D300AA2ECC /* MCDownloadManager */ = { 159 | isa = PBXNativeTarget; 160 | buildConfigurationList = 9B24E5D61D7D44D300AA2ECC /* Build configuration list for PBXNativeTarget "MCDownloadManager" */; 161 | buildPhases = ( 162 | 9B24E5BB1D7D44D300AA2ECC /* Sources */, 163 | 9B24E5BC1D7D44D300AA2ECC /* Frameworks */, 164 | 9B24E5BD1D7D44D300AA2ECC /* Resources */, 165 | ); 166 | buildRules = ( 167 | ); 168 | dependencies = ( 169 | ); 170 | name = MCDownloadManager; 171 | productName = MCDownloadManager; 172 | productReference = 9B24E5BF1D7D44D300AA2ECC /* MCDownloadManager.app */; 173 | productType = "com.apple.product-type.application"; 174 | }; 175 | /* End PBXNativeTarget section */ 176 | 177 | /* Begin PBXProject section */ 178 | 9B24E5B71D7D44D300AA2ECC /* Project object */ = { 179 | isa = PBXProject; 180 | attributes = { 181 | LastUpgradeCheck = 0800; 182 | ORGANIZATIONNAME = qikeyun; 183 | TargetAttributes = { 184 | 9B24E5BE1D7D44D300AA2ECC = { 185 | CreatedOnToolsVersion = 7.3; 186 | DevelopmentTeam = XC34BSW465; 187 | SystemCapabilities = { 188 | com.apple.BackgroundModes = { 189 | enabled = 1; 190 | }; 191 | com.apple.InterAppAudio = { 192 | enabled = 0; 193 | }; 194 | }; 195 | }; 196 | }; 197 | }; 198 | buildConfigurationList = 9B24E5BA1D7D44D300AA2ECC /* Build configuration list for PBXProject "MCDownloadManager" */; 199 | compatibilityVersion = "Xcode 3.2"; 200 | developmentRegion = English; 201 | hasScannedForEncodings = 0; 202 | knownRegions = ( 203 | en, 204 | Base, 205 | ); 206 | mainGroup = 9B24E5B61D7D44D300AA2ECC; 207 | productRefGroup = 9B24E5C01D7D44D300AA2ECC /* Products */; 208 | projectDirPath = ""; 209 | projectRoot = ""; 210 | targets = ( 211 | 9B24E5BE1D7D44D300AA2ECC /* MCDownloadManager */, 212 | ); 213 | }; 214 | /* End PBXProject section */ 215 | 216 | /* Begin PBXResourcesBuildPhase section */ 217 | 9B24E5BD1D7D44D300AA2ECC /* Resources */ = { 218 | isa = PBXResourcesBuildPhase; 219 | buildActionMask = 2147483647; 220 | files = ( 221 | 9B24E5D21D7D44D300AA2ECC /* LaunchScreen.storyboard in Resources */, 222 | 9B24E5CF1D7D44D300AA2ECC /* Assets.xcassets in Resources */, 223 | 9B24E5CD1D7D44D300AA2ECC /* Main.storyboard in Resources */, 224 | ); 225 | runOnlyForDeploymentPostprocessing = 0; 226 | }; 227 | /* End PBXResourcesBuildPhase section */ 228 | 229 | /* Begin PBXSourcesBuildPhase section */ 230 | 9B24E5BB1D7D44D300AA2ECC /* Sources */ = { 231 | isa = PBXSourcesBuildPhase; 232 | buildActionMask = 2147483647; 233 | files = ( 234 | E78B54DB1E693B3B00C28612 /* MCWiFiManager.m in Sources */, 235 | E78B54D81E69214900C28612 /* MCURLSessionConfiguration.m in Sources */, 236 | E78B54CB1E66C5C100C28612 /* TestViewController.m in Sources */, 237 | E78B54D71E69214900C28612 /* MCURLResponse.m in Sources */, 238 | 9B24E5CA1D7D44D300AA2ECC /* ViewController.m in Sources */, 239 | 9B48434E1D7EC00E00A2CBBE /* TableViewCell.m in Sources */, 240 | 9B24E5DC1D7D453B00AA2ECC /* MCDownloadManager.m in Sources */, 241 | E78B54D51E69214900C28612 /* MCURLRequest.m in Sources */, 242 | 9B24E5C71D7D44D300AA2ECC /* AppDelegate.m in Sources */, 243 | E78B54D61E69214900C28612 /* MCURLRequestCenter.m in Sources */, 244 | 9B0E8D281D825CDC00452963 /* QKYDelayButton.m in Sources */, 245 | 9B24E5C41D7D44D300AA2ECC /* main.m in Sources */, 246 | ); 247 | runOnlyForDeploymentPostprocessing = 0; 248 | }; 249 | /* End PBXSourcesBuildPhase section */ 250 | 251 | /* Begin PBXVariantGroup section */ 252 | 9B24E5CB1D7D44D300AA2ECC /* Main.storyboard */ = { 253 | isa = PBXVariantGroup; 254 | children = ( 255 | 9B24E5CC1D7D44D300AA2ECC /* Base */, 256 | ); 257 | name = Main.storyboard; 258 | sourceTree = ""; 259 | }; 260 | 9B24E5D01D7D44D300AA2ECC /* LaunchScreen.storyboard */ = { 261 | isa = PBXVariantGroup; 262 | children = ( 263 | 9B24E5D11D7D44D300AA2ECC /* Base */, 264 | ); 265 | name = LaunchScreen.storyboard; 266 | sourceTree = ""; 267 | }; 268 | /* End PBXVariantGroup section */ 269 | 270 | /* Begin XCBuildConfiguration section */ 271 | 9B24E5D41D7D44D300AA2ECC /* Debug */ = { 272 | isa = XCBuildConfiguration; 273 | buildSettings = { 274 | ALWAYS_SEARCH_USER_PATHS = NO; 275 | CLANG_ANALYZER_NONNULL = YES; 276 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 277 | CLANG_CXX_LIBRARY = "libc++"; 278 | CLANG_ENABLE_MODULES = YES; 279 | CLANG_ENABLE_OBJC_ARC = YES; 280 | CLANG_WARN_BOOL_CONVERSION = YES; 281 | CLANG_WARN_CONSTANT_CONVERSION = YES; 282 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 283 | CLANG_WARN_EMPTY_BODY = YES; 284 | CLANG_WARN_ENUM_CONVERSION = YES; 285 | CLANG_WARN_INFINITE_RECURSION = YES; 286 | CLANG_WARN_INT_CONVERSION = YES; 287 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 288 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 289 | CLANG_WARN_UNREACHABLE_CODE = YES; 290 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 291 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 292 | COPY_PHASE_STRIP = NO; 293 | DEBUG_INFORMATION_FORMAT = dwarf; 294 | ENABLE_STRICT_OBJC_MSGSEND = YES; 295 | ENABLE_TESTABILITY = YES; 296 | GCC_C_LANGUAGE_STANDARD = gnu99; 297 | GCC_DYNAMIC_NO_PIC = NO; 298 | GCC_NO_COMMON_BLOCKS = YES; 299 | GCC_OPTIMIZATION_LEVEL = 0; 300 | GCC_PREPROCESSOR_DEFINITIONS = ( 301 | "DEBUG=1", 302 | "$(inherited)", 303 | ); 304 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 305 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 306 | GCC_WARN_UNDECLARED_SELECTOR = YES; 307 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 308 | GCC_WARN_UNUSED_FUNCTION = YES; 309 | GCC_WARN_UNUSED_VARIABLE = YES; 310 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 311 | MTL_ENABLE_DEBUG_INFO = YES; 312 | ONLY_ACTIVE_ARCH = YES; 313 | SDKROOT = iphoneos; 314 | }; 315 | name = Debug; 316 | }; 317 | 9B24E5D51D7D44D300AA2ECC /* Release */ = { 318 | isa = XCBuildConfiguration; 319 | buildSettings = { 320 | ALWAYS_SEARCH_USER_PATHS = NO; 321 | CLANG_ANALYZER_NONNULL = YES; 322 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 323 | CLANG_CXX_LIBRARY = "libc++"; 324 | CLANG_ENABLE_MODULES = YES; 325 | CLANG_ENABLE_OBJC_ARC = YES; 326 | CLANG_WARN_BOOL_CONVERSION = YES; 327 | CLANG_WARN_CONSTANT_CONVERSION = YES; 328 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 329 | CLANG_WARN_EMPTY_BODY = YES; 330 | CLANG_WARN_ENUM_CONVERSION = YES; 331 | CLANG_WARN_INFINITE_RECURSION = YES; 332 | CLANG_WARN_INT_CONVERSION = YES; 333 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 334 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 335 | CLANG_WARN_UNREACHABLE_CODE = YES; 336 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 337 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 338 | COPY_PHASE_STRIP = NO; 339 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 340 | ENABLE_NS_ASSERTIONS = NO; 341 | ENABLE_STRICT_OBJC_MSGSEND = YES; 342 | GCC_C_LANGUAGE_STANDARD = gnu99; 343 | GCC_NO_COMMON_BLOCKS = YES; 344 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 345 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 346 | GCC_WARN_UNDECLARED_SELECTOR = YES; 347 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 348 | GCC_WARN_UNUSED_FUNCTION = YES; 349 | GCC_WARN_UNUSED_VARIABLE = YES; 350 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 351 | MTL_ENABLE_DEBUG_INFO = NO; 352 | SDKROOT = iphoneos; 353 | VALIDATE_PRODUCT = YES; 354 | }; 355 | name = Release; 356 | }; 357 | 9B24E5D71D7D44D300AA2ECC /* Debug */ = { 358 | isa = XCBuildConfiguration; 359 | buildSettings = { 360 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 361 | CODE_SIGN_IDENTITY = "iPhone Developer"; 362 | DEVELOPMENT_TEAM = XC34BSW465; 363 | INFOPLIST_FILE = MCDownloadManager/Info.plist; 364 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 365 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 366 | PRODUCT_BUNDLE_IDENTIFIER = com.7keyun.com.MCDownloadManager; 367 | PRODUCT_NAME = "$(TARGET_NAME)"; 368 | }; 369 | name = Debug; 370 | }; 371 | 9B24E5D81D7D44D300AA2ECC /* Release */ = { 372 | isa = XCBuildConfiguration; 373 | buildSettings = { 374 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 375 | CODE_SIGN_IDENTITY = "iPhone Developer"; 376 | DEVELOPMENT_TEAM = XC34BSW465; 377 | INFOPLIST_FILE = MCDownloadManager/Info.plist; 378 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 379 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 380 | PRODUCT_BUNDLE_IDENTIFIER = com.7keyun.com.MCDownloadManager; 381 | PRODUCT_NAME = "$(TARGET_NAME)"; 382 | }; 383 | name = Release; 384 | }; 385 | /* End XCBuildConfiguration section */ 386 | 387 | /* Begin XCConfigurationList section */ 388 | 9B24E5BA1D7D44D300AA2ECC /* Build configuration list for PBXProject "MCDownloadManager" */ = { 389 | isa = XCConfigurationList; 390 | buildConfigurations = ( 391 | 9B24E5D41D7D44D300AA2ECC /* Debug */, 392 | 9B24E5D51D7D44D300AA2ECC /* Release */, 393 | ); 394 | defaultConfigurationIsVisible = 0; 395 | defaultConfigurationName = Release; 396 | }; 397 | 9B24E5D61D7D44D300AA2ECC /* Build configuration list for PBXNativeTarget "MCDownloadManager" */ = { 398 | isa = XCConfigurationList; 399 | buildConfigurations = ( 400 | 9B24E5D71D7D44D300AA2ECC /* Debug */, 401 | 9B24E5D81D7D44D300AA2ECC /* Release */, 402 | ); 403 | defaultConfigurationIsVisible = 0; 404 | defaultConfigurationName = Release; 405 | }; 406 | /* End XCConfigurationList section */ 407 | }; 408 | rootObject = 9B24E5B71D7D44D300AA2ECC /* Project object */; 409 | } 410 | -------------------------------------------------------------------------------- /MCDownloadManager.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /MCDownloadManager.xcodeproj/project.xcworkspace/xcuserdata/M.C.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agelessman/MCDownloadManager/16abea6dfcc345e046745ada9420f9fe4e5bd53b/MCDownloadManager.xcodeproj/project.xcworkspace/xcuserdata/M.C.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /MCDownloadManager.xcodeproj/project.xcworkspace/xcuserdata/machao.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agelessman/MCDownloadManager/16abea6dfcc345e046745ada9420f9fe4e5bd53b/MCDownloadManager.xcodeproj/project.xcworkspace/xcuserdata/machao.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /MCDownloadManager.xcodeproj/project.xcworkspace/xcuserdata/test.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agelessman/MCDownloadManager/16abea6dfcc345e046745ada9420f9fe4e5bd53b/MCDownloadManager.xcodeproj/project.xcworkspace/xcuserdata/test.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /MCDownloadManager.xcodeproj/xcuserdata/M.C.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /MCDownloadManager.xcodeproj/xcuserdata/M.C.xcuserdatad/xcschemes/MCDownloadManager.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /MCDownloadManager.xcodeproj/xcuserdata/M.C.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | MCDownloadManager.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 9B24E5BE1D7D44D300AA2ECC 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /MCDownloadManager.xcodeproj/xcuserdata/machao.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /MCDownloadManager.xcodeproj/xcuserdata/machao.xcuserdatad/xcschemes/MCDownloadManager.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /MCDownloadManager.xcodeproj/xcuserdata/machao.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | MCDownloadManager.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 9B24E5BE1D7D44D300AA2ECC 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /MCDownloadManager.xcodeproj/xcuserdata/test.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /MCDownloadManager.xcodeproj/xcuserdata/test.xcuserdatad/xcschemes/MCDownloadManager.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /MCDownloadManager.xcodeproj/xcuserdata/test.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | MCDownloadManager.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 9B24E5BE1D7D44D300AA2ECC 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /MCDownloadManager/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // MCDownloadManager 4 | // 5 | // Created by 马超 on 16/9/5. 6 | // Copyright © 2016年 qikeyun. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /MCDownloadManager/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // MCDownloadManager 4 | // 5 | // Created by 马超 on 16/9/5. 6 | // Copyright © 2016年 qikeyun. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "ViewController.h" 11 | 12 | @interface AppDelegate () 13 | 14 | @end 15 | 16 | @implementation AppDelegate 17 | 18 | 19 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 20 | // Override point for customization after application launch. 21 | 22 | return YES; 23 | } 24 | 25 | - (void)applicationWillResignActive:(UIApplication *)application { 26 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 27 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 28 | } 29 | 30 | - (void)applicationDidEnterBackground:(UIApplication *)application { 31 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | } 34 | 35 | - (void)applicationWillEnterForeground:(UIApplication *)application { 36 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 37 | } 38 | 39 | - (void)applicationDidBecomeActive:(UIApplication *)application { 40 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 41 | } 42 | 43 | - (void)applicationWillTerminate:(UIApplication *)application { 44 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 45 | } 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /MCDownloadManager/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /MCDownloadManager/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /MCDownloadManager/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 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 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 61 | 71 | 81 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | -------------------------------------------------------------------------------- /MCDownloadManager/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | NSAppTransportSecurity 26 | 27 | NSAllowsArbitraryLoads 28 | 29 | 30 | NSCameraUsageDescription 31 | 32 | NSContactsUsageDescription 33 | 34 | NSLocationAlwaysUsageDescription 35 | 36 | NSMicrophoneUsageDescription 37 | 38 | NSPhotoLibraryUsageDescription 39 | 40 | UIBackgroundModes 41 | 42 | fetch 43 | 44 | UILaunchStoryboardName 45 | LaunchScreen 46 | UIMainStoryboardFile 47 | Main 48 | UIRequiredDeviceCapabilities 49 | 50 | armv7 51 | 52 | UISupportedInterfaceOrientations 53 | 54 | UIInterfaceOrientationPortrait 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /MCDownloadManager/MCDownloadManager.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /MCDownloadManager/MCDownloadManager/MCDefine.h: -------------------------------------------------------------------------------- 1 | // 2 | // MCDefine.h 3 | // JZGChryslerForPad 4 | // 5 | // Created by test on 16/12/6. 6 | // Copyright © 2016年 Beijing JingZhenGu Information Technology Co.Ltd. All rights reserved. 7 | // 8 | 9 | #ifndef MCDefine_h 10 | #define MCDefine_h 11 | 12 | 13 | // Use dispatch_main_async_safe instead of dispatch_async(dispatch_get_main_queue(), block) 14 | #ifndef dispatch_main_async_safe 15 | #define dispatch_main_async_safe(block)\ 16 | if (strcmp(dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL), dispatch_queue_get_label(dispatch_get_main_queue())) == 0) {\ 17 | block();\ 18 | } else {\ 19 | dispatch_async(dispatch_get_main_queue(), block);\ 20 | } 21 | #endif 22 | 23 | 24 | 25 | #endif /* MCDefine_h */ 26 | -------------------------------------------------------------------------------- /MCDownloadManager/MCDownloadManager/MCDownloadManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // MCDownloadManager.h 3 | // MCDownloadManager 4 | // 5 | // Created by 马超 on 16/9/5. 6 | // Copyright © 2016年 qikeyun. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | 13 | NS_ASSUME_NONNULL_BEGIN 14 | 15 | FOUNDATION_EXPORT NSString * const MCDownloadCacheFolderName; 16 | @class MCDownloadReceipt; 17 | /** The download state */ 18 | typedef NS_ENUM(NSUInteger, MCDownloadState) { 19 | MCDownloadStateNone, /** default */ 20 | MCDownloadStateWillResume, /** waiting */ 21 | MCDownloadStateDownloading, /** downloading */ 22 | MCDownloadStateSuspened, /** suspened */ 23 | MCDownloadStateCompleted, /** download completed */ 24 | MCDownloadStateFailed /** download failed */ 25 | }; 26 | 27 | /** The download prioritization */ 28 | typedef NS_ENUM(NSInteger, MCDownloadPrioritization) { 29 | MCDownloadPrioritizationFIFO, /** first in first out */ 30 | MCDownloadPrioritizationLIFO /** last in first out */ 31 | }; 32 | 33 | typedef void (^MCSucessBlock)(NSURLRequest * _Nullable, NSHTTPURLResponse * _Nullable, NSURL * _Nonnull); 34 | typedef void (^MCFailureBlock)(NSURLRequest * _Nullable, NSHTTPURLResponse * _Nullable, NSError * _Nonnull); 35 | typedef void (^MCProgressBlock)(NSProgress * _Nonnull,MCDownloadReceipt *); 36 | 37 | /** 38 | * The receipt of a downloader,we can get all the informationg by the receipt. 39 | */ 40 | @interface MCDownloadReceipt : NSObject 41 | 42 | /** 43 | * Download State 44 | */ 45 | @property (nonatomic, assign, readonly) MCDownloadState state; 46 | 47 | @property (nonatomic, copy, readonly, nonnull) NSString *url; 48 | @property (nonatomic, copy, readonly, nonnull) NSString *filePath; 49 | @property (nonatomic, copy, readonly, nullable) NSString *filename; 50 | @property (nonatomic, copy, readonly, nullable) NSString *truename; 51 | @property (nonatomic, copy, readonly) NSString *speed; // KB/s 52 | 53 | @property (assign, nonatomic, readonly) long long totalBytesWritten; 54 | @property (assign, nonatomic, readonly) long long totalBytesExpectedToWrite; 55 | 56 | @property (nonatomic, copy, readonly, nonnull) NSProgress *progress; 57 | 58 | @property (nonatomic, strong, readonly, nullable) NSError *error; 59 | 60 | @property (nonatomic,copy)MCSucessBlock successBlock; 61 | @property (nonatomic,copy)MCFailureBlock failureBlock; 62 | @property (nonatomic,copy)MCProgressBlock progressBlock; 63 | @end 64 | 65 | 66 | @protocol MCDownloadControlDelegate 67 | 68 | - (void)suspendWithURL:(NSString * _Nonnull)url; 69 | - (void)suspendWithDownloadReceipt:(MCDownloadReceipt * _Nonnull)receipt; 70 | 71 | - (void)removeWithURL:(NSString * _Nonnull)url; 72 | - (void)removeWithDownloadReceipt:(MCDownloadReceipt * _Nonnull)receipt; 73 | 74 | @end 75 | 76 | 77 | @interface MCDownloadManager : NSObject 78 | 79 | /** 80 | Defines the order prioritization of incoming download requests being inserted into the queue. `MCDownloadPrioritizationFIFO` by default. 81 | */ 82 | @property (nonatomic, assign) MCDownloadPrioritization downloadPrioritizaton; 83 | 84 | /** 85 | The shared default instance of `MCDownloadManager` initialized with default values. 86 | */ 87 | + (instancetype)defaultInstance; 88 | 89 | /** 90 | Default initializer 91 | 92 | @return An instance of `MCDownloadManager` initialized with default values. 93 | */ 94 | - (instancetype)init; 95 | 96 | /** 97 | Initializes the `MCDownloadManager` instance with the given session manager, download prioritization, maximum active download count. 98 | 99 | @param sessionManager The session manager to use to download file. 100 | @param downloadPrioritization The download prioritization of the download queue. 101 | @param maximumActiveDownloads The maximum number of active downloads allowed at any given time. Recommend `4`. 102 | 103 | @return The new `MCDownloadManager` instance. 104 | */ 105 | - (instancetype)initWithSession:(NSURLSession *)session 106 | downloadPrioritization:(MCDownloadPrioritization)downloadPrioritization 107 | maximumActiveDownloads:(NSInteger)maximumActiveDownloads; 108 | 109 | ///----------------------------- 110 | /// @name Running Download Tasks 111 | ///----------------------------- 112 | 113 | /** 114 | Creates an `MCDownloadReceipt` with the specified request. 115 | 116 | @param url The URL for the request. 117 | @param downloadProgressBlock A block object to be executed when the download progress is updated. Note this block is called on the session queue, not the main queue. 118 | @param destination A block object to be executed in order to determine the destination of the downloaded file. This block takes two arguments, the target path & the server response, and returns the desired file URL of the resulting download. The temporary file used during the download will be automatically deleted after being moved to the returned URL. 119 | 120 | @warning If using a background `NSURLSessionConfiguration` on iOS, these blocks will be lost when the app is terminated. Background sessions may prefer to use `-setDownloadTaskDidFinishDownloadingBlock:` to specify the URL for saving the downloaded file, rather than the destination block of this method. 121 | */ 122 | - (MCDownloadReceipt *)downloadFileWithURL:(NSString * _Nullable)url 123 | progress:(nullable void (^)(NSProgress *downloadProgress, MCDownloadReceipt *receipt))downloadProgressBlock 124 | destination:(nullable NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination 125 | success:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, NSURL *filePath))success 126 | failure:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, NSError *error))failure; 127 | 128 | 129 | - (MCDownloadReceipt * _Nullable)downloadReceiptForURL:(NSString *)url; 130 | 131 | @end 132 | 133 | NS_ASSUME_NONNULL_END 134 | -------------------------------------------------------------------------------- /MCDownloadManager/MCDownloadManager/MCDownloadManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // MCDownloadManager.m 3 | // MCDownloadManager 4 | // 5 | // Created by 马超 on 16/9/5. 6 | // Copyright © 2016年 qikeyun. All rights reserved. 7 | // 8 | 9 | #import "MCDownloadManager.h" 10 | #import 11 | 12 | 13 | NSString * const MCDownloadCacheFolderName = @"MCDownloadCache"; 14 | 15 | static NSString * cacheFolder() { 16 | NSFileManager *filemgr = [NSFileManager defaultManager]; 17 | static NSString *cacheFolder; 18 | static dispatch_once_t onceToken; 19 | dispatch_once(&onceToken, ^{ 20 | if (!cacheFolder) { 21 | NSString *cacheDir = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES).firstObject; 22 | cacheFolder = [cacheDir stringByAppendingPathComponent:MCDownloadCacheFolderName]; 23 | } 24 | NSError *error = nil; 25 | if(![filemgr createDirectoryAtPath:cacheFolder withIntermediateDirectories:YES attributes:nil error:&error]) { 26 | NSLog(@"Failed to create cache directory at %@", cacheFolder); 27 | cacheFolder = nil; 28 | } 29 | }); 30 | return cacheFolder; 31 | } 32 | 33 | static NSString * LocalReceiptsPath() { 34 | return [cacheFolder() stringByAppendingPathComponent:@"receipts.data"]; 35 | } 36 | 37 | static unsigned long long fileSizeForPath(NSString *path) { 38 | 39 | signed long long fileSize = 0; 40 | NSFileManager *fileManager = [NSFileManager defaultManager]; 41 | if ([fileManager fileExistsAtPath:path]) { 42 | NSError *error = nil; 43 | NSDictionary *fileDict = [fileManager attributesOfItemAtPath:path error:&error]; 44 | if (!error && fileDict) { 45 | fileSize = [fileDict fileSize]; 46 | } 47 | } 48 | return fileSize; 49 | } 50 | 51 | static NSString * getMD5String(NSString *str) { 52 | 53 | if (str == nil) return nil; 54 | 55 | const char *cstring = str.UTF8String; 56 | unsigned char bytes[CC_MD5_DIGEST_LENGTH]; 57 | CC_MD5(cstring, (CC_LONG)strlen(cstring), bytes); 58 | 59 | NSMutableString *md5String = [NSMutableString string]; 60 | for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) { 61 | [md5String appendFormat:@"%02x", bytes[i]]; 62 | } 63 | return md5String; 64 | } 65 | 66 | 67 | 68 | @interface MCDownloadReceipt() 69 | 70 | @property (nonatomic, copy) NSString *url; 71 | @property (nonatomic, copy) NSString *filePath; 72 | @property (nonatomic, copy) NSString *filename; 73 | @property (nonatomic, copy) NSString *truename; 74 | @property (nonatomic, copy) NSString *speed; // KB/s 75 | @property (nonatomic, assign) MCDownloadState state; 76 | 77 | @property (assign, nonatomic) long long totalBytesWritten; 78 | @property (assign, nonatomic) long long totalBytesExpectedToWrite; 79 | @property (nonatomic, copy) NSProgress *progress; 80 | 81 | @property (strong, nonatomic) NSOutputStream *stream; 82 | 83 | @property (nonatomic, assign) NSUInteger totalRead; 84 | @property (nonatomic, strong) NSDate *date; 85 | 86 | 87 | @end 88 | @implementation MCDownloadReceipt 89 | 90 | - (NSOutputStream *)stream 91 | { 92 | if (_stream == nil) { 93 | _stream = [NSOutputStream outputStreamToFileAtPath:self.filePath append:YES]; 94 | } 95 | return _stream; 96 | } 97 | 98 | - (NSString *)filePath { 99 | 100 | NSString *path = [cacheFolder() stringByAppendingPathComponent:self.filename]; 101 | if (![path isEqualToString:_filePath] ) { 102 | if (_filePath && ![[NSFileManager defaultManager] fileExistsAtPath:_filePath]) { 103 | NSString *dir = [_filePath stringByDeletingLastPathComponent]; 104 | [[NSFileManager defaultManager] createDirectoryAtPath:dir withIntermediateDirectories:YES attributes:nil error:nil]; 105 | } 106 | _filePath = path; 107 | } 108 | 109 | return _filePath; 110 | } 111 | 112 | 113 | - (NSString *)filename { 114 | if (_filename == nil) { 115 | NSString *pathExtension = self.url.pathExtension; 116 | if (pathExtension.length) { 117 | _filename = [NSString stringWithFormat:@"%@.%@", getMD5String(self.url), pathExtension]; 118 | } else { 119 | _filename = getMD5String(self.url); 120 | } 121 | } 122 | return _filename; 123 | } 124 | 125 | - (NSString *)truename { 126 | if (_truename == nil) { 127 | _truename = self.url.lastPathComponent; 128 | } 129 | return _truename; 130 | } 131 | 132 | - (NSProgress *)progress { 133 | if (_progress == nil) { 134 | _progress = [[NSProgress alloc] initWithParent:nil userInfo:nil]; 135 | } 136 | @try { 137 | _progress.totalUnitCount = self.totalBytesExpectedToWrite; 138 | _progress.completedUnitCount = self.totalBytesWritten; 139 | } @catch (NSException *exception) { 140 | 141 | } 142 | return _progress; 143 | } 144 | 145 | - (long long)totalBytesWritten { 146 | 147 | return fileSizeForPath(self.filePath); 148 | } 149 | 150 | 151 | - (instancetype)initWithURL:(NSString *)url { 152 | if (self = [self init]) { 153 | 154 | self.url = url; 155 | self.totalBytesExpectedToWrite = 1; 156 | } 157 | return self; 158 | } 159 | 160 | #pragma mark - NSCoding 161 | - (void)encodeWithCoder:(NSCoder *)aCoder 162 | { 163 | [aCoder encodeObject:self.url forKey:NSStringFromSelector(@selector(url))]; 164 | [aCoder encodeObject:self.filePath forKey:NSStringFromSelector(@selector(filePath))]; 165 | [aCoder encodeObject:@(self.state) forKey:NSStringFromSelector(@selector(state))]; 166 | [aCoder encodeObject:self.filename forKey:NSStringFromSelector(@selector(filename))]; 167 | [aCoder encodeObject:@(self.totalBytesWritten) forKey:NSStringFromSelector(@selector(totalBytesWritten))]; 168 | [aCoder encodeObject:@(self.totalBytesExpectedToWrite) forKey:NSStringFromSelector(@selector(totalBytesExpectedToWrite))]; 169 | 170 | } 171 | 172 | - (id)initWithCoder:(NSCoder *)aDecoder 173 | { 174 | self = [super init]; 175 | if (self) { 176 | self.url = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(url))]; 177 | self.filePath = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(filePath))]; 178 | self.state = [[aDecoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(state))] unsignedIntegerValue]; 179 | self.filename = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(filename))]; 180 | self.totalBytesWritten = [[aDecoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(totalBytesWritten))] unsignedIntegerValue]; 181 | self.totalBytesExpectedToWrite = [[aDecoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(totalBytesExpectedToWrite))] unsignedIntegerValue]; 182 | 183 | } 184 | return self; 185 | } 186 | 187 | 188 | @end 189 | 190 | 191 | #pragma mark - 192 | 193 | #if OS_OBJECT_USE_OBJC 194 | #define MCDispatchQueueSetterSementics strong 195 | #else 196 | #define MCDispatchQueueSetterSementics assign 197 | #endif 198 | 199 | @interface MCDownloadManager () 200 | @property (nonatomic, MCDispatchQueueSetterSementics) dispatch_queue_t synchronizationQueue; 201 | @property (strong, nonatomic) NSURLSession *session; 202 | 203 | @property (nonatomic, assign) NSInteger maximumActiveDownloads; 204 | @property (nonatomic, assign) NSInteger activeRequestCount; 205 | 206 | @property (nonatomic, strong) NSMutableArray *queuedTasks; 207 | @property (nonatomic, strong) NSMutableDictionary *tasks; 208 | 209 | @property (nonatomic, strong) NSMutableDictionary *allDownloadReceipts; 210 | @property (assign, nonatomic) UIBackgroundTaskIdentifier backgroundTaskId; 211 | @end 212 | 213 | @implementation MCDownloadManager 214 | 215 | + (NSURLSessionConfiguration *)defaultURLSessionConfiguration { 216 | NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; 217 | 218 | configuration.HTTPShouldSetCookies = YES; 219 | configuration.HTTPShouldUsePipelining = NO; 220 | configuration.requestCachePolicy = NSURLRequestUseProtocolCachePolicy; 221 | configuration.allowsCellularAccess = YES; 222 | configuration.timeoutIntervalForRequest = 60.0; 223 | configuration.HTTPMaximumConnectionsPerHost = 10; 224 | configuration.discretionary = YES; 225 | return configuration; 226 | } 227 | 228 | 229 | - (instancetype)init { 230 | 231 | 232 | NSURLSessionConfiguration *defaultConfiguration = [self.class defaultURLSessionConfiguration]; 233 | 234 | NSOperationQueue *queue = [[NSOperationQueue alloc] init]; 235 | queue.maxConcurrentOperationCount = 1; 236 | NSURLSession *session = [NSURLSession sessionWithConfiguration:defaultConfiguration delegate:self delegateQueue:queue]; 237 | 238 | return [self initWithSession:session 239 | downloadPrioritization:MCDownloadPrioritizationFIFO 240 | maximumActiveDownloads:4 ]; 241 | } 242 | 243 | 244 | - (instancetype)initWithSession:(NSURLSession *)session downloadPrioritization:(MCDownloadPrioritization)downloadPrioritization maximumActiveDownloads:(NSInteger)maximumActiveDownloads { 245 | if (self = [super init]) { 246 | 247 | self.session = session; 248 | self.downloadPrioritizaton = downloadPrioritization; 249 | self.maximumActiveDownloads = maximumActiveDownloads; 250 | 251 | self.queuedTasks = [[NSMutableArray alloc] init]; 252 | self.tasks = [[NSMutableDictionary alloc] init]; 253 | self.activeRequestCount = 0; 254 | 255 | NSString *name = [NSString stringWithFormat:@"com.mc.downloadManager.synchronizationqueue-%@", [[NSUUID UUID] UUIDString]]; 256 | self.synchronizationQueue = dispatch_queue_create([name cStringUsingEncoding:NSASCIIStringEncoding], DISPATCH_QUEUE_SERIAL); 257 | 258 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillTerminate:) name:UIApplicationWillTerminateNotification object:nil]; 259 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidReceiveMemoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; 260 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillResignActive:) name:UIApplicationWillResignActiveNotification object:nil]; 261 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil]; 262 | } 263 | 264 | return self; 265 | } 266 | 267 | + (instancetype)defaultInstance { 268 | static MCDownloadManager *sharedInstance = nil; 269 | static dispatch_once_t onceToken; 270 | dispatch_once(&onceToken, ^{ 271 | sharedInstance = [[self alloc] init]; 272 | }); 273 | return sharedInstance; 274 | } 275 | 276 | 277 | - (NSMutableDictionary *)allDownloadReceipts { 278 | if (_allDownloadReceipts == nil) { 279 | NSDictionary *receipts = [NSKeyedUnarchiver unarchiveObjectWithFile:LocalReceiptsPath()]; 280 | _allDownloadReceipts = receipts != nil ? receipts.mutableCopy : [NSMutableDictionary dictionary]; 281 | } 282 | return _allDownloadReceipts; 283 | } 284 | 285 | - (void)saveReceipts:(NSDictionary *)receipts { 286 | [NSKeyedArchiver archiveRootObject:receipts toFile:LocalReceiptsPath()]; 287 | } 288 | 289 | - (MCDownloadReceipt *)updateReceiptWithURL:(NSString *)url state:(MCDownloadState)state { 290 | MCDownloadReceipt *receipt = [self downloadReceiptForURL:url]; 291 | receipt.state = state; 292 | 293 | [self saveReceipts:self.allDownloadReceipts]; 294 | 295 | return receipt; 296 | } 297 | 298 | 299 | - (MCDownloadReceipt *)downloadFileWithURL:(NSString *)url 300 | progress:(void (^)(NSProgress * _Nonnull,MCDownloadReceipt *receipt))downloadProgressBlock 301 | destination:(NSURL * (^)(NSURL * _Nonnull, NSURLResponse * _Nonnull))destination 302 | success:(nullable void (^)(NSURLRequest * _Nullable, NSHTTPURLResponse * _Nullable, NSURL * _Nonnull))success 303 | failure:(nullable void (^)(NSURLRequest * _Nullable, NSHTTPURLResponse * _Nullable, NSError * _Nonnull))failure { 304 | 305 | __block MCDownloadReceipt *receipt = [self downloadReceiptForURL:url]; 306 | 307 | dispatch_sync(self.synchronizationQueue, ^{ 308 | NSString *URLIdentifier = url; 309 | if (URLIdentifier == nil) { 310 | if (failure) { 311 | NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorBadURL userInfo:nil]; 312 | dispatch_async(dispatch_get_main_queue(), ^{ 313 | failure(nil, nil, error); 314 | }); 315 | } 316 | return; 317 | } 318 | 319 | receipt.successBlock = success; 320 | receipt.failureBlock = failure; 321 | receipt.progressBlock = downloadProgressBlock; 322 | 323 | if (receipt.state == MCDownloadStateCompleted && receipt.totalBytesWritten == receipt.totalBytesExpectedToWrite) { 324 | dispatch_async(dispatch_get_main_queue(), ^{ 325 | if (receipt.successBlock) { 326 | receipt.successBlock(nil,nil,[NSURL URLWithString:receipt.url]); 327 | } 328 | }); 329 | return ; 330 | } 331 | 332 | if (receipt.state == MCDownloadStateDownloading && receipt.totalBytesWritten != receipt.totalBytesExpectedToWrite) { 333 | dispatch_async(dispatch_get_main_queue(), ^{ 334 | if (receipt.progressBlock) { 335 | receipt.progressBlock(receipt.progress,receipt); 336 | } 337 | }); 338 | return ; 339 | } 340 | 341 | NSURLSessionDataTask *task = self.tasks[receipt.url]; 342 | // 当请求暂停一段时间后。转态会变化。所有要判断下状态 343 | if (!task || ((task.state != NSURLSessionTaskStateRunning) && (task.state != NSURLSessionTaskStateSuspended))) { 344 | NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:receipt.url]]; 345 | 346 | NSString *range = [NSString stringWithFormat:@"bytes=%zd-", receipt.totalBytesWritten]; 347 | [request setValue:range forHTTPHeaderField:@"Range"]; 348 | NSURLSessionDataTask *task = [self.session dataTaskWithRequest:request]; 349 | task.taskDescription = receipt.url; 350 | self.tasks[receipt.url] = task; 351 | [self.queuedTasks addObject:task]; 352 | } 353 | 354 | [self resumeWithDownloadReceipt:receipt]; 355 | 356 | 357 | }); 358 | return receipt; 359 | } 360 | 361 | 362 | 363 | #pragma mark - ----------------------- 364 | 365 | - (NSURLSessionDataTask*)safelyRemoveTaskWithURLIdentifier:(NSString *)URLIdentifier { 366 | __block NSURLSessionDataTask *task = nil; 367 | dispatch_sync(self.synchronizationQueue, ^{ 368 | task = [self removeTaskWithURLIdentifier:URLIdentifier]; 369 | }); 370 | return task; 371 | } 372 | 373 | //This method should only be called from safely within the synchronizationQueue 374 | - (NSURLSessionDataTask *)removeTaskWithURLIdentifier:(NSString *)URLIdentifier { 375 | NSURLSessionDataTask *task = self.tasks[URLIdentifier]; 376 | [self.tasks removeObjectForKey:URLIdentifier]; 377 | return task; 378 | } 379 | 380 | - (void)safelyDecrementActiveTaskCount { 381 | dispatch_sync(self.synchronizationQueue, ^{ 382 | if (self.activeRequestCount > 0) { 383 | self.activeRequestCount -= 1; 384 | } 385 | }); 386 | } 387 | 388 | - (void)safelyStartNextTaskIfNecessary { 389 | dispatch_sync(self.synchronizationQueue, ^{ 390 | if ([self isActiveRequestCountBelowMaximumLimit]) { 391 | while (self.queuedTasks.count > 0) { 392 | NSURLSessionDataTask *task = [self dequeueTask]; 393 | MCDownloadReceipt *receipt = [self downloadReceiptForURL:task.taskDescription]; 394 | if (task.state == NSURLSessionTaskStateSuspended && receipt.state == MCDownloadStateWillResume) { 395 | [self startTask:task]; 396 | break; 397 | } 398 | } 399 | } 400 | }); 401 | } 402 | 403 | 404 | - (void)startTask:(NSURLSessionDataTask *)task { 405 | [task resume]; 406 | ++self.activeRequestCount; 407 | [self updateReceiptWithURL:task.taskDescription state:MCDownloadStateDownloading]; 408 | } 409 | 410 | - (void)enqueueTask:(NSURLSessionDataTask *)task { 411 | switch (self.downloadPrioritizaton) { 412 | case MCDownloadPrioritizationFIFO: // 413 | [self.queuedTasks addObject:task]; 414 | break; 415 | case MCDownloadPrioritizationLIFO: // 416 | [self.queuedTasks insertObject:task atIndex:0]; 417 | break; 418 | } 419 | } 420 | 421 | - (NSURLSessionDataTask *)dequeueTask { 422 | NSURLSessionDataTask *task = nil; 423 | task = [self.queuedTasks firstObject]; 424 | [self.queuedTasks removeObject:task]; 425 | return task; 426 | } 427 | 428 | - (BOOL)isActiveRequestCountBelowMaximumLimit { 429 | return self.activeRequestCount < self.maximumActiveDownloads; 430 | } 431 | 432 | 433 | #pragma mark - 434 | - (MCDownloadReceipt *)downloadReceiptForURL:(NSString *)url { 435 | 436 | if (url == nil) return nil; 437 | MCDownloadReceipt *receipt = self.allDownloadReceipts[url]; 438 | if (receipt) return receipt; 439 | receipt = [[MCDownloadReceipt alloc] initWithURL:url]; 440 | receipt.state = MCDownloadStateNone; 441 | receipt.totalBytesExpectedToWrite = 1; 442 | 443 | dispatch_sync(self.synchronizationQueue, ^{ 444 | [self.allDownloadReceipts setObject:receipt forKey:url]; 445 | [self saveReceipts:self.allDownloadReceipts]; 446 | }); 447 | 448 | return receipt; 449 | } 450 | 451 | #pragma mark - NSNotification 452 | - (void)applicationWillTerminate:(NSNotification *)not { 453 | 454 | [self suspendAll]; 455 | } 456 | 457 | - (void)applicationDidReceiveMemoryWarning:(NSNotification *)not { 458 | 459 | [self suspendAll]; 460 | } 461 | 462 | - (void)applicationWillResignActive:(NSNotification *)not { 463 | /// 捕获到失去激活状态后 464 | Class UIApplicationClass = NSClassFromString(@"UIApplication"); 465 | BOOL hasApplication = UIApplicationClass && [UIApplicationClass respondsToSelector:@selector(sharedApplication)]; 466 | if (hasApplication ) { 467 | __weak __typeof__ (self) wself = self; 468 | UIApplication * app = [UIApplicationClass performSelector:@selector(sharedApplication)]; 469 | self.backgroundTaskId = [app beginBackgroundTaskWithExpirationHandler:^{ 470 | __strong __typeof (wself) sself = wself; 471 | 472 | if (sself) { 473 | [sself suspendAll]; 474 | 475 | [app endBackgroundTask:sself.backgroundTaskId]; 476 | sself.backgroundTaskId = UIBackgroundTaskInvalid; 477 | } 478 | }]; 479 | } 480 | } 481 | 482 | - (void)applicationDidBecomeActive:(NSNotification *)not { 483 | 484 | Class UIApplicationClass = NSClassFromString(@"UIApplication"); 485 | if(!UIApplicationClass || ![UIApplicationClass respondsToSelector:@selector(sharedApplication)]) { 486 | return; 487 | } 488 | if (self.backgroundTaskId != UIBackgroundTaskInvalid) { 489 | UIApplication * app = [UIApplication performSelector:@selector(sharedApplication)]; 490 | [app endBackgroundTask:self.backgroundTaskId]; 491 | self.backgroundTaskId = UIBackgroundTaskInvalid; 492 | } 493 | } 494 | 495 | #pragma mark - MCDownloadControlDelegate 496 | 497 | - (void)resumeWithURL:(NSString *)url { 498 | 499 | if (url == nil) return; 500 | 501 | MCDownloadReceipt *receipt = [self downloadReceiptForURL:url]; 502 | [self resumeWithDownloadReceipt:receipt]; 503 | 504 | } 505 | - (void)resumeWithDownloadReceipt:(MCDownloadReceipt *)receipt { 506 | 507 | if ([self isActiveRequestCountBelowMaximumLimit]) { 508 | NSURLSessionDataTask *task = self.tasks[receipt.url]; 509 | // 当请求暂停一段时间后。转态会变化。所有要判断下状态 510 | if (!task || ((task.state != NSURLSessionTaskStateRunning) && (task.state != NSURLSessionTaskStateSuspended))) { 511 | [self downloadFileWithURL:receipt.url progress:receipt.progressBlock destination:nil success:receipt.successBlock failure:receipt.failureBlock]; 512 | }else { 513 | [self startTask:self.tasks[receipt.url]]; 514 | receipt.date = [NSDate date]; 515 | } 516 | 517 | }else { 518 | receipt.state = MCDownloadStateWillResume; 519 | [self saveReceipts:self.allDownloadReceipts]; 520 | [self enqueueTask:self.tasks[receipt.url]]; 521 | } 522 | } 523 | 524 | - (void)suspendAll { 525 | 526 | for (NSURLSessionDataTask *task in self.queuedTasks) { 527 | 528 | MCDownloadReceipt *receipt = [self downloadReceiptForURL:task.taskDescription]; 529 | receipt.state = MCDownloadStateFailed; 530 | [task suspend]; 531 | [self safelyDecrementActiveTaskCount]; 532 | } 533 | [self saveReceipts:self.allDownloadReceipts]; 534 | 535 | } 536 | -(void)suspendWithURL:(NSString *)url { 537 | 538 | if (url == nil) return; 539 | 540 | MCDownloadReceipt *receipt = [self downloadReceiptForURL:url]; 541 | [self suspendWithDownloadReceipt:receipt]; 542 | 543 | } 544 | - (void)suspendWithDownloadReceipt:(MCDownloadReceipt *)receipt { 545 | 546 | [self updateReceiptWithURL:receipt.url state:MCDownloadStateSuspened]; 547 | NSURLSessionDataTask *task = self.tasks[receipt.url]; 548 | if (task) { 549 | [task suspend]; 550 | [self safelyDecrementActiveTaskCount]; 551 | [self safelyStartNextTaskIfNecessary]; 552 | } 553 | 554 | } 555 | 556 | 557 | - (void)removeWithURL:(NSString *)url { 558 | 559 | if (url == nil) return; 560 | 561 | MCDownloadReceipt *receipt = [self downloadReceiptForURL:url]; 562 | [self removeWithDownloadReceipt:receipt]; 563 | 564 | } 565 | - (void)removeWithDownloadReceipt:(MCDownloadReceipt *)receipt { 566 | 567 | NSURLSessionDataTask *task = self.tasks[receipt.url]; 568 | if (task) { 569 | [task cancel]; 570 | } 571 | 572 | [self.queuedTasks removeObject:task]; 573 | [self safelyRemoveTaskWithURLIdentifier:receipt.url]; 574 | 575 | dispatch_sync(self.synchronizationQueue, ^{ 576 | [self.allDownloadReceipts removeObjectForKey:receipt.url]; 577 | [self saveReceipts:self.allDownloadReceipts]; 578 | }); 579 | 580 | NSFileManager *fileManager = [NSFileManager defaultManager]; 581 | [fileManager removeItemAtPath:receipt.filePath error:nil]; 582 | 583 | } 584 | #pragma mark - 585 | - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSHTTPURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler 586 | { 587 | MCDownloadReceipt *receipt = [self downloadReceiptForURL:dataTask.taskDescription]; 588 | receipt.totalBytesExpectedToWrite = receipt.totalBytesWritten + dataTask.countOfBytesExpectedToReceive; 589 | receipt.state = MCDownloadStateDownloading; 590 | 591 | [self saveReceipts:self.allDownloadReceipts]; 592 | 593 | completionHandler(NSURLSessionResponseAllow); 594 | } 595 | 596 | - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data 597 | { 598 | 599 | dispatch_sync(self.synchronizationQueue, ^{ 600 | 601 | __block NSError *error = nil; 602 | MCDownloadReceipt *receipt = [self downloadReceiptForURL:dataTask.taskDescription]; 603 | 604 | // Speed 605 | receipt.totalRead += data.length; 606 | NSDate *currentDate = [NSDate date]; 607 | if ([currentDate timeIntervalSinceDate:receipt.date] >= 1) { 608 | double time = [currentDate timeIntervalSinceDate:receipt.date]; 609 | long long speed = receipt.totalRead/time; 610 | receipt.speed = [self formatByteCount:speed]; 611 | receipt.totalRead = 0.0; 612 | receipt.date = currentDate; 613 | } 614 | 615 | // Write Data 616 | NSInputStream *inputStream = [[NSInputStream alloc] initWithData:data]; 617 | NSOutputStream *outputStream = [[NSOutputStream alloc] initWithURL:[NSURL fileURLWithPath:receipt.filePath] append:YES]; 618 | [inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 619 | [outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 620 | 621 | [inputStream open]; 622 | [outputStream open]; 623 | 624 | while ([inputStream hasBytesAvailable] && [outputStream hasSpaceAvailable]) { 625 | uint8_t buffer[1024]; 626 | 627 | NSInteger bytesRead = [inputStream read:buffer maxLength:1024]; 628 | if (inputStream.streamError || bytesRead < 0) { 629 | error = inputStream.streamError; 630 | break; 631 | } 632 | 633 | NSInteger bytesWritten = [outputStream write:buffer maxLength:(NSUInteger)bytesRead]; 634 | if (outputStream.streamError || bytesWritten < 0) { 635 | error = outputStream.streamError; 636 | break; 637 | } 638 | 639 | if (bytesRead == 0 && bytesWritten == 0) { 640 | break; 641 | } 642 | } 643 | [outputStream close]; 644 | [inputStream close]; 645 | 646 | receipt.progress.totalUnitCount = receipt.totalBytesExpectedToWrite; 647 | receipt.progress.completedUnitCount = receipt.totalBytesWritten; 648 | 649 | dispatch_async(dispatch_get_main_queue(), ^{ 650 | if (receipt.progressBlock) { 651 | receipt.progressBlock(receipt.progress,receipt); 652 | } 653 | }); 654 | }); 655 | 656 | } 657 | 658 | - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error 659 | { 660 | MCDownloadReceipt *receipt = [self downloadReceiptForURL:task.taskDescription]; 661 | 662 | if (error) { 663 | receipt.state = MCDownloadStateFailed; 664 | dispatch_async(dispatch_get_main_queue(), ^{ 665 | if (receipt.failureBlock) { 666 | receipt.failureBlock(task.originalRequest,(NSHTTPURLResponse *)task.response,error); 667 | } 668 | }); 669 | }else { 670 | [receipt.stream close]; 671 | receipt.stream = nil; 672 | receipt.state = MCDownloadStateCompleted; 673 | dispatch_async(dispatch_get_main_queue(), ^{ 674 | if (receipt.successBlock) { 675 | receipt.successBlock(task.originalRequest,(NSHTTPURLResponse *)task.response,task.originalRequest.URL); 676 | } 677 | }); 678 | } 679 | 680 | [self saveReceipts:self.allDownloadReceipts]; 681 | [self safelyDecrementActiveTaskCount]; 682 | [self safelyStartNextTaskIfNecessary]; 683 | 684 | } 685 | 686 | - (NSString*)formatByteCount:(long long)size 687 | { 688 | return [NSByteCountFormatter stringFromByteCount:size countStyle:NSByteCountFormatterCountStyleFile]; 689 | } 690 | @end 691 | -------------------------------------------------------------------------------- /MCDownloadManager/Networking/MCURLRequest.h: -------------------------------------------------------------------------------- 1 | // 2 | // MCURLRequest.h 3 | // MCDownloadManager 4 | // 5 | // Created by 马超 on 16/9/23. 6 | // Copyright © 2016年 qikeyun. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "MCURLSessionConfiguration.h" 11 | #import "MCURLResponse.h" 12 | 13 | NS_ASSUME_NONNULL_BEGIN 14 | 15 | @class MCURLRequest; 16 | @protocol MCURLRequestDelegate 17 | @optional 18 | - (void)URLRequest:(MCURLRequest *)request didCompleteWithResponse:(MCURLResponse *)response; 19 | @end 20 | 21 | 22 | typedef NS_ENUM(NSUInteger, MCHTTPMethod) { 23 | MCHTTPMethodGET, 24 | MCHTTPMethodPOST, 25 | MCHTTPMethodPUT, 26 | MCHTTPMethodHEAD, 27 | MCHTTPMethodPATCH, 28 | MCHTTPMethodDELETE 29 | }; 30 | //这个类是对请求的封装,在实际发出请求之前,按照设计,都在这个类处理 31 | /** 32 | * 设计的过程是 写请求(包括配置) -> 发请求 -> 得到相应(数据) 33 | */ 34 | @interface MCURLRequest : NSObject 35 | 36 | ///--------------------------------------- 37 | /// Initialization 38 | ///--------------------------------------- 39 | 40 | /* 41 | * Customization of MCURLRequest occurs during creation of a new URLRequest. 42 | * If you only need to use the convenience routines with custom 43 | * configuration options it is not necessary to specify a delegate. 44 | * If you do specify a delegate, the delegate will be retained until after 45 | * the delegate has been sent the URLSession:didBecomeInvalidWithError: message. 46 | 这里需要调用afn的didBecomeInvalidWithError 然后释放delegate 47 | */ 48 | + (instancetype)URLRequestWithConfiguration:(MCURLSessionConfiguration *)configuration; 49 | + (instancetype)URLRequestWithConfiguration:(MCURLSessionConfiguration *)configuration delegate:(nullable id )delegate delegateQueue:(nullable NSOperationQueue *)queue; 50 | 51 | @property (nonatomic, readonly, retain) NSOperationQueue *delegateQueue; 52 | @property (nonatomic, nullable, retain) id delegate; 53 | @property (nonatomic, copy) MCURLSessionConfiguration *configuration; 54 | 55 | ///--------------------------------------- 56 | /// Parameters 57 | ///--------------------------------------- 58 | // 参数,有字典,url,, nsdate ,流, 反正式afn提供的。 59 | @property (nonatomic, copy, nullable) NSString *url; 60 | @property (nonatomic, copy, nullable) NSDictionary *parameterDict; 61 | @property (nonatomic, assign) MCHTTPMethod HTTPMethod; 62 | @property (nonatomic, assign, getter=isCacheResponse) BOOL cacheResponse; 63 | 64 | // 跟上传相关 65 | @property (nonatomic, strong, nullable) NSData *data; 66 | @property (nonatomic, copy, nullable) NSString *fileURL; 67 | @property (nonatomic, strong, nullable) NSInputStream *inputStream; 68 | 69 | @property (nonatomic, copy, nullable) NSString *fileName; 70 | @property (nonatomic, copy, nullable) NSString *name; 71 | @property (nonatomic, copy, nullable) NSString *mimeType; 72 | @property (nonatomic, assign) int64_t length; 73 | 74 | 75 | 76 | ///--------------------------------------- 77 | /// Load Datas 78 | ///--------------------------------------- 79 | 80 | - (void)fetchDataWithMethod:(MCHTTPMethod)method completionHandler:(void (^)(MCURLResponse *response))handler; 81 | - (void)fetchDataWithMethod:(MCHTTPMethod)method progress:(nullable void (^)(NSProgress *downloadProgress))downloadProgress completionHandler:(void (^)(MCURLResponse *response))handler; 82 | 83 | ///--------------------------------------- 84 | /// Upload Datas 85 | ///--------------------------------------- 86 | - (void)uploadDataWithCompletionHandler:(void (^)(MCURLResponse *response))handler; 87 | - (void)uploadDataWithProgress:(nullable void (^)(NSProgress *uploadProgress))uploadProgress completionHandler:(void (^)(MCURLResponse *response))handler; 88 | @end 89 | 90 | NS_ASSUME_NONNULL_END -------------------------------------------------------------------------------- /MCDownloadManager/Networking/MCURLRequest.m: -------------------------------------------------------------------------------- 1 | // 2 | // MCURLRequest.m 3 | // MCDownloadManager 4 | // 5 | // Created by 马超 on 16/9/23. 6 | // Copyright © 2016年 qikeyun. All rights reserved. 7 | // 8 | 9 | #import "MCURLRequest.h" 10 | 11 | @interface MCURLRequest () 12 | @property (nonatomic, retain) NSOperationQueue *delegateQueue; 13 | 14 | @end 15 | @implementation MCURLRequest 16 | 17 | #pragma mark - Initialization 18 | - (instancetype)init { 19 | self = [super init]; 20 | if (self == nil) { 21 | return nil; 22 | } 23 | self.HTTPMethod = MCHTTPMethodGET; 24 | self.cacheResponse = NO; 25 | 26 | MCURLSessionConfiguration *configuration = [MCURLSessionConfiguration defaultURLSessionConfiguration]; 27 | self.configuration = configuration; 28 | 29 | self.delegateQueue = [[NSOperationQueue alloc] init]; 30 | 31 | return self; 32 | } 33 | 34 | + (instancetype)URLRequestWithConfiguration:(MCURLSessionConfiguration *)configuration { 35 | 36 | MCURLRequest *request = [self init]; 37 | if (configuration) { 38 | request.configuration = configuration; 39 | } 40 | return request; 41 | } 42 | 43 | +(instancetype)URLRequestWithConfiguration:(MCURLSessionConfiguration *)configuration delegate:(id)delegate delegateQueue:(NSOperationQueue *)queue { 44 | 45 | MCURLRequest *request = [self init]; 46 | if (configuration) { 47 | request.configuration = configuration; 48 | } 49 | if (queue) { 50 | request.delegateQueue = queue; 51 | } 52 | return request; 53 | } 54 | 55 | #pragma mark - Public Methods 56 | - (void)fetchDataWithMethod:(MCHTTPMethod)method completionHandler:(void (^)(MCURLResponse * _Nonnull))handler { 57 | 58 | } 59 | - (void)fetchDataWithMethod:(MCHTTPMethod)method progress:(void (^)(NSProgress * _Nonnull))downloadProgress completionHandler:(void (^)(MCURLResponse * _Nonnull))handler { 60 | 61 | } 62 | 63 | - (void)uploadDataWithCompletionHandler:(void (^)(MCURLResponse * _Nonnull))handler { 64 | 65 | } 66 | - (void)uploadDataWithProgress:(void (^)(NSProgress * _Nonnull))uploadProgress completionHandler:(void (^)(MCURLResponse * _Nonnull))handler { 67 | 68 | } 69 | @end 70 | -------------------------------------------------------------------------------- /MCDownloadManager/Networking/MCURLRequestCenter.h: -------------------------------------------------------------------------------- 1 | // 2 | // MCURLRequestCenter.h 3 | // MCDownloadManager 4 | // 5 | // Created by 马超 on 16/9/30. 6 | // Copyright © 2016年 qikeyun. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface MCURLRequestCenter : NSObject 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /MCDownloadManager/Networking/MCURLRequestCenter.m: -------------------------------------------------------------------------------- 1 | // 2 | // MCURLRequestCenter.m 3 | // MCDownloadManager 4 | // 5 | // Created by 马超 on 16/9/30. 6 | // Copyright © 2016年 qikeyun. All rights reserved. 7 | // 8 | 9 | #import "MCURLRequestCenter.h" 10 | 11 | @implementation MCURLRequestCenter 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /MCDownloadManager/Networking/MCURLResponse.h: -------------------------------------------------------------------------------- 1 | // 2 | // MCURLResponse.h 3 | // MCDownloadManager 4 | // 5 | // Created by 马超 on 16/9/21. 6 | // Copyright © 2016年 qikeyun. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | typedef NS_ENUM(NSUInteger, MCURLResponseStatus) { 14 | MCURLResponseStatusNone, 15 | MCURLResponseStatusSuccess, // 成功 16 | MCURLResponseStatusDataInvalid, // 请求成功,但服务器返回的数据不正确 17 | MCURLResponseStatusParameterInvalid, // 参数错误,不会发请求 18 | MCURLResponseStatusTimeout, // 请求超时 19 | MCURLResponseStatusNetworkNotReachable // 网络不可达,这个会在发请求之前检测网络是不是可达的 20 | }; 21 | 22 | // 需要一个把结果加压成何种数据的说明 23 | @interface MCURLResponse : NSObject 24 | 25 | // 响应的所有封装的数据,这里能拿到我们需要的最原始的数据 26 | // 这里如果出错,最好能告诉用户出错的原因。 27 | 28 | @property (nonatomic, assign) MCURLResponseStatus status; 29 | @property (nonatomic, copy, readonly, nullable) id responseObject; 30 | @property (nonatomic, copy, readonly) NSDictionary *requestParameter; // 这里封装的应该是请求封装,请求封装中能够拿到必要的配置信息, 31 | @property (nonatomic, assign, readonly, getter=isCache) BOOL cache; 32 | @property (nonatomic, copy, nullable) NSString *URLIdentifier; 33 | @property (nonatomic, strong, readonly, nullable) NSURLSessionDataTask *task; 34 | @property (nonatomic, strong, readonly, nullable) NSError *error; 35 | 36 | //对于响应来说,初始化方法,有多少个完全取决于第三方网络框架提供的获取数据成功或失败后返回的数据 37 | 38 | - (instancetype)init; 39 | 40 | - (instancetype)initWithURLSessionDataTask:(NSURLSessionDataTask * _Nullable)task responseObject:(id _Nullable)responseObject; 41 | 42 | - (instancetype)initWithURLSessionDataTask:(NSURLSessionDataTask * _Nullable)task error:(NSError * _Nullable)error; 43 | 44 | - (instancetype)initWithURLSessionDataTask:(NSURLSessionDataTask * _Nullable)task responseObject:(id _Nullable)responseObject error:(NSError * _Nullable)error; 45 | @end 46 | 47 | NS_ASSUME_NONNULL_END -------------------------------------------------------------------------------- /MCDownloadManager/Networking/MCURLResponse.m: -------------------------------------------------------------------------------- 1 | // 2 | // MCURLResponse.m 3 | // MCDownloadManager 4 | // 5 | // Created by 马超 on 16/9/21. 6 | // Copyright © 2016年 qikeyun. All rights reserved. 7 | // 8 | 9 | #import "MCURLResponse.h" 10 | 11 | @interface MCURLResponse() 12 | @property (nonatomic, copy, readwrite, nullable) id responseObject; 13 | @property (nonatomic, copy, readwrite) NSDictionary *requestParameter; // 这里封装的应该是请求封装,请求封装中能够拿到必要的配置信息, 14 | @property (nonatomic, assign, readwrite, getter=isCache) BOOL cache; 15 | @property (nonatomic, strong, readwrite, nullable) NSURLSessionDataTask *task; 16 | @property (nonatomic, strong, readwrite, nullable) NSError *error; 17 | @end 18 | 19 | @implementation MCURLResponse 20 | 21 | - (instancetype)init { 22 | self = [super init]; 23 | if (!self) { 24 | return nil; 25 | } 26 | self.status = MCURLResponseStatusNone; 27 | return self; 28 | } 29 | 30 | - (instancetype)initWithURLSessionDataTask:(NSURLSessionDataTask *)task responseObject:(id)responseObject { 31 | return [self initWithURLSessionDataTask:task responseObject:responseObject error:nil]; 32 | } 33 | 34 | - (instancetype)initWithURLSessionDataTask:(NSURLSessionDataTask *)task error:(NSError *)error { 35 | return [self initWithURLSessionDataTask:task responseObject:nil error:error]; 36 | } 37 | 38 | - (instancetype)initWithURLSessionDataTask:(NSURLSessionDataTask *)task responseObject:(id)responseObject error:(NSError *)error { 39 | self = [super init]; 40 | if (!self) { 41 | return nil; 42 | } 43 | 44 | self.status = MCURLResponseStatusNone; 45 | if (error) { 46 | self.error = error; 47 | if (error.code == -1001) { 48 | self.status = MCURLResponseStatusTimeout; 49 | } 50 | } 51 | 52 | if (!responseObject) { 53 | self.status = MCURLResponseStatusDataInvalid; 54 | } 55 | 56 | if (task) { 57 | self.task = task; 58 | self.URLIdentifier = task.originalRequest.URL.absoluteString; 59 | } 60 | 61 | self.responseObject = responseObject; 62 | 63 | return self; 64 | } 65 | @end 66 | -------------------------------------------------------------------------------- /MCDownloadManager/Networking/MCURLSessionConfiguration.h: -------------------------------------------------------------------------------- 1 | // 2 | // MCURLSessionConfiguration.h 3 | // MCDownloadManager 4 | // 5 | // Created by 马超 on 16/9/23. 6 | // Copyright © 2016年 qikeyun. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface MCURLSessionConfiguration : NSObject 14 | + (MCURLSessionConfiguration *)defaultURLSessionConfiguration; 15 | + (MCURLSessionConfiguration *)ephemeralURLSessionConfiguration; 16 | + (MCURLSessionConfiguration *)backgroundURLSessionConfigurationWithIdentifier:(NSString *)identifier; 17 | @end 18 | 19 | NS_ASSUME_NONNULL_END -------------------------------------------------------------------------------- /MCDownloadManager/Networking/MCURLSessionConfiguration.m: -------------------------------------------------------------------------------- 1 | // 2 | // MCURLSessionConfiguration.m 3 | // MCDownloadManager 4 | // 5 | // Created by 马超 on 16/9/23. 6 | // Copyright © 2016年 qikeyun. All rights reserved. 7 | // 8 | 9 | #import "MCURLSessionConfiguration.h" 10 | 11 | @implementation MCURLSessionConfiguration 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /MCDownloadManager/Networking/MCWiFiManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // MCWiFiManager.h 3 | // MCDownloadManager 4 | // 5 | // Created by 马超 on 16/9/14. 6 | // Copyright © 2016年 qikeyun. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface MCWiFi : NSObject 14 | @property (nonatomic, copy, readonly, nullable)NSString *wifiName; 15 | @property (nonatomic, copy, readonly, nullable)NSString *wifiBSSID; 16 | 17 | - (instancetype)initWithName:(NSString *)name BSSID:(NSString *)bssid; 18 | @end 19 | 20 | 21 | @interface MCWiFiManager : NSObject 22 | 23 | /** 24 | The shared default instance of `MCWiFiManager` initialized with default values. 25 | */ 26 | + (instancetype)defaultInstance; 27 | 28 | /** 29 | Default initializer 30 | 31 | @return An instance of `MCWiFiManager` initialized with default values. 32 | */ 33 | - (instancetype)init; 34 | 35 | 36 | - (void)scanNetworksWithCompletionHandler:(void(^_Nullable)(NSArray * _Nullable networks, MCWiFi *_Nullable currentWiFi, NSError *_Nullable error))handler; 37 | 38 | 39 | - (NSString *)getGatewayIpForCurrentWiFi; 40 | 41 | /** 42 | * Get the local info for currentWifi except for GatewayIp 43 | * 44 | * @return NSDictionary 45 | * { 46 | broadcast = "192.168.8.233"; 47 | interface = en0; 48 | localIp = "192.168.5.140"; 49 | netmask = "255.255.255.0"; 50 | } 51 | */ 52 | - (NSDictionary *)getLocalInfoForCurrentWiFi; 53 | @end 54 | 55 | NS_ASSUME_NONNULL_END -------------------------------------------------------------------------------- /MCDownloadManager/Networking/MCWiFiManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // MCWiFiManager.m 3 | // MCDownloadManager 4 | // 5 | // Created by 马超 on 16/9/14. 6 | // Copyright © 2016年 qikeyun. All rights reserved. 7 | // 8 | 9 | 10 | 11 | #import "MCWiFiManager.h" 12 | #import 13 | #import 14 | #import 15 | #import 16 | #import 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | 24 | 25 | /* 26 | * Copyright (c) 2000-2008 Apple Inc. All rights reserved. 27 | * 28 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 29 | * 30 | * This file contains Original Code and/or Modifications of Original Code 31 | * as defined in and that are subject to the Apple Public Source License 32 | * Version 2.0 (the 'License'). You may not use this file except in 33 | * compliance with the License. The rights granted to you under the License 34 | * may not be used to create, or enable the creation or redistribution of, 35 | * unlawful or unlicensed copies of an Apple operating system, or to 36 | * circumvent, violate, or enable the circumvention or violation of, any 37 | * terms of an Apple operating system software license agreement. 38 | * 39 | * Please obtain a copy of the License at 40 | * http://www.opensource.apple.com/apsl/ and read it before using this file. 41 | * 42 | * The Original Code and all software distributed under the License are 43 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 44 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 45 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 46 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 47 | * Please see the License for the specific language governing rights and 48 | * limitations under the License. 49 | * 50 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 51 | */ 52 | /* 53 | * Copyright (c) 1980, 1986, 1993 54 | * The Regents of the University of California. All rights reserved. 55 | * 56 | * Redistribution and use in source and binary forms, with or without 57 | * modification, are permitted provided that the following conditions 58 | * are met: 59 | * 1. Redistributions of source code must retain the above copyright 60 | * notice, this list of conditions and the following disclaimer. 61 | * 2. Redistributions in binary form must reproduce the above copyright 62 | * notice, this list of conditions and the following disclaimer in the 63 | * documentation and/or other materials provided with the distribution. 64 | * 3. All advertising materials mentioning features or use of this software 65 | * must display the following acknowledgement: 66 | * This product includes software developed by the University of 67 | * California, Berkeley and its contributors. 68 | * 4. Neither the name of the University nor the names of its contributors 69 | * may be used to endorse or promote products derived from this software 70 | * without specific prior written permission. 71 | * 72 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 73 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 74 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 75 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 76 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 77 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 78 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 79 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 80 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 81 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 82 | * SUCH DAMAGE. 83 | * 84 | * @(#)route.h 8.3 (Berkeley) 4/19/94 85 | * $FreeBSD: src/sys/net/route.h,v 1.36.2.1 2000/08/16 06:14:23 jayanth Exp $ 86 | */ 87 | #ifndef TARGET_IPHONE_SIMULATOR 88 | 89 | #ifndef _NET_ROUTE_H_ 90 | #define _NET_ROUTE_H_ 91 | #include 92 | #include 93 | #include 94 | #include 95 | 96 | /* 97 | * Kernel resident routing tables. 98 | * 99 | * The routing tables are initialized when interface addresses 100 | * are set by making entries for all directly connected interfaces. 101 | */ 102 | 103 | /* 104 | * A route consists of a destination address and a reference 105 | * to a routing entry. These are often held by protocols 106 | * in their control blocks, e.g. inpcb. 107 | */ 108 | struct route; 109 | 110 | 111 | /* 112 | * These numbers are used by reliable protocols for determining 113 | * retransmission behavior and are included in the routing structure. 114 | */ 115 | struct rt_metrics { 116 | u_int32_t rmx_locks; /* Kernel must leave these values alone */ 117 | u_int32_t rmx_mtu; /* MTU for this path */ 118 | u_int32_t rmx_hopcount; /* max hops expected */ 119 | int32_t rmx_expire; /* lifetime for route, e.g. redirect */ 120 | u_int32_t rmx_recvpipe; /* inbound delay-bandwidth product */ 121 | u_int32_t rmx_sendpipe; /* outbound delay-bandwidth product */ 122 | u_int32_t rmx_ssthresh; /* outbound gateway buffer limit */ 123 | u_int32_t rmx_rtt; /* estimated round trip time */ 124 | u_int32_t rmx_rttvar; /* estimated rtt variance */ 125 | u_int32_t rmx_pksent; /* packets sent using this route */ 126 | u_int32_t rmx_filler[4]; /* will be used for T/TCP later */ 127 | }; 128 | 129 | 130 | 131 | /* 132 | * rmx_rtt and rmx_rttvar are stored as microseconds; 133 | */ 134 | #define RTM_RTTUNIT 1000000 /* units for rtt, rttvar, as units per sec */ 135 | 136 | /* 137 | * We distinguish between routes to hosts and routes to networks, 138 | * preferring the former if available. For each route we infer 139 | * the interface to use from the gateway address supplied when 140 | * the route was entered. Routes that forward packets through 141 | * gateways are marked so that the output routines know to address the 142 | * gateway rather than the ultimate destination. 143 | */ 144 | 145 | 146 | #define RTF_UP 0x1 /* route usable */ 147 | #define RTF_GATEWAY 0x2 /* destination is a gateway */ 148 | #define RTF_HOST 0x4 /* host entry (net otherwise) */ 149 | #define RTF_REJECT 0x8 /* host or net unreachable */ 150 | #define RTF_DYNAMIC 0x10 /* created dynamically (by redirect) */ 151 | #define RTF_MODIFIED 0x20 /* modified dynamically (by redirect) */ 152 | #define RTF_DONE 0x40 /* message confirmed */ 153 | #define RTF_DELCLONE 0x80 /* delete cloned route */ 154 | #define RTF_CLONING 0x100 /* generate new routes on use */ 155 | #define RTF_XRESOLVE 0x200 /* external daemon resolves name */ 156 | #define RTF_LLINFO 0x400 /* generated by link layer (e.g. ARP) */ 157 | #define RTF_STATIC 0x800 /* manually added */ 158 | #define RTF_BLACKHOLE 0x1000 /* just discard pkts (during updates) */ 159 | #define RTF_PROTO2 0x4000 /* protocol specific routing flag */ 160 | #define RTF_PROTO1 0x8000 /* protocol specific routing flag */ 161 | 162 | #define RTF_PRCLONING 0x10000 /* protocol requires cloning */ 163 | #define RTF_WASCLONED 0x20000 /* route generated through cloning */ 164 | #define RTF_PROTO3 0x40000 /* protocol specific routing flag */ 165 | /* 0x80000 unused */ 166 | #define RTF_PINNED 0x100000 /* future use */ 167 | #define RTF_LOCAL 0x200000 /* route represents a local address */ 168 | #define RTF_BROADCAST 0x400000 /* route represents a bcast address */ 169 | #define RTF_MULTICAST 0x800000 /* route represents a mcast address */ 170 | #define RTF_IFSCOPE 0x1000000 /* has valid interface scope */ 171 | #define RTF_CONDEMNED 0x2000000 /* defunct; no longer modifiable */ 172 | /* 0x4000000 and up unassigned */ 173 | 174 | /* 175 | * Routing statistics. 176 | */ 177 | struct rtstat { 178 | short rts_badredirect; /* bogus redirect calls */ 179 | short rts_dynamic; /* routes created by redirects */ 180 | short rts_newgateway; /* routes modified by redirects */ 181 | short rts_unreach; /* lookups which failed */ 182 | short rts_wildcard; /* lookups satisfied by a wildcard */ 183 | }; 184 | 185 | /* 186 | * Structures for routing messages. 187 | */ 188 | struct rt_msghdr { 189 | u_short rtm_msglen; /* to skip over non-understood messages */ 190 | u_char rtm_version; /* future binary compatibility */ 191 | u_char rtm_type; /* message type */ 192 | u_short rtm_index; /* index for associated ifp */ 193 | int rtm_flags; /* flags, incl. kern & message, e.g. DONE */ 194 | int rtm_addrs; /* bitmask identifying sockaddrs in msg */ 195 | pid_t rtm_pid; /* identify sender */ 196 | int rtm_seq; /* for sender to identify action */ 197 | int rtm_errno; /* why failed */ 198 | int rtm_use; /* from rtentry */ 199 | u_int32_t rtm_inits; /* which metrics we are initializing */ 200 | struct rt_metrics rtm_rmx; /* metrics themselves */ 201 | }; 202 | 203 | struct rt_msghdr2 { 204 | u_short rtm_msglen; /* to skip over non-understood messages */ 205 | u_char rtm_version; /* future binary compatibility */ 206 | u_char rtm_type; /* message type */ 207 | u_short rtm_index; /* index for associated ifp */ 208 | int rtm_flags; /* flags, incl. kern & message, e.g. DONE */ 209 | int rtm_addrs; /* bitmask identifying sockaddrs in msg */ 210 | int32_t rtm_refcnt; /* reference count */ 211 | int rtm_parentflags; /* flags of the parent route */ 212 | int rtm_reserved; /* reserved field set to 0 */ 213 | int rtm_use; /* from rtentry */ 214 | u_int32_t rtm_inits; /* which metrics we are initializing */ 215 | struct rt_metrics rtm_rmx; /* metrics themselves */ 216 | }; 217 | 218 | 219 | #define RTM_VERSION 5 /* Up the ante and ignore older versions */ 220 | 221 | /* 222 | * Message types. 223 | */ 224 | #define RTM_ADD 0x1 /* Add Route */ 225 | #define RTM_DELETE 0x2 /* Delete Route */ 226 | #define RTM_CHANGE 0x3 /* Change Metrics or flags */ 227 | #define RTM_GET 0x4 /* Report Metrics */ 228 | #define RTM_LOSING 0x5 /* Kernel Suspects Partitioning */ 229 | #define RTM_REDIRECT 0x6 /* Told to use different route */ 230 | #define RTM_MISS 0x7 /* Lookup failed on this address */ 231 | #define RTM_LOCK 0x8 /* fix specified metrics */ 232 | #define RTM_OLDADD 0x9 /* caused by SIOCADDRT */ 233 | #define RTM_OLDDEL 0xa /* caused by SIOCDELRT */ 234 | #define RTM_RESOLVE 0xb /* req to resolve dst to LL addr */ 235 | #define RTM_NEWADDR 0xc /* address being added to iface */ 236 | #define RTM_DELADDR 0xd /* address being removed from iface */ 237 | #define RTM_IFINFO 0xe /* iface going up/down etc. */ 238 | #define RTM_NEWMADDR 0xf /* mcast group membership being added to if */ 239 | #define RTM_DELMADDR 0x10 /* mcast group membership being deleted */ 240 | #define RTM_IFINFO2 0x12 /* */ 241 | #define RTM_NEWMADDR2 0x13 /* */ 242 | #define RTM_GET2 0x14 /* */ 243 | 244 | /* 245 | * Bitmask values for rtm_inits and rmx_locks. 246 | */ 247 | #define RTV_MTU 0x1 /* init or lock _mtu */ 248 | #define RTV_HOPCOUNT 0x2 /* init or lock _hopcount */ 249 | #define RTV_EXPIRE 0x4 /* init or lock _expire */ 250 | #define RTV_RPIPE 0x8 /* init or lock _recvpipe */ 251 | #define RTV_SPIPE 0x10 /* init or lock _sendpipe */ 252 | #define RTV_SSTHRESH 0x20 /* init or lock _ssthresh */ 253 | #define RTV_RTT 0x40 /* init or lock _rtt */ 254 | #define RTV_RTTVAR 0x80 /* init or lock _rttvar */ 255 | 256 | /* 257 | * Bitmask values for rtm_addrs. 258 | */ 259 | #define RTA_DST 0x1 /* destination sockaddr present */ 260 | #define RTA_GATEWAY 0x2 /* gateway sockaddr present */ 261 | #define RTA_NETMASK 0x4 /* netmask sockaddr present */ 262 | #define RTA_GENMASK 0x8 /* cloning mask sockaddr present */ 263 | #define RTA_IFP 0x10 /* interface name sockaddr present */ 264 | #define RTA_IFA 0x20 /* interface addr sockaddr present */ 265 | #define RTA_AUTHOR 0x40 /* sockaddr for author of redirect */ 266 | #define RTA_BRD 0x80 /* for NEWADDR, broadcast or p-p dest addr */ 267 | 268 | /* 269 | * Index offsets for sockaddr array for alternate internal encoding. 270 | */ 271 | #define RTAX_DST 0 /* destination sockaddr present */ 272 | #define RTAX_GATEWAY 1 /* gateway sockaddr present */ 273 | #define RTAX_NETMASK 2 /* netmask sockaddr present */ 274 | #define RTAX_GENMASK 3 /* cloning mask sockaddr present */ 275 | #define RTAX_IFP 4 /* interface name sockaddr present */ 276 | #define RTAX_IFA 5 /* interface addr sockaddr present */ 277 | #define RTAX_AUTHOR 6 /* sockaddr for author of redirect */ 278 | #define RTAX_BRD 7 /* for NEWADDR, broadcast or p-p dest addr */ 279 | #define RTAX_MAX 8 /* size of array to allocate */ 280 | 281 | struct rt_addrinfo { 282 | int rti_addrs; 283 | struct sockaddr *rti_info[RTAX_MAX]; 284 | }; 285 | 286 | struct route_cb { 287 | int ip_count; 288 | int ip6_count; 289 | int ipx_count; 290 | int ns_count; 291 | int iso_count; 292 | int any_count; 293 | }; 294 | 295 | 296 | 297 | #endif 298 | 299 | 300 | 301 | #define CTL_NET 4 /* network, see socket.h */ 302 | 303 | 304 | #if defined(BSD) || defined(__APPLE__) 305 | 306 | #define ROUNDUP(a) \ 307 | ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 308 | 309 | char * getdefaultgateway(in_addr_t * addr) 310 | { 311 | #if 0 312 | /* net.route.0.inet.dump.0.0 ? */ 313 | int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, 314 | NET_RT_DUMP, 0, 0/*tableid*/}; 315 | #endif 316 | /* net.route.0.inet.flags.gateway */ 317 | int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, 318 | NET_RT_FLAGS, RTF_GATEWAY}; 319 | size_t l; 320 | char * buf, * p; 321 | struct rt_msghdr * rt; 322 | struct sockaddr * sa; 323 | struct sockaddr * sa_tab[RTAX_MAX]; 324 | int i; 325 | int r = -1; 326 | static char tmp[20]; 327 | 328 | #if TARGET_OS_IPHONE 329 | if(sysctl(mib, sizeof(mib)/sizeof(int), 0, &l, 0, 0) < 0) { 330 | return tmp; 331 | } 332 | 333 | if(l>0) { 334 | buf = malloc(l); 335 | 336 | if(sysctl(mib, sizeof(mib)/sizeof(int), buf, &l, 0, 0) < 0) { 337 | return tmp; 338 | } 339 | 340 | for(p=buf; prtm_msglen) { 341 | rt = (struct rt_msghdr *)p; 342 | sa = (struct sockaddr *)(rt + 1); 343 | for(i=0; irtm_addrs & (1 << i)) { 345 | sa_tab[i] = sa; 346 | sa = (struct sockaddr *)((char *)sa + ROUNDUP(sa->sa_len)); 347 | } else { 348 | sa_tab[i] = NULL; 349 | } 350 | } 351 | 352 | if( ((rt->rtm_addrs & (RTA_DST|RTA_GATEWAY)) == (RTA_DST|RTA_GATEWAY)) 353 | && sa_tab[RTAX_DST]->sa_family == AF_INET 354 | && sa_tab[RTAX_GATEWAY]->sa_family == AF_INET) { 355 | 356 | unsigned char octet[4] = {0,0,0,0}; 357 | for (int i=0; i<4; i++){ 358 | octet[i] = ( ((struct sockaddr_in *)(sa_tab[RTAX_GATEWAY]))->sin_addr.s_addr >> (i*8) ) & 0xFF; 359 | } 360 | 361 | if(((struct sockaddr_in *)sa_tab[RTAX_DST])->sin_addr.s_addr == 0) { 362 | 363 | *addr = ((struct sockaddr_in *)(sa_tab[RTAX_GATEWAY]))->sin_addr.s_addr; 364 | r = 0; 365 | sprintf(tmp,"%d.%d.%d.%d",octet[0],octet[1],octet[2],octet[3]); 366 | printf("gateway : %s\n",tmp); 367 | printf("gateway address--%d.%d.%d.%d\n",octet[0],octet[1],octet[2],octet[3]); 368 | } 369 | } 370 | } 371 | free(buf); 372 | } 373 | 374 | #endif 375 | return tmp; 376 | } 377 | 378 | #endif 379 | #endif 380 | 381 | 382 | @implementation MCWiFi 383 | 384 | - (instancetype)initWithName:(NSString *)name BSSID:(NSString *)bssid { 385 | 386 | if (self = [super init]) { 387 | 388 | _wifiName = name; 389 | _wifiBSSID = bssid; 390 | } 391 | return self; 392 | } 393 | 394 | @end 395 | 396 | 397 | #pragma mark - 398 | 399 | @implementation MCWiFiManager 400 | 401 | - (instancetype)init { 402 | 403 | if (self = [super init]) { 404 | 405 | } 406 | return self; 407 | } 408 | 409 | + (instancetype)defaultInstance { 410 | static MCWiFiManager *sharedInstance = nil; 411 | static dispatch_once_t onceToken; 412 | dispatch_once(&onceToken, ^{ 413 | sharedInstance = [[self alloc] init]; 414 | }); 415 | return sharedInstance; 416 | } 417 | 418 | 419 | #pragma mark - 420 | - (void)scanNetworksWithCompletionHandler:(void (^)(NSArray * _Nullable, MCWiFi * _Nullable, NSError * _Nullable))handler { 421 | 422 | NSString *wifiName = @"Not Found"; 423 | NSString *wifiBSSID = @"Not Found"; 424 | CFArrayRef myArray = CNCopySupportedInterfaces(); 425 | if (myArray != nil) { 426 | for (int i = 0; i < CFArrayGetCount(myArray); i++) { 427 | CFStringRef strRef = CFArrayGetValueAtIndex(myArray, i); 428 | CFDictionaryRef myDict = CNCopyCurrentNetworkInfo(strRef); 429 | if (myDict != nil) { 430 | NSDictionary *dict = (NSDictionary*)CFBridgingRelease(myDict); 431 | wifiName = [dict valueForKey:(__bridge NSString *)kCNNetworkInfoKeySSID]; 432 | wifiBSSID = [dict valueForKey:(__bridge NSString *)kCNNetworkInfoKeyBSSID]; 433 | 434 | break; 435 | } 436 | } 437 | 438 | } 439 | 440 | if (myArray) { 441 | CFRelease(myArray); 442 | } 443 | 444 | 445 | MCWiFi *wifi = [[MCWiFi alloc] initWithName:wifiName BSSID:wifiBSSID]; 446 | 447 | if (handler) { 448 | handler(@[wifi], wifi, nil); 449 | } 450 | } 451 | 452 | - (NSString *)getGatewayIpForCurrentWiFi { 453 | NSString *address = @"error"; 454 | struct ifaddrs *interfaces = NULL; 455 | struct ifaddrs *temp_addr = NULL; 456 | int success = 0; 457 | // retrieve the current interfaces - returns 0 on success 458 | success = getifaddrs(&interfaces); 459 | if (success == 0) { 460 | // Loop through linked list of interfaces 461 | temp_addr = interfaces; 462 | //*/ 463 | while(temp_addr != NULL) { 464 | /*/ 465 | int i=255; 466 | while((i--)>0) 467 | //*/ 468 | if(temp_addr->ifa_addr->sa_family == AF_INET) { 469 | // Check if interface is en0 which is the wifi connection on the iPhone 470 | if([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"en0"]) 471 | { 472 | // Get NSString from C String //ifa_addr 473 | //ifa->ifa_dstaddr is the broadcast address, which explains the "255's" 474 | // address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_dstaddr)->sin_addr)]; 475 | address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)]; 476 | 477 | } 478 | } 479 | temp_addr = temp_addr->ifa_next; 480 | } 481 | } 482 | // Free memory 483 | freeifaddrs(interfaces); 484 | 485 | 486 | #ifndef TARGET_IPHONE_SIMULATOR 487 | in_addr_t i = inet_addr([address cStringUsingEncoding:NSUTF8StringEncoding]); 488 | in_addr_t* x = &i; 489 | unsigned char *s = (unsigned char *)getdefaultgateway(x) ; 490 | NSString *ip=[NSString stringWithFormat:@"%d.%d.%d.%d",s[0],s[1],s[2],s[3]]; 491 | return ip; 492 | #endif 493 | return nil; 494 | } 495 | 496 | 497 | 498 | - (NSDictionary *)getLocalInfoForCurrentWiFi { 499 | NSMutableDictionary *dict = [NSMutableDictionary dictionary]; 500 | struct ifaddrs *interfaces = NULL; 501 | struct ifaddrs *temp_addr = NULL; 502 | int success = 0; 503 | // retrieve the current interfaces - returns 0 on success 504 | success = getifaddrs(&interfaces); 505 | if (success == 0) { 506 | // Loop through linked list of interfaces 507 | temp_addr = interfaces; 508 | //*/ 509 | while(temp_addr != NULL) { 510 | if(temp_addr->ifa_addr->sa_family == AF_INET) { 511 | // Check if interface is en0 which is the wifi connection on the iPhone 512 | if([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"en0"]) { 513 | 514 | NSString *broadcast = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_dstaddr)->sin_addr)]; 515 | if (broadcast) { 516 | [dict setObject:broadcast forKey:@"broadcast"]; 517 | } 518 | NSLog(@"broadcast address--%@",broadcast); 519 | 520 | NSString *localIp = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)]; 521 | if (localIp) { 522 | [dict setObject:localIp forKey:@"localIp"]; 523 | } 524 | 525 | NSString *netmask = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_netmask)->sin_addr)]; 526 | if (netmask) { 527 | [dict setObject:netmask forKey:@"netmask"]; 528 | } 529 | 530 | NSString *interface = [NSString stringWithUTF8String:temp_addr->ifa_name]; 531 | if (interface) { 532 | [dict setObject:interface forKey:@"interface"]; 533 | } 534 | return dict; 535 | } 536 | } 537 | temp_addr = temp_addr->ifa_next; 538 | } 539 | } 540 | // Free memory 541 | freeifaddrs(interfaces); 542 | return dict; 543 | } 544 | @end 545 | 546 | 547 | -------------------------------------------------------------------------------- /MCDownloadManager/QKYDelayButton.h: -------------------------------------------------------------------------------- 1 | // 2 | // QKYDelayButton.h 3 | // qikeyun 4 | // 5 | // Created by 马超 on 16/6/4. 6 | // Copyright © 2016年 Jerome. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface QKYDelayButton : UIButton 12 | 13 | @property (nonatomic,assign)NSTimeInterval clickDurationTime; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /MCDownloadManager/QKYDelayButton.m: -------------------------------------------------------------------------------- 1 | // 2 | // QKYDelayButton.m 3 | // qikeyun 4 | // 5 | // Created by 马超 on 16/6/4. 6 | // Copyright © 2016年 Jerome. All rights reserved. 7 | // 8 | 9 | #import "QKYDelayButton.h" 10 | 11 | static NSTimeInterval defaultDuration = 1.0f; 12 | 13 | static BOOL _isIgnoreEvent = NO; 14 | 15 | static void resetState() { 16 | 17 | _isIgnoreEvent = NO; 18 | } 19 | 20 | 21 | @implementation QKYDelayButton 22 | 23 | - (void)sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event 24 | { 25 | if ([self isKindOfClass:[UIButton class]]) { 26 | 27 | self.clickDurationTime = self.clickDurationTime == 0 ? defaultDuration : self.clickDurationTime; 28 | 29 | if (_isIgnoreEvent) { 30 | 31 | return; 32 | } 33 | else if (self.clickDurationTime > 0) { 34 | 35 | _isIgnoreEvent = YES; 36 | 37 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(self.clickDurationTime * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 38 | 39 | resetState(); 40 | }); 41 | 42 | [super sendAction:action to:target forEvent:event]; 43 | } 44 | } 45 | else { 46 | 47 | [super sendAction:action to:target forEvent:event]; 48 | } 49 | } 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /MCDownloadManager/TableViewCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // TableViewCell.h 3 | // MCDownloadManager 4 | // 5 | // Created by 马超 on 16/9/6. 6 | // Copyright © 2016年 qikeyun. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "QKYDelayButton.h" 11 | 12 | @class TableViewCell; 13 | @protocol TableViewCellDelegate 14 | 15 | - (void)cell:(TableViewCell *)cell didClickedBtn:(UIButton *)btn; 16 | 17 | @end 18 | 19 | @interface TableViewCell : UITableViewCell 20 | @property (weak, nonatomic) IBOutlet UIProgressView *progressView; 21 | @property (weak, nonatomic) IBOutlet UILabel *nameLabel; 22 | @property (weak, nonatomic) IBOutlet QKYDelayButton *button; 23 | @property (weak, nonatomic) IBOutlet UILabel *bytesLable; 24 | @property (weak, nonatomic) IBOutlet UILabel *speedLable; 25 | 26 | 27 | @property (nonatomic, weak) id delegate; 28 | @property (nonatomic,copy)NSString *url; 29 | @end 30 | -------------------------------------------------------------------------------- /MCDownloadManager/TableViewCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // TableViewCell.m 3 | // MCDownloadManager 4 | // 5 | // Created by 马超 on 16/9/6. 6 | // Copyright © 2016年 qikeyun. All rights reserved. 7 | // 8 | 9 | #import "TableViewCell.h" 10 | #import "MCDownloadManager.h" 11 | 12 | 13 | 14 | @implementation TableViewCell 15 | 16 | - (void)awakeFromNib { 17 | [super awakeFromNib]; 18 | // Initialization code 19 | 20 | self.button.clipsToBounds = YES; 21 | self.button.layer.cornerRadius = 10; 22 | self.button.layer.borderWidth = 1; 23 | self.button.layer.borderColor = [UIColor orangeColor].CGColor; 24 | [self.button setTitleColor:[UIColor orangeColor] forState:UIControlStateNormal]; 25 | self.button.clickDurationTime = 1.0; 26 | } 27 | 28 | - (void)setSelected:(BOOL)selected animated:(BOOL)animated { 29 | [super setSelected:selected animated:animated]; 30 | 31 | // Configure the view for the selected state 32 | } 33 | 34 | - (void)setUrl:(NSString *)url { 35 | _url = url; 36 | 37 | MCDownloadReceipt *receipt = [[MCDownloadManager defaultInstance] downloadReceiptForURL:url]; 38 | 39 | self.nameLabel.text = receipt.truename; 40 | self.speedLable.text = nil; 41 | self.bytesLable.text = nil; 42 | self.progressView.progress = 0; 43 | 44 | self.progressView.progress = receipt.progress.fractionCompleted; 45 | 46 | if (receipt.state == MCDownloadStateDownloading) { 47 | [self.button setTitle:@"停止" forState:UIControlStateNormal]; 48 | }else if (receipt.state == MCDownloadStateCompleted) { 49 | [self.button setTitle:@"播放" forState:UIControlStateNormal]; 50 | }else { 51 | [self.button setTitle:@"下载" forState:UIControlStateNormal]; 52 | } 53 | 54 | receipt.progressBlock = ^(NSProgress * _Nonnull downloadProgress,MCDownloadReceipt *receipt) { 55 | if ([receipt.url isEqualToString:self.url]) { 56 | self.progressView.progress = downloadProgress.fractionCompleted ; 57 | self.bytesLable.text = [NSString stringWithFormat:@"%0.2fm/%0.2fm", downloadProgress.completedUnitCount/1024.0/1024, downloadProgress.totalUnitCount/1024.0/1024]; 58 | self.speedLable.text = [NSString stringWithFormat:@"%@/s", receipt.speed]; 59 | } 60 | }; 61 | 62 | receipt.successBlock = ^(NSURLRequest * _Nullablerequest, NSHTTPURLResponse * _Nullableresponse, NSURL * _NonnullfilePath) { 63 | [self.button setTitle:@"播放" forState:UIControlStateNormal]; 64 | }; 65 | 66 | receipt.failureBlock = ^(NSURLRequest * _Nullable request, NSHTTPURLResponse * _Nullable response, NSError * _Nonnull error) { 67 | [self.button setTitle:@"下载" forState:UIControlStateNormal]; 68 | }; 69 | 70 | } 71 | - (IBAction)buttonAction:(UIButton *)sender { 72 | 73 | MCDownloadReceipt *receipt = [[MCDownloadManager defaultInstance] downloadReceiptForURL:self.url]; 74 | 75 | if (receipt.state == MCDownloadStateDownloading) { 76 | [self.button setTitle:@"下载" forState:UIControlStateNormal]; 77 | [[MCDownloadManager defaultInstance] suspendWithDownloadReceipt:receipt]; 78 | }else if (receipt.state == MCDownloadStateCompleted) { 79 | 80 | if ([self.delegate respondsToSelector:@selector(cell:didClickedBtn:)]) { 81 | [self.delegate cell:self didClickedBtn:sender]; 82 | } 83 | }else { 84 | [self.button setTitle:@"停止" forState:UIControlStateNormal]; 85 | [self download]; 86 | } 87 | 88 | } 89 | 90 | - (void)download { 91 | [[MCDownloadManager defaultInstance] downloadFileWithURL:self.url 92 | progress:^(NSProgress * _Nonnull downloadProgress, MCDownloadReceipt *receipt) { 93 | 94 | if ([receipt.url isEqualToString:self.url]) { 95 | self.progressView.progress = downloadProgress.fractionCompleted ; 96 | self.bytesLable.text = [NSString stringWithFormat:@"%0.2fm/%0.2fm", downloadProgress.completedUnitCount/1024.0/1024, downloadProgress.totalUnitCount/1024.0/1024]; 97 | self.speedLable.text = [NSString stringWithFormat:@"%@/s", receipt.speed]; 98 | } 99 | 100 | } 101 | destination:nil 102 | success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, NSURL * _Nonnull filePath) { 103 | [self.button setTitle:@"播放" forState:UIControlStateNormal]; 104 | } 105 | failure:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, NSError * _Nonnull error) { 106 | [self.button setTitle:@"下载" forState:UIControlStateNormal]; 107 | }]; 108 | 109 | } 110 | @end 111 | -------------------------------------------------------------------------------- /MCDownloadManager/TestViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // TestViewController.h 3 | // MCDownloadManager 4 | // 5 | // Created by M.C on 17/3/1. 6 | // Copyright © 2017年 qikeyun. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface TestViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /MCDownloadManager/TestViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // TestViewController.m 3 | // MCDownloadManager 4 | // 5 | // Created by M.C on 17/3/1. 6 | // Copyright © 2017年 qikeyun. All rights reserved. 7 | // 8 | 9 | #import "TestViewController.h" 10 | 11 | @interface TestViewController () 12 | 13 | @end 14 | 15 | @implementation TestViewController 16 | 17 | - (void)viewDidLoad { 18 | [super viewDidLoad]; 19 | // Do any additional setup after loading the view. 20 | } 21 | 22 | - (void)didReceiveMemoryWarning { 23 | [super didReceiveMemoryWarning]; 24 | // Dispose of any resources that can be recreated. 25 | } 26 | 27 | /* 28 | #pragma mark - Navigation 29 | 30 | // In a storyboard-based application, you will often want to do a little preparation before navigation 31 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 32 | // Get the new view controller using [segue destinationViewController]. 33 | // Pass the selected object to the new view controller. 34 | } 35 | */ 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /MCDownloadManager/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // MCDownloadManager 4 | // 5 | // Created by 马超 on 16/9/5. 6 | // Copyright © 2016年 qikeyun. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UITableViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /MCDownloadManager/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // MCDownloadManager 4 | // 5 | // Created by 马超 on 16/9/5. 6 | // Copyright © 2016年 qikeyun. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "MCDownloadManager.h" 11 | #import "TableViewCell.h" 12 | #import "MCWiFiManager.h" 13 | #import 14 | #import "TestViewController.h" 15 | 16 | 17 | @interface ViewController () 18 | @property (weak, nonatomic) IBOutlet UILabel *label; 19 | 20 | 21 | 22 | @property (strong, nonatomic) NSMutableArray *urls; 23 | @end 24 | 25 | @implementation ViewController 26 | 27 | - (NSMutableArray *)urls 28 | { 29 | if (!_urls) { 30 | self.urls = [NSMutableArray array]; 31 | for (int i = 1; i<=10; i++) { 32 | [self.urls addObject:[NSString stringWithFormat:@"http://120.25.226.186:32812/resources/videos/minion_%02d.mp4", i]]; 33 | 34 | // [self.urls addObject:@"http://localhost/MJDownload-master.zip"]; 35 | } 36 | } 37 | return _urls; 38 | } 39 | - (void)viewDidLoad { 40 | [super viewDidLoad]; 41 | // Do any additional setup after loading the view, typically from a nib. 42 | self.view.backgroundColor = [UIColor whiteColor]; 43 | 44 | MCWiFiManager *wifiManager = [[MCWiFiManager alloc] init]; 45 | [wifiManager scanNetworksWithCompletionHandler:^(NSArray * _Nullable networks, MCWiFi * _Nullable currentWiFi, NSError * _Nullable error) { 46 | NSLog(@"name:%@ -- mac:%@",currentWiFi.wifiName,currentWiFi.wifiBSSID); 47 | }]; 48 | 49 | NSLog(@"网关:%@",[wifiManager getGatewayIpForCurrentWiFi]); 50 | 51 | } 52 | 53 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 54 | return self.urls.count; 55 | } 56 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 57 | return 100; 58 | } 59 | 60 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 61 | TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath]; 62 | cell.url = self.urls[indexPath.row]; 63 | cell.delegate = self; 64 | return cell; 65 | } 66 | - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { 67 | return YES; 68 | } 69 | - (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath { 70 | return UITableViewCellEditingStyleDelete; 71 | } 72 | - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { 73 | if (editingStyle == UITableViewCellEditingStyleDelete) { 74 | [[MCDownloadManager defaultInstance] removeWithURL:self.urls[indexPath.row]]; 75 | [self.tableView reloadData]; 76 | } 77 | } 78 | 79 | - (IBAction)nextAction:(id)sender { 80 | 81 | TestViewController *vc = [[TestViewController alloc] init]; 82 | [self.navigationController pushViewController:vc animated:YES]; 83 | return; 84 | 85 | NSArray *urls = @[ 86 | @"http://mhpic.taomanhua.com/comic/M%2F%E8%8E%BD%E8%8D%92%E7%BA%AA%2F34%E8%AF%9D%E5%86%8D%E6%88%98%E7%BF%BC%E8%9B%87%E4%BA%8C%2F1.jpg", 87 | @"http://mhpic.taomanhua.com/comic/M%2F%E8%8E%BD%E8%8D%92%E7%BA%AA%2F34%E8%AF%9D%E5%86%8D%E6%88%98%E7%BF%BC%E8%9B%87%E4%BA%8C%2F2.jpg", 88 | @"http://mhpic.taomanhua.com/comic/M%2F%E8%8E%BD%E8%8D%92%E7%BA%AA%2F34%E8%AF%9D%E5%86%8D%E6%88%98%E7%BF%BC%E8%9B%87%E4%BA%8C%2F3.jpg", 89 | @"http://mhpic.taomanhua.com/comic/M%2F%E8%8E%BD%E8%8D%92%E7%BA%AA%2F34%E8%AF%9D%E5%86%8D%E6%88%98%E7%BF%BC%E8%9B%87%E4%BA%8C%2F4.jpg", 90 | @"http://mhpic.taomanhua.com/comic/M%2F%E8%8E%BD%E8%8D%92%E7%BA%AA%2F34%E8%AF%9D%E5%86%8D%E6%88%98%E7%BF%BC%E8%9B%87%E4%BA%8C%2F5.jpg", 91 | @"http://mhpic.taomanhua.com/comic/M%2F%E8%8E%BD%E8%8D%92%E7%BA%AA%2F34%E8%AF%9D%E5%86%8D%E6%88%98%E7%BF%BC%E8%9B%87%E4%BA%8C%2F6.jpg", 92 | @"http://mhpic.taomanhua.com/comic/M%2F%E8%8E%BD%E8%8D%92%E7%BA%AA%2F34%E8%AF%9D%E5%86%8D%E6%88%98%E7%BF%BC%E8%9B%87%E4%BA%8C%2F7.jpg", 93 | @"http://mhpic.taomanhua.com/comic/M%2F%E8%8E%BD%E8%8D%92%E7%BA%AA%2F34%E8%AF%9D%E5%86%8D%E6%88%98%E7%BF%BC%E8%9B%87%E4%BA%8C%2F8.jpg", 94 | @"http://mhpic.taomanhua.com/comic/M%2F%E8%8E%BD%E8%8D%92%E7%BA%AA%2F34%E8%AF%9D%E5%86%8D%E6%88%98%E7%BF%BC%E8%9B%87%E4%BA%8C%2F9.jpg", 95 | @"http://mhpic.taomanhua.com/comic/M%2F%E8%8E%BD%E8%8D%92%E7%BA%AA%2F34%E8%AF%9D%E5%86%8D%E6%88%98%E7%BF%BC%E8%9B%87%E4%BA%8C%2F10.jpg", 96 | @"http://mhpic.taomanhua.com/comic/M%2F%E8%8E%BD%E8%8D%92%E7%BA%AA%2F34%E8%AF%9D%E5%86%8D%E6%88%98%E7%BF%BC%E8%9B%87%E4%BA%8C%2F11.jpg", 97 | @"http://mhpic.taomanhua.com/comic/M%2F%E8%8E%BD%E8%8D%92%E7%BA%AA%2F34%E8%AF%9D%E5%86%8D%E6%88%98%E7%BF%BC%E8%9B%87%E4%BA%8C%2F12.jpg", 98 | @"http://mhpic.taomanhua.com/comic/M%2F%E8%8E%BD%E8%8D%92%E7%BA%AA%2F34%E8%AF%9D%E5%86%8D%E6%88%98%E7%BF%BC%E8%9B%87%E4%BA%8C%2F13.jpg", 99 | @"http://mhpic.taomanhua.com/comic/M%2F%E8%8E%BD%E8%8D%92%E7%BA%AA%2F34%E8%AF%9D%E5%86%8D%E6%88%98%E7%BF%BC%E8%9B%87%E4%BA%8C%2F14.jpg", 100 | @"http://mhpic.taomanhua.com/comic/M%2F%E8%8E%BD%E8%8D%92%E7%BA%AA%2F34%E8%AF%9D%E5%86%8D%E6%88%98%E7%BF%BC%E8%9B%87%E4%BA%8C%2F15.jpg", 101 | @"http://mhpic.taomanhua.com/comic/M%2F%E8%8E%BD%E8%8D%92%E7%BA%AA%2F34%E8%AF%9D%E5%86%8D%E6%88%98%E7%BF%BC%E8%9B%87%E4%BA%8C%2F16.jpg" 102 | ]; 103 | 104 | for (NSString *url in urls) { 105 | [[MCDownloadManager defaultInstance] downloadFileWithURL:url progress:^(NSProgress * _Nonnull downloadProgress, MCDownloadReceipt * _Nonnull receipt) { 106 | 107 | } destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) { 108 | 109 | return nil; 110 | } success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, NSURL * _Nonnull filePath) { 111 | 112 | NSLog(@"----===="); 113 | NSFileManager *filemgr = [NSFileManager defaultManager]; 114 | NSString *cacheFolder; 115 | NSString *cacheDir = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES).firstObject; 116 | cacheFolder = [cacheDir stringByAppendingPathComponent:@"diyizhang"]; 117 | NSError *error = nil; 118 | if(![filemgr createDirectoryAtPath:cacheFolder withIntermediateDirectories:YES attributes:nil error:&error]) { 119 | NSLog(@"Failed to create cache directory at %@", cacheFolder); 120 | cacheFolder = nil; 121 | } 122 | MCDownloadReceipt * receipt = [[MCDownloadManager defaultInstance] downloadReceiptForURL:url]; 123 | [filemgr copyItemAtPath:receipt.filePath toPath:[cacheFolder stringByAppendingPathComponent:receipt.filename] error:nil]; 124 | [filemgr removeItemAtPath:receipt.filePath error:nil]; 125 | } failure:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, NSError * _Nonnull error) { 126 | 127 | }]; 128 | } 129 | 130 | 131 | } 132 | 133 | - (void)cell:(TableViewCell *)cell didClickedBtn:(UIButton *)btn { 134 | MCDownloadReceipt *receipt = [[MCDownloadManager defaultInstance] downloadReceiptForURL:cell.url]; 135 | UIViewController *vc = [UIApplication sharedApplication].keyWindow.rootViewController; 136 | MPMoviePlayerViewController *mpc = [[MPMoviePlayerViewController alloc] initWithContentURL:[NSURL fileURLWithPath:receipt.filePath]]; 137 | [vc presentViewController:mpc animated:YES completion:nil]; 138 | } 139 | 140 | 141 | @end 142 | -------------------------------------------------------------------------------- /MCDownloadManager/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // MCDownloadManager 4 | // 5 | // Created by 马超 on 16/9/5. 6 | // Copyright © 2016年 qikeyun. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MCDownloadManager 2 | A simple and convenient multi task download manager 3 | 4 | ![](http://images2015.cnblogs.com/blog/637318/201609/637318-20160912112148570-1105374973.gif) 5 | 6 | ## Attention 7 | 8 | 这个版本默认只支持同时下载10个文件 9 | This version only supports 10 file downloads at the same time. 10 | 11 | 若要支持更多,请修改下边的代码 12 | 13 | `configuration.HTTPMaximumConnectionsPerHost = 10;` 14 | 15 | **添加了速度提示(比如:400KB/s)** 16 | 17 | **支持后台和锁屏下载** 18 | 19 | ## Installation 20 | ### Cocoapods 21 | [CocoaPods](http://cocoapods.org) is a dependency manager for Cocoa projects. You can install it with the following command: 22 | 23 | ```bash 24 | $ gem install cocoapods 25 | ``` 26 | 27 | > CocoaPods 1.1.0+ is required to build MCDownloadManager 1.0.0+. 28 | 29 | To integrate MCDownloadManager into your Xcode project using CocoaPods, specify it in your `Podfile`: 30 | 31 | ```ruby 32 | pod 'MCDownloadManager', '~> 1.0.3' 33 | ``` 34 | 35 | Then, run the following command: 36 | 37 | ```bash 38 | $ pod install 39 | ``` 40 | 41 | 42 | 43 | ## Usage 44 | - (void)download { 45 | [[MCDownloadManager defaultInstance] downloadFileWithURL:self.url 46 | progress:^(NSProgress * _Nonnull downloadProgress, MCDownloadReceipt *receipt) { 47 | 48 | if ([receipt.url isEqualToString:self.url]) { 49 | self.progressView.progress = downloadProgress.fractionCompleted ; 50 | } 51 | 52 | } 53 | destination:nil 54 | success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, NSURL * _Nonnull filePath) { 55 | [self.button setTitle:@"播放" forState:UIControlStateNormal]; 56 | } 57 | failure:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, NSError * _Nonnull error) { 58 | [self.button setTitle:@"重新下载" forState:UIControlStateNormal]; 59 | }]; 60 | 61 | } 62 | --------------------------------------------------------------------------------