Explorar el Código

Update Cartfile

marinofaggiana hace 6 años
padre
commit
0671e8e1cf
Se han modificado 100 ficheros con 2065 adiciones y 1776 borrados
  1. 4 4
      Cartfile
  2. 7 7
      Cartfile.resolved
  3. 12 0
      Carthage/Checkouts/CocoaLumberjack/CHANGELOG.md
  4. 1 1
      Carthage/Checkouts/KTVHTTPCache/Framework/Info.plist
  5. 11 3
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache.podspec
  6. 1 2
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCCommon/KTVHCError.h
  7. 17 17
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCCommon/KTVHCError.m
  8. 11 18
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCCommon/KTVHCLog.h
  9. 48 47
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCCommon/KTVHCLog.m
  10. 6 5
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCCommon/KTVHCRange.h
  11. 38 45
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCCommon/KTVHCRange.m
  12. 6 5
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataCacheItem.h
  13. 8 22
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataCacheItem.m
  14. 2 2
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataCacheItemZone.h
  15. 4 10
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataCacheItemZone.m
  16. 7 17
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataFileSource.h
  17. 42 58
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataFileSource.m
  18. 10 12
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataLoader.h
  19. 31 43
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataLoader.m
  20. 9 19
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataNetworkSource.h
  21. 87 131
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataNetworkSource.m
  22. 11 13
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataReader.h
  23. 68 100
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataReader.m
  24. 4 7
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataRequest.h
  25. 11 19
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataRequest.m
  26. 7 12
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataResponse.h
  27. 11 41
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataResponse.m
  28. 9 20
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataSourceManager.h
  29. 121 91
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataSourceManager.m
  30. 3 3
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataStorage.h
  31. 11 13
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataStorage.m
  32. 16 21
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataUnit.h
  33. 127 175
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataUnit.m
  34. 8 10
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataUnitItem.h
  35. 25 31
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataUnitItem.m
  36. 1 1
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataUnitPool.h
  37. 71 91
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataUnitPool.m
  38. 2 2
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataUnitQueue.h
  39. 20 35
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataUnitQueue.m
  40. 10 10
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDownload/KTVHCDownload.h
  41. 118 135
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDownload/KTVHCDownload.m
  42. 0 2
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCHTTPServer/KTVHCHTTPConnection.h
  43. 8 30
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCHTTPServer/KTVHCHTTPConnection.m
  44. 2 2
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCHTTPServer/KTVHCHTTPResponse.h
  45. 28 31
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCHTTPServer/KTVHCHTTPResponse.m
  46. 2 2
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCHTTPServer/KTVHCHTTPServer.h
  47. 108 100
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCHTTPServer/KTVHCHTTPServer.m
  48. 335 8
      Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/KTVHTTPCache.h
  49. 1 1
      Carthage/Checkouts/KTVHTTPCache/LICENSE
  50. 2 2
      Carthage/Checkouts/PDFGenerator/PDFGenerator.podspec
  51. 1 1
      Carthage/Checkouts/SVGKit/Source/DOM classes/Core DOM/DOMGlobalSettings.h
  52. 1 1
      Carthage/Checkouts/SVGKit/Source/DOM classes/SVG-DOM/SVGNumber.h
  53. 1 1
      Carthage/Checkouts/SVGKit/Source/DOM classes/Unported or Partial DOM/SVGElement.h
  54. 1 1
      Carthage/Checkouts/SVGKit/Source/Foundation additions/NSData+NSInputStream.h
  55. 1 1
      Carthage/Checkouts/SVGKit/Source/Foundation additions/NSData+NSInputStream.m
  56. 6 1
      Carthage/Checkouts/SVGKit/Source/UIKit additions/SVGKFastImageView.m
  57. 5 1
      Carthage/Checkouts/SVGKit/Source/UIKit additions/SVGKLayeredImageView.m
  58. 1 1
      Carthage/Checkouts/TLPhotoPicker/.swift-version
  59. 3 3
      Carthage/Checkouts/TLPhotoPicker/TLPhotoPicker.podspec
  60. 5 2
      Carthage/Checkouts/TLPhotoPicker/TLPhotoPicker/Classes/TLAssetsCollection.swift
  61. 10 10
      Carthage/Checkouts/TLPhotoPicker/TLPhotoPicker/Classes/TLPhotoLibrary.swift
  62. 44 38
      Carthage/Checkouts/TLPhotoPicker/TLPhotoPicker/Classes/TLPhotosPickerViewController.swift
  63. 87 39
      Carthage/Checkouts/realm-cocoa/.jenkins.yml
  64. 4 0
      Carthage/Checkouts/realm-cocoa/.swiftlint.yml
  65. 49 0
      Carthage/Checkouts/realm-cocoa/CHANGELOG.md
  66. 1 1
      Carthage/Checkouts/realm-cocoa/Configuration/Base.xcconfig
  67. 12 14
      Carthage/Checkouts/realm-cocoa/Jenkinsfile.releasability
  68. 1 46
      Carthage/Checkouts/realm-cocoa/Realm/ObjectServerTests/RLMObjectServerTests.mm
  69. 1 1
      Carthage/Checkouts/realm-cocoa/Realm/ObjectServerTests/RLMSyncTestCase.mm
  70. 5 14
      Carthage/Checkouts/realm-cocoa/Realm/ObjectServerTests/SwiftObjectServerTests.swift
  71. 2 2
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/CMake/RealmCore.cmake
  72. 5 0
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/CMakeLists.txt
  73. 2 2
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/dependencies.list
  74. 16 2
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/CMakeLists.txt
  75. 38 24
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/apple/external_commit_helper.cpp
  76. 2 2
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/apple/external_commit_helper.hpp
  77. 30 32
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/epoll/external_commit_helper.cpp
  78. 27 9
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/realm_coordinator.cpp
  79. 4 0
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/realm_coordinator.hpp
  80. 3 0
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/results.cpp
  81. 31 11
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/shared_realm.cpp
  82. 18 8
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/shared_realm.hpp
  83. 2 0
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/CMakeLists.txt
  84. 52 1
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/realm.cpp
  85. 40 1
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/results.cpp
  86. 1 1
      Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/workflow/build.sh
  87. 2 1
      Carthage/Checkouts/realm-cocoa/Realm/RLMCollection.h
  88. 10 1
      Carthage/Checkouts/realm-cocoa/Realm/RLMConstants.h
  89. 10 15
      Carthage/Checkouts/realm-cocoa/Realm/RLMNetworkClient.mm
  90. 1 1
      Carthage/Checkouts/realm-cocoa/Realm/RLMRealm.mm
  91. 3 1
      Carthage/Checkouts/realm-cocoa/Realm/RLMSyncConfiguration_Private.h
  92. 1 1
      Carthage/Checkouts/realm-cocoa/Realm/RLMSyncManager.h
  93. 2 1
      Carthage/Checkouts/realm-cocoa/Realm/RLMSyncPermission.h
  94. 1 1
      Carthage/Checkouts/realm-cocoa/Realm/RLMSyncSession.h
  95. 1 1
      Carthage/Checkouts/realm-cocoa/Realm/RLMSyncSubscription.h
  96. 2 2
      Carthage/Checkouts/realm-cocoa/Realm/Realm-Info.plist
  97. 9 1
      Carthage/Checkouts/realm-cocoa/Realm/Tests/AsyncTests.mm
  98. 2 2
      Carthage/Checkouts/realm-cocoa/Realm/Tests/InterprocessTests.m
  99. 6 0
      Carthage/Checkouts/realm-cocoa/Realm/Tests/RealmTests.mm
  100. 1 1
      Carthage/Checkouts/realm-cocoa/RealmSwift/Object.swift

+ 4 - 4
Cartfile

@@ -1,4 +1,4 @@
-github "tilltue/TLPhotoPicker" == 1.8.3
+github "tilltue/TLPhotoPicker" == 1.8.5
 github "kishikawakatsumi/UICKeyChainStore" == 2.1.2
 github "danielsaidi/Sheeeeeeeeet" == 1.2.2
 github "sgr-ksmt/PDFGenerator" == 2.1
@@ -8,10 +8,10 @@ github "ealeksandrov/EAIntroView" == 2.12.0
 github "calimarkus/JDStatusBarNotification" == 1.6.0
 github "ChangbaDevs/KTVHTTPCache" == 2.0.0
 github "jdg/MBProgressHUD" == 1.1.0
-github "realm/realm-cocoa" == 3.13.1
+github "realm/realm-cocoa" == 3.14.1
 github "SVGKit/SVGKit" == 2.1.0
-github "WeTransfer/WeScan" == 0.9.1
-github "malcommac/SwiftRichString" == 2.0.1
+github "WeTransfer/WeScan" == 1.1.0
+github "malcommac/SwiftRichString" == 3.0.0
 github "https://github.com/marinofaggiana/FastScroll" "master"
 github "yannickl/QRCodeReader.swift" >= 10.0.0
 github "marmelroy/Zip"

+ 7 - 7
Cartfile.resolved

@@ -1,8 +1,8 @@
-github "ChangbaDevs/KTVHTTPCache" "1.1.7"
+github "ChangbaDevs/KTVHTTPCache" "2.0.0"
 github "CocoaLumberjack/CocoaLumberjack" "3.5.2"
 github "MortimerGoro/MGSwipeTableCell" "1.6.8"
-github "SVGKit/SVGKit" "4b507e48da30711e25d1bcdd19580f25887a2267"
-github "WeTransfer/WeScan" "v0.9.1"
+github "SVGKit/SVGKit" "2.1.0"
+github "WeTransfer/WeScan" "v1.1.0"
 github "calimarkus/JDStatusBarNotification" "1.6.0"
 github "danielsaidi/Sheeeeeeeeet" "1.2.2"
 github "dzenbot/DZNEmptyDataSet" "v1.8.1"
@@ -10,10 +10,10 @@ github "ealeksandrov/EAIntroView" "2.12.0"
 github "ealeksandrov/EARestrictedScrollView" "1.1.0"
 github "jdg/MBProgressHUD" "1.1.0"
 github "kishikawakatsumi/UICKeyChainStore" "v2.1.2"
-github "malcommac/SwiftRichString" "2.1.0"
+github "malcommac/SwiftRichString" "3.0.0"
 github "marinofaggiana/FastScroll" "81967c2309d29bc2c330d422da612160a30bade8"
 github "marmelroy/Zip" "1.1.0"
-github "realm/realm-cocoa" "v3.13.1"
-github "sgr-ksmt/PDFGenerator" "2.1.1"
-github "tilltue/TLPhotoPicker" "1.8.3"
+github "realm/realm-cocoa" "v3.14.1"
+github "sgr-ksmt/PDFGenerator" "2.1"
+github "tilltue/TLPhotoPicker" "1.8.5"
 github "yannickl/QRCodeReader.swift" "10.0.0"

+ 12 - 0
Carthage/Checkouts/CocoaLumberjack/CHANGELOG.md

@@ -1,3 +1,15 @@
+## [3.5.2 - Xcode 10.1 on 15th, 2019](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/3.5.2)
+
+### Public
+- Fix reusing of log files after rolling (#1042)
+- Fix creation of too many log files (#1049)
+- Preliminary compatibility with Swift 5 (backwards compatible with Swift 4) (#1044)
+- core: loggers os logger variations have been added (#1039)
+
+### Internal
+- Sync internal queues to prevent cleaning up log files too soon in tests (#1053)
+- DDLog checks for NULL values and for global queue dispatching has been added (#1045)
+
 ## [3.5.1 - Xcode 10 on Feb 4th, 2019](https://github.com/CocoaLumberjack/CocoaLumberjack/releases/tag/3.5.1)
 
 ### Public

+ 1 - 1
Carthage/Checkouts/KTVHTTPCache/Framework/Info.plist

@@ -15,7 +15,7 @@
 	<key>CFBundlePackageType</key>
 	<string>FMWK</string>
 	<key>CFBundleShortVersionString</key>
-	<string>1.1.7</string>
+	<string>2.0.0</string>
 	<key>CFBundleVersion</key>
 	<string>$(CURRENT_PROJECT_VERSION)</string>
 	<key>LSApplicationCategoryType</key>

+ 11 - 3
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache.podspec

@@ -1,7 +1,7 @@
 Pod::Spec.new do |s|
   s.name                = "KTVHTTPCache"
-  s.version             = "1.1.7"
-  s.summary             = "A media cache framework from Changba iOS Team."
+  s.version             = "2.0.0"
+  s.summary             = "A powerful media cache framework."
   s.homepage            = "https://github.com/ChangbaDevs/KTVHTTPCache"
   s.license             = { :type => "MIT", :file => "LICENSE" }
   s.author              = { "Single" => "libobjc@gmail.com" }
@@ -9,7 +9,15 @@ Pod::Spec.new do |s|
   s.platform            = :ios, "8.0"
   s.source              = { :git => "https://github.com/ChangbaDevs/KTVHTTPCache.git", :tag => "#{s.version}" }
   s.source_files        = "KTVHTTPCache", "KTVHTTPCache/**/*.{h,m}"
-  s.public_header_files = "KTVHTTPCache/**/*.h"
+  s.public_header_files =
+                          "KTVHTTPCache/KTVHTTPCache.h",
+                          "KTVHTTPCache/Classes/KTVHCCommon/KTVHCRange.h",
+                          "KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataReader.h",
+                          "KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataLoader.h",
+                          "KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataRequest.h",
+                          "KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataResponse.h",
+                          "KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataCacheItem.h",
+                          "KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataCacheItemZone.h"
   s.frameworks          = "UIKit", "Foundation"
   s.requires_arc        = true
   s.dependency 'KTVCocoaHTTPServer'

+ 1 - 2
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCCommon/KTVHCError.h

@@ -8,8 +8,7 @@
 
 #import <Foundation/Foundation.h>
 
-typedef NS_ENUM(NSInteger, KTVHCErrorCode)
-{
+typedef NS_ENUM(NSInteger, KTVHCErrorCode) {
     KTVHCErrorCodeResponseUnavailable  = -192700,
     KTVHCErrorCodeUnsupportContentType = -192701,
     KTVHCErrorCodeNotEnoughDiskSpace   = -192702,

+ 17 - 17
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCCommon/KTVHCError.m

@@ -18,7 +18,7 @@ NSString * const KTVHCErrorUserInfoKeyResponse = @"KTVHCErrorUserInfoKeyResponse
                                  request:(NSURLRequest *)request
                                 response:(NSURLResponse *)response
 {
-    NSMutableDictionary * userInfo = [NSMutableDictionary dictionary];
+    NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
     if (URL) {
         [userInfo setObject:URL forKey:KTVHCErrorUserInfoKeyURL];
     }
@@ -28,9 +28,9 @@ NSString * const KTVHCErrorUserInfoKeyResponse = @"KTVHCErrorUserInfoKeyResponse
     if (response) {
         [userInfo setObject:response forKey:KTVHCErrorUserInfoKeyResponse];
     }
-    NSError * error = [NSError errorWithDomain:@"KTVHTTPCache error"
-                                          code:KTVHCErrorCodeResponseUnavailable
-                                      userInfo:userInfo];
+    NSError *error = [NSError errorWithDomain:@"KTVHTTPCache error"
+                                         code:KTVHCErrorCodeResponseUnavailable
+                                     userInfo:userInfo];
     return error;
 }
 
@@ -38,7 +38,7 @@ NSString * const KTVHCErrorUserInfoKeyResponse = @"KTVHCErrorUserInfoKeyResponse
                                   request:(NSURLRequest *)request
                                  response:(NSURLResponse *)response
 {
-    NSMutableDictionary * userInfo = [NSMutableDictionary dictionary];
+    NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
     if (URL) {
         [userInfo setObject:URL forKey:KTVHCErrorUserInfoKeyURL];
     }
@@ -48,9 +48,9 @@ NSString * const KTVHCErrorUserInfoKeyResponse = @"KTVHCErrorUserInfoKeyResponse
     if (response) {
         [userInfo setObject:response forKey:KTVHCErrorUserInfoKeyResponse];
     }
-    NSError * error = [NSError errorWithDomain:@"KTVHTTPCache error"
-                                          code:KTVHCErrorCodeUnsupportContentType
-                                      userInfo:userInfo];
+    NSError *error = [NSError errorWithDomain:@"KTVHTTPCache error"
+                                         code:KTVHCErrorCodeUnsupportContentType
+                                     userInfo:userInfo];
     return error;
 }
 
@@ -59,20 +59,20 @@ NSString * const KTVHCErrorUserInfoKeyResponse = @"KTVHCErrorUserInfoKeyResponse
                        totalCacheLength:(long long)totalCacheLength
                          maxCacheLength:(long long)maxCacheLength
 {
-    NSError * error = [NSError errorWithDomain:@"KTVHTTPCache error"
-                                          code:KTVHCErrorCodeNotEnoughDiskSpace
-                                      userInfo:@{@"totlaContentLength" : @(totlaContentLength),
-                                                 @"currentContentLength" : @(currentContentLength),
-                                                 @"totalCacheLength" : @(totalCacheLength),
-                                                 @"maxCacheLength" : @(maxCacheLength)}];
+    NSError *error = [NSError errorWithDomain:@"KTVHTTPCache error"
+                                         code:KTVHCErrorCodeNotEnoughDiskSpace
+                                     userInfo:@{@"totlaContentLength" : @(totlaContentLength),
+                                                @"currentContentLength" : @(currentContentLength),
+                                                @"totalCacheLength" : @(totalCacheLength),
+                                                @"maxCacheLength" : @(maxCacheLength)}];
     return error;
 }
 
 + (NSError *)errorForException:(NSException *)exception
 {
-    NSError * error = [NSError errorWithDomain:@"KTVHTTPCache error"
-                                          code:KTVHCErrorCodeException
-                                      userInfo:exception.userInfo];
+    NSError *error = [NSError errorWithDomain:@"KTVHTTPCache error"
+                                        code:KTVHCErrorCodeException
+                                    userInfo:exception.userInfo];
     return error;
 }
 

+ 11 - 18
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCCommon/KTVHCLog.h

@@ -28,10 +28,7 @@ KTVHCLogEnable(Common,            YES, YES)
  */
 KTVHCLogEnable(HTTPServer,        YES, YES)
 KTVHCLogEnable(HTTPConnection,    YES, YES)
-KTVHCLogEnable(HTTPRequest,       YES, YES)
 KTVHCLogEnable(HTTPResponse,      YES, YES)
-KTVHCLogEnable(HTTPResponsePing,  YES, YES)
-KTVHCLogEnable(HTTPURL,           YES, YES)
 
 /**
  *  Data Storage
@@ -48,7 +45,6 @@ KTVHCLogEnable(DataUnitPool,      YES, YES)
 KTVHCLogEnable(DataUnitQueue,     YES, YES)
 
 KTVHCLogEnable(DataSourceManager, YES, YES)
-KTVHCLogEnable(DataSourceQueue,   YES, YES)
 KTVHCLogEnable(DataFileSource,    YES, YES)
 KTVHCLogEnable(DataNetworkSource, YES, YES)
 
@@ -69,8 +65,8 @@ KTVHCLogEnable(Dealloc,           YES, YES)
 #define KTVHCLogging(target, console_log_enable, record_log_enable, ...)            \
 if (([KTVHCLog log].consoleLogEnable && console_log_enable) || ([KTVHCLog log].recordLogEnable && record_log_enable))       \
 {                                                                                   \
-    NSString * va_args = [NSString stringWithFormat:__VA_ARGS__];                   \
-    NSString * log = [NSString stringWithFormat:@"%@  :   %@", target, va_args];    \
+    NSString *va_args = [NSString stringWithFormat:__VA_ARGS__];                    \
+    NSString *log = [NSString stringWithFormat:@"%@  :   %@", target, va_args];     \
     if ([KTVHCLog log].recordLogEnable && record_log_enable) {                      \
         [[KTVHCLog log] addRecordLog:log];                                          \
     }                                                                               \
@@ -83,17 +79,14 @@ if (([KTVHCLog log].consoleLogEnable && console_log_enable) || ([KTVHCLog log].r
 /**
  *  Common
  */
-#define KTVHCLogCommon(...)                 KTVHCLogging(@"KTVHCCommon           ", KTVHCLogEnableValueConsoleLog(Common),            KTVHCLogEnableValueRecordLog(Common),            ##__VA_ARGS__)
+#define KTVHCLogCommon(...)                 KTVHCLogging(@"KTVHCMacro           ", KTVHCLogEnableValueConsoleLog(Common),            KTVHCLogEnableValueRecordLog(Common),            ##__VA_ARGS__)
 
 /**
  *  HTTP Server
  */
 #define KTVHCLogHTTPServer(...)             KTVHCLogging(@"KTVHCHTTPServer       ", KTVHCLogEnableValueConsoleLog(HTTPServer),        KTVHCLogEnableValueRecordLog(HTTPServer),        ##__VA_ARGS__)
 #define KTVHCLogHTTPConnection(...)         KTVHCLogging(@"KTVHCHTTPConnection   ", KTVHCLogEnableValueConsoleLog(HTTPConnection),    KTVHCLogEnableValueRecordLog(HTTPConnection),    ##__VA_ARGS__)
-#define KTVHCLogHTTPRequest(...)            KTVHCLogging(@"KTVHCHTTPRequest      ", KTVHCLogEnableValueConsoleLog(HTTPRequest),       KTVHCLogEnableValueRecordLog(HTTPRequest),       ##__VA_ARGS__)
 #define KTVHCLogHTTPResponse(...)           KTVHCLogging(@"KTVHCHTTPResponse     ", KTVHCLogEnableValueConsoleLog(HTTPResponse),      KTVHCLogEnableValueRecordLog(HTTPResponse),      ##__VA_ARGS__)
-#define KTVHCLogHTTPResponsePing(...)       KTVHCLogging(@"KTVHCHTTPPingResponse ", KTVHCLogEnableValueConsoleLog(HTTPResponsePing),  KTVHCLogEnableValueRecordLog(HTTPResponsePing),  ##__VA_ARGS__)
-#define KTVHCLogHTTPURL(...)                KTVHCLogging(@"KTVHCHTTPURL          ", KTVHCLogEnableValueConsoleLog(HTTPURL),           KTVHCLogEnableValueRecordLog(HTTPURL),           ##__VA_ARGS__)
 
 /**
  *  Data Storage
@@ -110,7 +103,6 @@ if (([KTVHCLog log].consoleLogEnable && console_log_enable) || ([KTVHCLog log].r
 #define KTVHCLogDataUnitQueue(...)          KTVHCLogging(@"KTVHCDataUnitQueue    ", KTVHCLogEnableValueConsoleLog(DataUnitQueue),     KTVHCLogEnableValueRecordLog(DataUnitQueue),     ##__VA_ARGS__)
 
 #define KTVHCLogDataSourceManager(...)      KTVHCLogging(@"KTVHCDataSourceManager", KTVHCLogEnableValueConsoleLog(DataSourceManager), KTVHCLogEnableValueRecordLog(DataSourceManager), ##__VA_ARGS__)
-#define KTVHCLogDataSourceQueue(...)        KTVHCLogging(@"KTVHCDataSourceQueue  ", KTVHCLogEnableValueConsoleLog(DataSourceQueue),   KTVHCLogEnableValueRecordLog(DataSourceQueue),   ##__VA_ARGS__)
 #define KTVHCLogDataFileSource(...)         KTVHCLogging(@"KTVHCDataFileSource   ", KTVHCLogEnableValueConsoleLog(DataFileSource),    KTVHCLogEnableValueRecordLog(DataFileSource),    ##__VA_ARGS__)
 #define KTVHCLogDataNetworkSource(...)      KTVHCLogging(@"KTVHCDataNetworkSource", KTVHCLogEnableValueConsoleLog(DataNetworkSource), KTVHCLogEnableValueRecordLog(DataNetworkSource), ##__VA_ARGS__)
 
@@ -136,24 +128,25 @@ if (([KTVHCLog log].consoleLogEnable && console_log_enable) || ([KTVHCLog log].r
  *  DEBUG   : default is NO.
  *  RELEASE : default is NO.
  */
-@property (nonatomic, assign) BOOL consoleLogEnable;
+@property (nonatomic) BOOL consoleLogEnable;
 
 /**
  *  DEBUG   : default is NO.
  *  RELEASE : default is NO.
  */
-@property (nonatomic, assign) BOOL recordLogEnable;
+@property (nonatomic) BOOL recordLogEnable;
 
 - (void)addRecordLog:(NSString *)log;
 
-- (NSString *)recordLogFilePath;
-- (void)deleteRecordLog;
+- (NSURL *)recordLogFileURL;
+- (void)deleteRecordLogFile;
 
 /**
  *  Error
  */
-- (NSError *)lastError;
-- (NSArray <NSError *> *)allErrors;
-- (void)addError:(NSError *)error;
+- (void)addError:(NSError *)error forURL:(NSURL *)URL;
+- (NSDictionary<NSURL *, NSError *> *)errors;
+- (NSError *)errorForURL:(NSURL *)URL;
+- (void)cleanErrorForURL:(NSURL *)URL;
 
 @end

+ 48 - 47
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCCommon/KTVHCLog.m

@@ -7,15 +7,15 @@
 //
 
 #import "KTVHCLog.h"
-#import "KTVHCPathTools.h"
+#import "KTVHCPathTool.h"
 
 #import <UIKit/UIKit.h>
 
 @interface KTVHCLog ()
 
-@property (nonatomic, strong) NSLock * lock;
-@property (nonatomic, strong) NSFileHandle * writingHandle;
-@property (nonatomic, strong) NSMutableArray <NSError *> * internalErrors;
+@property (nonatomic, strong) NSLock *lock;
+@property (nonatomic, strong) NSFileHandle *writingHandle;
+@property (nonatomic, strong) NSMutableDictionary<NSURL *, NSError *> *internalErrors;
 
 @end
 
@@ -23,7 +23,7 @@
 
 + (instancetype)log
 {
-    static KTVHCLog * obj = nil;
+    static KTVHCLog *obj = nil;
     static dispatch_once_t onceToken;
     dispatch_once(&onceToken, ^{
         obj = [[self alloc] init];
@@ -33,54 +33,49 @@
 
 - (instancetype)init
 {
-    if (self = [super init])
-    {
+    if (self = [super init]) {
         self.consoleLogEnable = NO;
         self.recordLogEnable = NO;
         self.lock = [[NSLock alloc] init];
-        self.internalErrors = [NSMutableArray array];
+        self.internalErrors = [NSMutableDictionary dictionary];
     }
     return self;
 }
 
 - (void)addRecordLog:(NSString *)log
 {
-    if (!self.recordLogEnable)
-    {
+    if (!self.recordLogEnable) {
         return;
     }
-    if (log.length <= 0)
-    {
+    if (log.length <= 0) {
         return;
     }
     [self.lock lock];
-    NSString * string = [NSString stringWithFormat:@"%@  %@\n", [NSDate date], log];
-    NSData * data = [string dataUsingEncoding:NSUTF8StringEncoding];
-    if (!self.writingHandle)
-    {
-        [KTVHCPathTools deleteFileAtPath:[KTVHCPathTools logPath]];
-        [KTVHCPathTools createFileAtPath:[KTVHCPathTools logPath]];
-        self.writingHandle = [NSFileHandle fileHandleForWritingAtPath:[KTVHCPathTools logPath]];
+    NSString *string = [NSString stringWithFormat:@"%@  %@\n", [NSDate date], log];
+    NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
+    if (!self.writingHandle) {
+        [KTVHCPathTool deleteFileAtPath:[KTVHCPathTool logPath]];
+        [KTVHCPathTool createFileAtPath:[KTVHCPathTool logPath]];
+        self.writingHandle = [NSFileHandle fileHandleForWritingAtPath:[KTVHCPathTool logPath]];
         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillTerminate:) name:UIApplicationWillTerminateNotification object:nil];
     }
     [self.writingHandle writeData:data];
     [self.lock unlock];
 }
 
-- (NSString *)recordLogFilePath
+- (NSURL *)recordLogFileURL
 {
-    NSString * path = nil;
+    NSURL *URL = nil;
     [self.lock lock];
-    long long size = [KTVHCPathTools sizeOfItemAtPath:[KTVHCPathTools logPath]];
-    if (size > 0)
-    {
-        path = [KTVHCPathTools logPath];
+    long long size = [KTVHCPathTool sizeAtPath:[KTVHCPathTool logPath]];
+    if (size > 0) {
+        URL = [NSURL fileURLWithPath:[KTVHCPathTool logPath]];
     }
     [self.lock unlock];
-    return path;
+    return URL;
 }
 
-- (void)deleteRecordLog
+- (void)deleteRecordLogFile
 {
     [self.lock lock];
     [self.writingHandle synchronizeFile];
@@ -90,41 +85,47 @@
     [self.lock unlock];
 }
 
-- (NSError *)lastError
+- (void)addError:(NSError *)error forURL:(NSURL *)URL
 {
-    if (self.internalErrors.count > 0)
-    {
-        return self.internalErrors.lastObject;
+    if (!URL || ![error isKindOfClass:[NSError class]]) {
+        return;
     }
-    return nil;
+    [self.lock lock];
+    [self.internalErrors setObject:error forKey:URL];
+    [self.lock unlock];
 }
 
-- (NSArray<NSError *> *)allErrors
+- (NSDictionary<NSURL *,NSError *> *)errors
 {
-    if (self.internalErrors.count > 0)
-    {
-        return [self.internalErrors copy];
-    }
-    return nil;
+    [self.lock lock];
+    NSDictionary<NSURL *,NSError *> *ret = [self.internalErrors copy];
+    [self.lock unlock];
+    return ret;
 }
 
-- (void)addError:(NSError *)error
+- (NSError *)errorForURL:(NSURL *)URL
 {
-    if (error && [error isKindOfClass:[NSError class]])
-    {
-        if (self.internalErrors.count >= 20)
-        {
-            [self.internalErrors removeObjectAtIndex:0];
-        }
-        [self.internalErrors addObject:error];
+    if (!URL) {
+        return nil;
     }
+    [self.lock lock];
+    NSError *ret = [self.internalErrors objectForKey:URL];
+    [self.lock unlock];
+    return ret;
+}
+
+- (void)cleanErrorForURL:(NSURL *)URL
+{
+    [self.lock lock];
+    [self.internalErrors removeObjectForKey:URL];
+    [self.lock unlock];
 }
 
 #pragma mark - UIApplicationWillTerminateNotification
 
 - (void)applicationWillTerminate:(NSNotification *)notification
 {
-    [self deleteRecordLog];
+    [self deleteRecordLogFile];
 }
 
 @end

+ 6 - 5
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCCommon/KTVHCRange.h

@@ -21,14 +21,15 @@ BOOL KTVHCRangeIsInvaild(KTVHCRange range);
 BOOL KTVHCEqualRanges(KTVHCRange range1, KTVHCRange range2);
 long long KTVHCRangeGetLength(KTVHCRange range);
 NSString * KTVHCStringFromRange(KTVHCRange range);
-NSDictionary * KTVHCRangeFillToRequestHeaders(KTVHCRange range, NSDictionary * headers);
-NSDictionary * KTVHCRangeFillToResponseHeaders(KTVHCRange range, NSDictionary * headers, long long totalLength);
+NSDictionary * KTVHCRangeFillToRequestHeaders(KTVHCRange range, NSDictionary *eaders);
+NSDictionary * KTVHCRangeFillToRequestHeadersIfNeeded(KTVHCRange range, NSDictionary *headers);
+NSDictionary * KTVHCRangeFillToResponseHeaders(KTVHCRange range, NSDictionary *headers, long long totalLength);
 
 KTVHCRange KTVHCMakeRange(long long start, long long end);
 KTVHCRange KTVHCRangeZero(void);
 KTVHCRange KTVHCRangeFull(void);
 KTVHCRange KTVHCRangeInvaild(void);
-KTVHCRange KTVHCRangeWithSeparateValue(NSString * value);
-KTVHCRange KTVHCRangeWithRequestHeaderValue(NSString * value);
-KTVHCRange KTVHCRangeWithResponseHeaderValue(NSString * value, long long * totalLength);
+KTVHCRange KTVHCRangeWithSeparateValue(NSString *value);
+KTVHCRange KTVHCRangeWithRequestHeaderValue(NSString *value);
+KTVHCRange KTVHCRangeWithResponseHeaderValue(NSString *value, long long *totalLength);
 KTVHCRange KTVHCRangeWithEnsureLength(KTVHCRange range, long long ensureLength);

+ 38 - 45
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCCommon/KTVHCRange.m

@@ -30,43 +30,48 @@ BOOL KTVHCEqualRanges(KTVHCRange range1, KTVHCRange range2)
 
 long long KTVHCRangeGetLength(KTVHCRange range)
 {
-    if (range.start == KTVHCNotFound || range.end == KTVHCNotFound)
-    {
+    if (range.start == KTVHCNotFound || range.end == KTVHCNotFound) {
         return KTVHCNotFound;
     }
     return range.end - range.start + 1;
 }
 
-NSString * KTVHCStringFromRange(KTVHCRange range)
+NSString *KTVHCStringFromRange(KTVHCRange range)
 {
     return [NSString stringWithFormat:@"Range : {%lld, %lld}", range.start, range.end];
 }
 
-NSString * KTVHCRangeGetHeaderString(KTVHCRange range)
+NSString *KTVHCRangeGetHeaderString(KTVHCRange range)
 {
-    NSMutableString * string = [NSMutableString stringWithFormat:@"bytes="];
-    if (range.start != KTVHCNotFound)
-    {
+    NSMutableString *string = [NSMutableString stringWithFormat:@"bytes="];
+    if (range.start != KTVHCNotFound) {
         [string appendFormat:@"%lld", range.start];
     }
     [string appendFormat:@"-"];
-    if (range.end != KTVHCNotFound)
-    {
+    if (range.end != KTVHCNotFound) {
         [string appendFormat:@"%lld", range.end];
     }
     return [string copy];
 }
 
-NSDictionary * KTVHCRangeFillToRequestHeaders(KTVHCRange range, NSDictionary * headers)
+NSDictionary *KTVHCRangeFillToRequestHeaders(KTVHCRange range, NSDictionary *headers)
 {
-    NSMutableDictionary * ret = [NSMutableDictionary dictionaryWithDictionary:headers];
+    NSMutableDictionary *ret = [NSMutableDictionary dictionaryWithDictionary:headers];
     [ret setObject:KTVHCRangeGetHeaderString(range) forKey:@"Range"];
     return ret;
 }
 
-NSDictionary * KTVHCRangeFillToResponseHeaders(KTVHCRange range, NSDictionary * headers, long long totalLength)
+NSDictionary *KTVHCRangeFillToRequestHeadersIfNeeded(KTVHCRange range, NSDictionary *headers)
 {
-    NSMutableDictionary * ret = [NSMutableDictionary dictionaryWithDictionary:headers];
+    if ([headers objectForKey:@"Range"]) {
+        return headers;
+    }
+    return KTVHCRangeFillToRequestHeaders(range, headers);
+}
+
+NSDictionary *KTVHCRangeFillToResponseHeaders(KTVHCRange range, NSDictionary *headers, long long totalLength)
+{
+    NSMutableDictionary *ret = [NSMutableDictionary dictionaryWithDictionary:headers];
     long long currentLength = KTVHCRangeGetLength(range);
     [ret setObject:[NSString stringWithFormat:@"%lld", currentLength] forKey:@"Content-Length"];
     [ret setObject:[NSString stringWithFormat:@"bytes %lld-%lld/%lld", range.start, range.end, totalLength] forKey:@"Content-Range"];
@@ -94,35 +99,27 @@ KTVHCRange KTVHCRangeInvaild()
     return KTVHCMakeRange(KTVHCNotFound, KTVHCNotFound);
 }
 
-KTVHCRange KTVHCRangeWithSeparateValue(NSString * value)
+KTVHCRange KTVHCRangeWithSeparateValue(NSString *value)
 {
     KTVHCRange range = KTVHCRangeInvaild();
-    if (value.length > 0)
-    {
-        NSArray * components = [value componentsSeparatedByString:@","];
-        if (components.count == 1)
-        {
+    if (value.length > 0) {
+        NSArray *components = [value componentsSeparatedByString:@","];
+        if (components.count == 1) {
             components = [components.firstObject componentsSeparatedByString:@"-"];
-            if (components.count == 2)
-            {
-                NSString * startString = [components objectAtIndex:0];
+            if (components.count == 2) {
+                NSString *startString = [components objectAtIndex:0];
                 NSInteger startValue = [startString integerValue];
-                NSString * endString = [components objectAtIndex:1];
+                NSString *endString = [components objectAtIndex:1];
                 NSInteger endValue = [endString integerValue];
-                if (startString.length && (startValue >= 0) && endString.length && (endValue >= startValue))
-                {
+                if (startString.length && (startValue >= 0) && endString.length && (endValue >= startValue)) {
                     // The second 500 bytes: "500-999"
                     range.start = startValue;
                     range.end = endValue;
-                }
-                else if (startString.length && (startValue >= 0))
-                {
+                } else if (startString.length && (startValue >= 0)) {
                     // The bytes after 9500 bytes: "9500-"
                     range.start = startValue;
                     range.end = KTVHCNotFound;
-                }
-                else if (endString.length && (endValue > 0))
-                {
+                } else if (endString.length && (endValue > 0)) {
                     // The final 500 bytes: "-500"
                     range.start = KTVHCNotFound;
                     range.end = endValue;
@@ -133,27 +130,24 @@ KTVHCRange KTVHCRangeWithSeparateValue(NSString * value)
     return range;
 }
 
-KTVHCRange KTVHCRangeWithRequestHeaderValue(NSString * value)
+KTVHCRange KTVHCRangeWithRequestHeaderValue(NSString *value)
 {
-    if ([value hasPrefix:@"bytes="])
-    {
-        NSString * rangeString = [value substringFromIndex:6];
+    if ([value hasPrefix:@"bytes="]) {
+        NSString *rangeString = [value substringFromIndex:6];
         return KTVHCRangeWithSeparateValue(rangeString);
     }
     return KTVHCRangeInvaild();
 }
 
-KTVHCRange KTVHCRangeWithResponseHeaderValue(NSString * value, long long * totalLength)
+KTVHCRange KTVHCRangeWithResponseHeaderValue(NSString *value, long long *totalLength)
 {
-    if ([value hasPrefix:@"bytes "])
-    {
+    if ([value hasPrefix:@"bytes "]) {
         value = [value stringByReplacingOccurrencesOfString:@"bytes " withString:@""];
         NSRange range = [value rangeOfString:@"/"];
-        if (range.location != NSNotFound)
-        {
-            NSString * rangeString = [value substringToIndex:range.location];
-            NSString * totalLengthString = [value substringFromIndex:range.location + range.length];
-            * totalLength = totalLengthString.longLongValue;
+        if (range.location != NSNotFound) {
+            NSString *rangeString = [value substringToIndex:range.location];
+            NSString *totalLengthString = [value substringFromIndex:range.location + range.length];
+            *totalLength = totalLengthString.longLongValue;
             return KTVHCRangeWithSeparateValue(rangeString);
         }
     }
@@ -162,8 +156,7 @@ KTVHCRange KTVHCRangeWithResponseHeaderValue(NSString * value, long long * total
 
 KTVHCRange KTVHCRangeWithEnsureLength(KTVHCRange range, long long ensureLength)
 {
-    if (range.end == KTVHCNotFound && ensureLength > 0)
-    {
+    if (range.end == KTVHCNotFound && ensureLength > 0) {
         return KTVHCMakeRange(range.start, ensureLength - 1);
     }
     return range;

+ 6 - 5
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataCacheItem.h

@@ -15,10 +15,11 @@
 + (instancetype)new NS_UNAVAILABLE;
 - (instancetype)init NS_UNAVAILABLE;
 
-@property (nonatomic, copy, readonly) NSURL * URL;
-@property (nonatomic, assign, readonly) long long totalLength;
-@property (nonatomic, assign, readonly) long long cacheLength;
-@property (nonatomic, assign, readonly) long long vaildLength;
-@property (nonatomic, copy, readonly) NSArray <KTVHCDataCacheItemZone *> * zones;
+@property (nonatomic, copy, readonly) NSURL *URL;
+@property (nonatomic, copy, readonly) NSArray<KTVHCDataCacheItemZone *> *zones;
+
+@property (nonatomic, readonly) long long totalLength;
+@property (nonatomic, readonly) long long cacheLength;
+@property (nonatomic, readonly) long long vaildLength;
 
 @end

+ 8 - 22
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataCacheItem.m

@@ -7,36 +7,22 @@
 //
 
 #import "KTVHCDataCacheItem.h"
-#import "KTVHCDataPrivate.h"
+#import "KTVHCData+Internal.h"
 
 @implementation KTVHCDataCacheItem
 
-+ (instancetype)itemWithURL:(NSURL *)URL
-                totalLength:(long long)totalLength
-                cacheLength:(long long)cacheLength
-                vaildLength:(long long)vaildLength
-                      zones:(NSArray <KTVHCDataCacheItemZone *> *)zones
-{
-    return [[self alloc] initWithURL:URL
-                         totalLength:totalLength
-                         cacheLength:cacheLength
-                         vaildLength:vaildLength
-                               zones:zones];
-}
-
 - (instancetype)initWithURL:(NSURL *)URL
+                      zones:(NSArray<KTVHCDataCacheItemZone *> *)zones
                 totalLength:(long long)totalLength
                 cacheLength:(long long)cacheLength
                 vaildLength:(long long)vaildLength
-                      zones:(NSArray <KTVHCDataCacheItemZone *> *)zones
 {
-    if (self = [super init])
-    {
-        _URL = URL;
-        _totalLength = totalLength;
-        _cacheLength = cacheLength;
-        _vaildLength = vaildLength;
-        _zones = zones;
+    if (self = [super init]) {
+        self->_URL = [URL copy];
+        self->_zones = [zones copy];
+        self->_totalLength = totalLength;
+        self->_cacheLength = cacheLength;
+        self->_vaildLength = vaildLength;
     }
     return self;
 }

+ 2 - 2
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataCacheItemZone.h

@@ -13,7 +13,7 @@
 + (instancetype)new NS_UNAVAILABLE;
 - (instancetype)init NS_UNAVAILABLE;
 
-@property (nonatomic, assign, readonly) long long offset;
-@property (nonatomic, assign, readonly) long long length;
+@property (nonatomic, readonly) long long offset;
+@property (nonatomic, readonly) long long length;
 
 @end

+ 4 - 10
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataCacheItemZone.m

@@ -7,21 +7,15 @@
 //
 
 #import "KTVHCDataCacheItemZone.h"
-#import "KTVHCDataPrivate.h"
+#import "KTVHCData+Internal.h"
 
 @implementation KTVHCDataCacheItemZone
 
-+ (instancetype)itemZoneWithOffset:(long long)offset length:(long long)length
-{
-    return [[self alloc] initWithOffset:offset length:length];
-}
-
 - (instancetype)initWithOffset:(long long)offset length:(long long)length
 {
-    if (self = [super init])
-    {
-        _offset = offset;
-        _length = length;
+    if (self = [super init]) {
+        self->_offset = offset;
+        self->_length = length;
     }
     return self;
 }

+ 7 - 17
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataFileSource.h

@@ -7,36 +7,26 @@
 //
 
 #import <Foundation/Foundation.h>
-#import "KTVHCDataSourceProtocol.h"
+#import "KTVHCDataSource.h"
 
 @class KTVHCDataFileSource;
 
 @protocol KTVHCDataFileSourceDelegate <NSObject>
 
-- (void)fileSourceDidPrepared:(KTVHCDataFileSource *)fileSource;
-- (void)fileSource:(KTVHCDataFileSource *)fileSource didFailed:(NSError *)error;
+- (void)ktv_fileSourceDidPrepare:(KTVHCDataFileSource *)fileSource;
+- (void)ktv_fileSource:(KTVHCDataFileSource *)fileSource didFailWithError:(NSError *)error;
 
 @end
 
-@interface KTVHCDataFileSource : NSObject <KTVHCDataSourceProtocol>
+@interface KTVHCDataFileSource : NSObject <KTVHCDataSource>
 
 + (instancetype)new NS_UNAVAILABLE;
 - (instancetype)init NS_UNAVAILABLE;
 
-- (instancetype)initWithPath:(NSString *)path range:(KTVHCRange)range readRange:(KTVHCRange)readRange;
+- (instancetype)initWithPath:(NSString *)path range:(KTVHCRange)range readRange:(KTVHCRange)readRange NS_DESIGNATED_INITIALIZER;
 
-@property (nonatomic, copy, readonly) NSString * path;
-@property (nonatomic, assign, readonly) KTVHCRange range;
-@property (nonatomic, assign, readonly) KTVHCRange readRange;
-
-@property (nonatomic, assign, readonly) BOOL didPrepared;
-@property (nonatomic, assign, readonly) BOOL didFinished;
-@property (nonatomic, assign, readonly) BOOL didClosed;
-
-- (void)prepare;
-- (void)close;
-
-- (NSData *)readDataOfLength:(NSUInteger)length;
+@property (nonatomic, copy, readonly) NSString *path;
+@property (nonatomic, readonly) KTVHCRange readRange;
 
 @property (nonatomic, weak, readonly) id<KTVHCDataFileSourceDelegate> delegate;
 @property (nonatomic, strong, readonly) dispatch_queue_t delegateQueue;

+ 42 - 58
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataFileSource.m

@@ -13,23 +13,28 @@
 
 @interface KTVHCDataFileSource () <NSLocking>
 
-@property (nonatomic, strong) NSError * error;
-@property (nonatomic, strong) NSLock * coreLock;
-@property (nonatomic, strong) NSFileHandle * readingHandle;
-@property (nonatomic, assign) long long readedLength;
+@property (nonatomic, strong) NSLock *coreLock;
+@property (nonatomic, strong) NSFileHandle *readingHandle;
 
 @end
 
 @implementation KTVHCDataFileSource
 
+@synthesize error = _error;
+@synthesize range = _range;
+@synthesize closed = _closed;
+@synthesize prepared = _prepared;
+@synthesize finished = _finished;
+@synthesize readedLength = _readedLength;
+
 - (instancetype)initWithPath:(NSString *)path range:(KTVHCRange)range readRange:(KTVHCRange)readRange
 {
     if (self = [super init])
     {
         KTVHCLogAlloc(self);
-        _path = path;
-        _range = range;
-        _readRange = readRange;
+        self->_path = path;
+        self->_range = range;
+        self->_readRange = readRange;
         KTVHCLogDataFileSource(@"%p, Create file source\npath : %@\nrange : %@\nreadRange : %@", self, path, KTVHCStringFromRange(range), KTVHCStringFromRange(readRange));
     }
     return self;
@@ -43,30 +48,25 @@
 - (void)prepare
 {
     [self lock];
-    if (self.didPrepared)
-    {
+    if (self.isPrepared) {
         [self unlock];
         return;
     }
     KTVHCLogDataFileSource(@"%p, Call prepare", self);
     self.readingHandle = [NSFileHandle fileHandleForReadingAtPath:self.path];
-    @try
-    {
+    @try {
         [self.readingHandle seekToFileOffset:self.readRange.start];
-        _didPrepared = YES;
-        if ([self.delegate respondsToSelector:@selector(fileSourceDidPrepared:)])
-        {
+        self->_prepared = YES;
+        if ([self.delegate respondsToSelector:@selector(ktv_fileSourceDidPrepare:)]) {
             KTVHCLogDataFileSource(@"%p, Callback for prepared - Begin", self);
             [KTVHCDataCallback callbackWithQueue:self.delegateQueue block:^{
                 KTVHCLogDataFileSource(@"%p, Callback for prepared - End", self);
-                [self.delegate fileSourceDidPrepared:self];
+                [self.delegate ktv_fileSourceDidPrepare:self];
             }];
         }
-    }
-    @catch (NSException * exception)
-    {
+    } @catch (NSException *exception) {
         KTVHCLogDataFileSource(@"%p, Seek file exception\nname : %@\nreason : %@\nuserInfo : %@", self, exception.name, exception.reason, exception.userInfo);
-        NSError * error = [KTVHCError errorForException:exception];
+        NSError *error = [KTVHCError errorForException:exception];
         [self callbackForFailed:error];
     }
     [self unlock];
@@ -75,12 +75,11 @@
 - (void)close
 {
     [self lock];
-    if (self.didClosed)
-    {
+    if (self.isClosed) {
         [self unlock];
         return;
     }
-    _didClosed = YES;
+    self->_closed = YES;
     KTVHCLogDataFileSource(@"%p, Call close", self);
     [self destoryReadingHandle];
     [self unlock];
@@ -89,38 +88,31 @@
 - (NSData *)readDataOfLength:(NSUInteger)length
 {
     [self lock];
-    if (self.didClosed)
-    {
+    if (self.isClosed) {
         [self unlock];
         return nil;
     }
-    if (self.didFinished)
-    {
+    if (self.isFinished) {
         [self unlock];
         return nil;
     }
-    NSData * data = nil;
-    @try
-    {
+    NSData *data = nil;
+    @try {
         long long readLength = KTVHCRangeGetLength(self.readRange);
         length = (NSUInteger)MIN(readLength - self.readedLength, length);
         data = [self.readingHandle readDataOfLength:length];
-        if (data.length > 0)
-        {
-            self.readedLength += data.length;
+        self->_readedLength += data.length;
+        if (data.length > 0) {
             KTVHCLogDataFileSource(@"%p, Read data : %lld, %lld, %lld", self, (long long)data.length, self.readedLength, readLength);
         }
-        if (self.readedLength >= readLength)
-        {
+        if (self.readedLength >= readLength) {
             KTVHCLogDataFileSource(@"%p, Read data did finished", self);
             [self destoryReadingHandle];
-            _didFinished = YES;
+            self->_finished = YES;
         }
-    }
-    @catch (NSException * exception)
-    {
+    } @catch (NSException *exception) {
         KTVHCLogDataFileSource(@"%p, Read exception\nname : %@\nreason : %@\nuserInfo : %@", self, exception.name, exception.reason, exception.userInfo);
-        NSError * error = [KTVHCError errorForException:exception];
+        NSError *error = [KTVHCError errorForException:exception];
         [self callbackForFailed:error];
     }
     [self unlock];
@@ -129,14 +121,10 @@
 
 - (void)destoryReadingHandle
 {
-    if (self.readingHandle)
-    {
-        @try
-        {
+    if (self.readingHandle) {
+        @try {
             [self.readingHandle closeFile];
-        }
-        @catch (NSException * exception)
-        {
+        } @catch (NSException *exception) {
             KTVHCLogDataFileSource(@"%p, Close exception\nname : %@\nreason : %@\nuserInfo : %@", self, exception.name, exception.reason, exception.userInfo);
         }
         self.readingHandle = nil;
@@ -145,35 +133,31 @@
 
 - (void)callbackForFailed:(NSError *)error
 {
-    if (!error)
-    {
+    if (!error) {
         return;
     }
-    if (self.error)
-    {
+    if (self.error) {
         return;
     }
-    self.error = error;
-    if ([self.delegate respondsToSelector:@selector(fileSource:didFailed:)])
-    {
+    self->_error = error;
+    if ([self.delegate respondsToSelector:@selector(ktv_fileSource:didFailWithError:)]) {
         KTVHCLogDataFileSource(@"%p, Callback for prepared - Begin", self);
         [KTVHCDataCallback callbackWithQueue:self.delegateQueue block:^{
             KTVHCLogDataFileSource(@"%p, Callback for prepared - End", self);
-            [self.delegate fileSource:self didFailed:self.error];
+            [self.delegate ktv_fileSource:self didFailWithError:self.error];
         }];
     }
 }
 
 - (void)setDelegate:(id <KTVHCDataFileSourceDelegate>)delegate delegateQueue:(dispatch_queue_t)delegateQueue
 {
-    _delegate = delegate;
-    _delegateQueue = delegateQueue;
+    self->_delegate = delegate;
+    self->_delegateQueue = delegateQueue;
 }
 
 - (void)lock
 {
-    if (!self.coreLock)
-    {
+    if (!self.coreLock) {
         self.coreLock = [[NSLock alloc] init];
     }
     [self.coreLock lock];

+ 10 - 12
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataLoader.h

@@ -14,9 +14,9 @@
 
 @protocol KTVHCDataLoaderDelegate <NSObject>
 
-- (void)loaderDidFinished:(KTVHCDataLoader *)loader;
-- (void)loader:(KTVHCDataLoader *)loader didFailed:(NSError *)error;
-- (void)loader:(KTVHCDataLoader *)loader didChangeProgress:(double)progress;
+- (void)ktv_loaderDidFinish:(KTVHCDataLoader *)loader;
+- (void)ktv_loader:(KTVHCDataLoader *)loader didFailWithError:(NSError *)error;
+- (void)ktv_loader:(KTVHCDataLoader *)loader didChangeProgress:(double)progress;
 
 @end
 
@@ -25,21 +25,19 @@
 + (instancetype)new NS_UNAVAILABLE;
 - (instancetype)init NS_UNAVAILABLE;
 
-+ (instancetype)loaderWithRequest:(KTVHCDataRequest *)request;
-
 @property (nonatomic, weak) id <KTVHCDataLoaderDelegate> delegate;
-
 @property (nonatomic, strong) id object;
 
-@property (nonatomic, strong, readonly) KTVHCDataRequest * request;
-@property (nonatomic, strong, readonly) KTVHCDataResponse * response;
+@property (nonatomic, strong, readonly) KTVHCDataRequest *request;
+@property (nonatomic, strong, readonly) KTVHCDataResponse *response;
 
-@property (nonatomic, strong, readonly) NSError * error;
+@property (nonatomic, copy, readonly) NSError *error;
 
-@property (nonatomic, assign, readonly) BOOL didClosed;
-@property (nonatomic, assign, readonly) BOOL didFinished;
+@property (nonatomic, readonly, getter=isFinished) BOOL finished;
+@property (nonatomic, readonly, getter=isClosed) BOOL closed;
 
-@property (nonatomic, assign, readonly) double progress;
+@property (nonatomic, readonly) long long loadedLength;
+@property (nonatomic, readonly) double progress;
 
 - (void)prepare;
 - (void)close;

+ 31 - 43
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataLoader.m

@@ -7,29 +7,22 @@
 //
 
 #import "KTVHCDataLoader.h"
-#import "KTVHCDataReader.h"
-#import "KTVHCDataResponse.h"
+#import "KTVHCData+Internal.h"
 #import "KTVHCLog.h"
 
 @interface KTVHCDataLoader () <KTVHCDataReaderDelegate>
 
-@property (nonatomic, strong) KTVHCDataReader * reader;
+@property (nonatomic, strong) KTVHCDataReader *reader;
 
 @end
 
 @implementation KTVHCDataLoader
 
-+ (instancetype)loaderWithRequest:(KTVHCDataRequest *)request
-{
-    return [[self alloc] initWithRequest:request];
-}
-
 - (instancetype)initWithRequest:(KTVHCDataRequest *)request
 {
-    if (self = [super init])
-    {
+    if (self = [super init]) {
         KTVHCLogAlloc(self);
-        self.reader = [KTVHCDataReader readerWithRequest:request];
+        self.reader = [[KTVHCDataReader alloc] initWithRequest:request];
         self.reader.delegate = self;
         KTVHCLogDataLoader(@"%p, Create loader\norignalRequest : %@\nreader : %@", self, request, self.reader);
     }
@@ -70,65 +63,60 @@
     return self.reader.error;
 }
 
-- (BOOL)didClosed
+- (BOOL)isFinished
 {
-    return self.reader.didClosed;
+    return self.reader.isFinished;
 }
 
-- (BOOL)didFinished
+- (BOOL)isClosed
 {
-    return self.reader.didFinished;
+    return self.reader.isClosed;
 }
 
 #pragma mark - KTVHCDataReaderDelegate
 
-- (void)readerDidPrepared:(KTVHCDataReader *)reader
+- (void)ktv_readerDidPrepare:(KTVHCDataReader *)reader
 {
     [self readData];
 }
 
-- (void)readerHasAvailableData:(KTVHCDataReader *)reader
+- (void)ktv_readerHasAvailableData:(KTVHCDataReader *)reader
 {
     [self readData];
 }
 
-- (void)reader:(KTVHCDataReader *)reader didFailed:(NSError *)error
+- (void)ktv_reader:(KTVHCDataReader *)reader didFailWithError:(NSError *)error
 {
     KTVHCLogDataLoader(@"%p, Callback for failed", self);
-    if ([self.delegate respondsToSelector:@selector(loader:didFailed:)])
-    {
-        [self.delegate loader:self didFailed:error];
+    if ([self.delegate respondsToSelector:@selector(ktv_loader:didFailWithError:)]) {
+        [self.delegate ktv_loader:self didFailWithError:error];
     }
 }
 
 - (void)readData
 {
-    while (YES)
-    {
-        @autoreleasepool
-        {
-            NSData * data = [self.reader readDataOfLength:1024 * 1024 * 1];
-            if (self.reader.didFinished)
-            {
-                _progress = 1.0f;
-                if ([self.delegate respondsToSelector:@selector(loader:didChangeProgress:)])
-                {
-                    [self.delegate loader:self didChangeProgress:_progress];
+    while (YES) {
+        @autoreleasepool {
+            NSData *data = [self.reader readDataOfLength:1024 * 1024 * 1];
+            if (self.reader.isFinished) {
+                self->_loadedLength = self.reader.readedLength;
+                self->_progress = 1.0f;
+                if ([self.delegate respondsToSelector:@selector(ktv_loader:didChangeProgress:)]) {
+                    [self.delegate ktv_loader:self didChangeProgress:self.progress];
                 }
                 KTVHCLogDataLoader(@"%p, Callback finished", self);
-                if ([self.delegate respondsToSelector:@selector(loaderDidFinished:)])
-                {
-                    [self.delegate loaderDidFinished:self];
+                if ([self.delegate respondsToSelector:@selector(ktv_loaderDidFinish:)]) {
+                    [self.delegate ktv_loaderDidFinish:self];
                 }
-            }
-            else if (data)
-            {
-                _progress = (double)self.reader.readOffset / (double)self.response.currentLength;
-                if ([self.delegate respondsToSelector:@selector(loader:didChangeProgress:)])
-                {
-                    [self.delegate loader:self didChangeProgress:_progress];
+            } else if (data) {
+                self->_loadedLength = self.reader.readedLength;
+                if (self.response.contentLength > 0) {
+                    self->_progress = (double)self.reader.readedLength / (double)self.response.contentLength;
+                }
+                if ([self.delegate respondsToSelector:@selector(ktv_loader:didChangeProgress:)]) {
+                    [self.delegate ktv_loader:self didChangeProgress:self.progress];
                 }
-                KTVHCLogDataLoader(@"%p, read data progress %f", self, _progress);
+                KTVHCLogDataLoader(@"%p, read data progress %f", self, self.progress);
                 continue;
             }
             KTVHCLogDataLoader(@"%p, read data break", self);

+ 9 - 19
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataNetworkSource.h

@@ -7,7 +7,7 @@
 //
 
 #import <Foundation/Foundation.h>
-#import "KTVHCDataSourceProtocol.h"
+#import "KTVHCDataSource.h"
 #import "KTVHCDataRequest.h"
 #import "KTVHCDataResponse.h"
 
@@ -15,32 +15,22 @@
 
 @protocol KTVHCDataNetworkSourceDelegate <NSObject>
 
-- (void)networkSourceDidPrepared:(KTVHCDataNetworkSource *)networkSource;
-- (void)networkSourceHasAvailableData:(KTVHCDataNetworkSource *)networkSource;
-- (void)networkSourceDidFinishedDownload:(KTVHCDataNetworkSource *)networkSource;
-- (void)networkSource:(KTVHCDataNetworkSource *)networkSource didFailed:(NSError *)error;
+- (void)ktv_networkSourceDidPrepare:(KTVHCDataNetworkSource *)networkSource;
+- (void)ktv_networkSourceHasAvailableData:(KTVHCDataNetworkSource *)networkSource;
+- (void)ktv_networkSourceDidFinisheDownload:(KTVHCDataNetworkSource *)networkSource;
+- (void)ktv_networkSource:(KTVHCDataNetworkSource *)networkSource didFailWithError:(NSError *)error;
 
 @end
 
-@interface KTVHCDataNetworkSource : NSObject <KTVHCDataSourceProtocol>
+@interface KTVHCDataNetworkSource : NSObject <KTVHCDataSource>
 
 + (instancetype)new NS_UNAVAILABLE;
 - (instancetype)init NS_UNAVAILABLE;
 
-- (instancetype)initWithRequest:(KTVHCDataRequest *)reqeust;
+- (instancetype)initWithRequest:(KTVHCDataRequest *)reqeust NS_DESIGNATED_INITIALIZER;
 
-@property (nonatomic, strong, readonly) KTVHCDataRequest * request;
-@property (nonatomic, strong, readonly) KTVHCDataResponse * response;
-@property (nonatomic, assign, readonly) KTVHCRange range;
-
-@property (nonatomic, assign, readonly) BOOL didPrepared;
-@property (nonatomic, assign, readonly) BOOL didFinished;
-@property (nonatomic, assign, readonly) BOOL didClosed;
-
-- (void)prepare;
-- (void)close;
-
-- (NSData *)readDataOfLength:(NSUInteger)length;
+@property (nonatomic, strong, readonly) KTVHCDataRequest *request;
+@property (nonatomic, strong, readonly) KTVHCDataResponse *response;
 
 @property (nonatomic, weak, readonly) id<KTVHCDataNetworkSourceDelegate> delegate;
 @property (nonatomic, strong, readonly) dispatch_queue_t delegateQueue;

+ 87 - 131
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataNetworkSource.m

@@ -9,37 +9,42 @@
 #import "KTVHCDataNetworkSource.h"
 #import "KTVHCDataUnitPool.h"
 #import "KTVHCDataCallback.h"
-#import "KTVHCPathTools.h"
+#import "KTVHCPathTool.h"
 #import "KTVHCDownload.h"
 #import "KTVHCError.h"
 #import "KTVHCLog.h"
 
 @interface KTVHCDataNetworkSource () <NSLocking, KTVHCDownloadDelegate>
 
-@property (nonatomic, strong) NSError * error;
-@property (nonatomic, strong) NSLock * coreLock;
-@property (nonatomic, assign) long long downloadLength;
-@property (nonatomic, assign) long long downloadReadedLength;
-@property (nonatomic, assign) BOOL downloadDidCallComplete;
-@property (nonatomic, assign) BOOL needCallHasAvailableData;
-@property (nonatomic, assign) BOOL didCalledPrepare;
+@property (nonatomic, strong) NSLock *coreLock;
+@property (nonatomic, strong) NSFileHandle *readingHandle;
+@property (nonatomic, strong) NSFileHandle *writingHandle;
+@property (nonatomic, strong) KTVHCDataUnitItem *unitItem;
+@property (nonatomic, strong) NSURLSessionTask *downlaodTask;
 
-@property (nonatomic, strong) KTVHCDataUnitItem * unitItem;
-@property (nonatomic, strong) NSFileHandle * readingHandle;
-@property (nonatomic, strong) NSFileHandle * writingHandle;
-@property (nonatomic, assign) NSURLSessionTask * downlaodTask;
+@property (nonatomic) long long downloadLength;
+@property (nonatomic) BOOL downloadCalledComplete;
+@property (nonatomic) BOOL callHasAvailableData;
+@property (nonatomic) BOOL calledPrepare;
 
 @end
 
 @implementation KTVHCDataNetworkSource
 
+@synthesize error = _error;
+@synthesize range = _range;
+@synthesize closed = _closed;
+@synthesize prepared = _prepared;
+@synthesize finished = _finished;
+@synthesize readedLength = _readedLength;
+
 - (instancetype)initWithRequest:(KTVHCDataRequest *)reqeust
 {
     if (self = [super init])
     {
         KTVHCLogAlloc(self);
-        _request = reqeust;
-        _range = reqeust.range;
+        self->_request = reqeust;
+        self->_range = reqeust.range;
         KTVHCLogDataNetworkSource(@"%p, Create network source\nrequest : %@\nrange : %@", self, self.request, KTVHCStringFromRange(self.range));
     }
     return self;
@@ -48,23 +53,21 @@
 - (void)dealloc
 {
     KTVHCLogDealloc(self);
-    KTVHCLogDataNetworkSource(@"%p, Destory network source\nError : %@\ndownloadLength : %lld\nreadedLength : %lld", self, self.error, self.downloadLength, self.downloadReadedLength);
+    KTVHCLogDataNetworkSource(@"%p, Destory network source\nError : %@\ndownloadLength : %lld\nreadedLength : %lld", self, self.error, self.downloadLength, self.readedLength);
 }
 
 - (void)prepare
 {
     [self lock];
-    if (self.didClosed)
-    {
+    if (self.isClosed) {
         [self unlock];
         return;
     }
-    if (self.didCalledPrepare)
-    {
+    if (self.calledPrepare) {
         [self unlock];
         return;
     }
-    _didCalledPrepare = YES;
+    self->_calledPrepare = YES;
     KTVHCLogDataNetworkSource(@"%p, Call prepare", self);
     self.downlaodTask = [[KTVHCDownload download] downloadWithRequest:self.request delegate:self];
     [self unlock];
@@ -73,15 +76,13 @@
 - (void)close
 {
     [self lock];
-    if (self.didClosed)
-    {
+    if (self.isClosed) {
         [self unlock];
         return;
     }
-    _didClosed = YES;
+    self->_closed = YES;
     KTVHCLogDataNetworkSource(@"%p, Call close", self);
-    if (!self.downloadDidCallComplete)
-    {
+    if (!self.downloadCalledComplete) {
         KTVHCLogDataNetworkSource(@"%p, Cancel download task", self);
         [self.downlaodTask cancel];
         self.downlaodTask = nil;
@@ -94,43 +95,34 @@
 - (NSData *)readDataOfLength:(NSUInteger)length
 {
     [self lock];
-    if (self.didClosed || self.didFinished || self.error)
-    {
+    if (self.isClosed || self.isFinished || self.error) {
         [self unlock];
         return nil;
     }
-    if (self.downloadReadedLength >= self.downloadLength)
-    {
-        if (self.downloadDidCallComplete)
-        {
-            KTVHCLogDataNetworkSource(@"%p, Read data failed\ndownloadLength : %lld\nreadedLength : %lld", self, self.downloadReadedLength, self.downloadLength);
+    if (self.readedLength >= self.downloadLength) {
+        if (self.downloadCalledComplete) {
+            KTVHCLogDataNetworkSource(@"%p, Read data failed\ndownloadLength : %lld\nreadedLength : %lld", self, self.readedLength, self.downloadLength);
             [self destoryReadingHandle];
-        }
-        else
-        {
+        } else {
             KTVHCLogDataNetworkSource(@"%p, Read data wait callback", self);
-            self.needCallHasAvailableData = YES;
+            self.callHasAvailableData = YES;
         }
         [self unlock];
         return nil;
     }
-    NSData * data = nil;
-    @try
-    {
-        data = [self.readingHandle readDataOfLength:(NSUInteger)MIN(self.downloadLength - self.downloadReadedLength, length)];
-        self.downloadReadedLength += data.length;
-        KTVHCLogDataNetworkSource(@"%p, Read data\nLength : %lld\ndownloadLength : %lld\nreadedLength : %lld", self, (long long)data.length, self.downloadReadedLength, self.downloadLength);
-        if (self.downloadReadedLength >= KTVHCRangeGetLength(self.response.range))
-        {
-            _didFinished = YES;
+    NSData *data = nil;
+    @try {
+        data = [self.readingHandle readDataOfLength:(NSUInteger)MIN(self.downloadLength - self.readedLength, length)];
+        self->_readedLength += data.length;
+        KTVHCLogDataNetworkSource(@"%p, Read data\nLength : %lld\ndownloadLength : %lld\nreadedLength : %lld", self, (long long)data.length, self.readedLength, self.downloadLength);
+        if (self.readedLength >= KTVHCRangeGetLength(self.response.contentRange)) {
+            self->_finished = YES;
             KTVHCLogDataNetworkSource(@"%p, Read data did finished", self);
             [self destoryReadingHandle];
         }
-    }
-    @catch (NSException * exception)
-    {
+    } @catch (NSException *exception) {
         KTVHCLogDataFileSource(@"%p, Read exception\nname : %@\nreason : %@\nuserInfo : %@", self, exception.name, exception.reason, exception.userInfo);
-        NSError * error = [KTVHCError errorForException:exception];
+        NSError *error = [KTVHCError errorForException:exception];
         [self callbackForFailed:error];
     }
     [self unlock];
@@ -139,63 +131,49 @@
 
 - (void)setDelegate:(id <KTVHCDataNetworkSourceDelegate>)delegate delegateQueue:(dispatch_queue_t)delegateQueue
 {
-    _delegate = delegate;
-    _delegateQueue = delegateQueue;
+    self->_delegate = delegate;
+    self->_delegateQueue = delegateQueue;
 }
 
-- (void)download:(KTVHCDownload *)download didCompleteWithError:(NSError *)error
+- (void)ktv_download:(KTVHCDownload *)download didCompleteWithError:(NSError *)error
 {
     [self lock];
-    self.downloadDidCallComplete = YES;
+    self.downloadCalledComplete = YES;
     [self destoryWritingHandle];
-    if (self.didClosed)
-    {
+    if (self.isClosed) {
         KTVHCLogDataNetworkSource(@"%p, Complete but did closed\nError : %@", self, error);
-    }
-    else if (self.error)
-    {
+    } else if (self.error) {
         KTVHCLogDataNetworkSource(@"%p, Complete but did failed\nself.error : %@\nerror : %@", self, self.error, error);
-    }
-    else if (error)
-    {
-        if (error.code != NSURLErrorCancelled)
-        {
+    } else if (error) {
+        if (error.code != NSURLErrorCancelled) {
             [self callbackForFailed:error];
-        }
-        else
-        {
+        } else {
             KTVHCLogDataNetworkSource(@"%p, Complete with cancel\nError : %@", self, error);
         }
-    }
-    else if (self.downloadLength >= KTVHCRangeGetLength(self.response.range))
-    {
+    } else if (self.downloadLength >= KTVHCRangeGetLength(self.response.contentRange)) {
         KTVHCLogDataNetworkSource(@"%p, Complete and finisehed", self);
-        if ([self.delegate respondsToSelector:@selector(networkSourceDidFinishedDownload:)])
-        {
+        if ([self.delegate respondsToSelector:@selector(ktv_networkSourceDidFinisheDownload:)]) {
             [KTVHCDataCallback callbackWithQueue:self.delegateQueue block:^{
-                [self.delegate networkSourceDidFinishedDownload:self];
+                [self.delegate ktv_networkSourceDidFinisheDownload:self];
             }];
         }
-    }
-    else
-    {
+    } else {
         KTVHCLogDataNetworkSource(@"%p, Complete but not finisehed\ndownloadLength : %lld", self, self.downloadLength);
     }
     [self unlock];
 }
 
-- (void)download:(KTVHCDownload *)download didReceiveResponse:(KTVHCDataResponse *)response
+- (void)ktv_download:(KTVHCDownload *)download didReceiveResponse:(KTVHCDataResponse *)response
 {
     [self lock];
-    if (self.didClosed || self.error)
-    {
+    if (self.isClosed || self.error) {
         [self unlock];
         return;
     }
-    _response = response;
-    NSString * path = [KTVHCPathTools unitItemPathWithURL:self.request.URL offset:self.request.range.start];
+    self->_response = response;
+    NSString *path = [KTVHCPathTool filePathWithURL:self.request.URL offset:self.request.range.start];
     self.unitItem = [[KTVHCDataUnitItem alloc] initWithPath:path offset:self.request.range.start];
-    KTVHCDataUnit * unit = [[KTVHCDataUnitPool pool] unitWithURL:self.request.URL];
+    KTVHCDataUnit *unit = [[KTVHCDataUnitPool pool] unitWithURL:self.request.URL];
     [unit insertUnitItem:self.unitItem];
     KTVHCLogDataNetworkSource(@"%p, Receive response\nResponse : %@\nUnit : %@\nUnitItem : %@", self, response, unit, self.unitItem);
     [unit workingRelease];
@@ -205,29 +183,24 @@
     [self unlock];
 }
 
-- (void)download:(KTVHCDownload *)download didReceiveData:(NSData *)data
+- (void)ktv_download:(KTVHCDownload *)download didReceiveData:(NSData *)data
 {
     [self lock];
-    if (self.didClosed || self.error)
-    {
+    if (self.isClosed || self.error) {
         [self unlock];
         return;
     }
-    @try
-    {
+    @try {
         [self.writingHandle writeData:data];
         self.downloadLength += data.length;
-        [self.unitItem setLength:self.downloadLength];
+        [self.unitItem updateLength:self.downloadLength];
         KTVHCLogDataNetworkSource(@"%p, Receive data : %lld, %lld, %lld", self, (long long)data.length, self.downloadLength, self.unitItem.length);
         [self callbackForHasAvailableData];
-    }
-    @catch (NSException * exception)
-    {
-        NSError * error = [KTVHCError errorForException:exception];
+    } @catch (NSException *exception) {
+        NSError *error = [KTVHCError errorForException:exception];
         KTVHCLogDataNetworkSource(@"%p, write exception\nError : %@", self, error);
         [self callbackForFailed:error];
-        if (!self.downloadDidCallComplete)
-        {
+        if (!self.downloadCalledComplete) {
             KTVHCLogDataNetworkSource(@"%p, Cancel download task when write exception", self);
             [self.downlaodTask cancel];
             self.downlaodTask = nil;
@@ -238,14 +211,10 @@
 
 - (void)destoryReadingHandle
 {
-    if (self.readingHandle)
-    {
-        @try
-        {
+    if (self.readingHandle) {
+        @try {
             [self.readingHandle closeFile];
-        }
-        @catch (NSException * exception)
-        {
+        } @catch (NSException *exception) {
             KTVHCLogDataFileSource(@"%p, Close reading handle exception\nname : %@\nreason : %@\nuserInfo : %@", self, exception.name, exception.reason, exception.userInfo);
         }
         self.readingHandle = nil;
@@ -254,15 +223,11 @@
 
 - (void)destoryWritingHandle
 {
-    if (self.writingHandle)
-    {
-        @try
-        {
+    if (self.writingHandle) {
+        @try {
             [self.writingHandle synchronizeFile];
             [self.writingHandle closeFile];
-        }
-        @catch (NSException * exception)
-        {
+        } @catch (NSException *exception) {
             KTVHCLogDataFileSource(@"%p, Close writing handle exception\nname : %@\nreason : %@\nuserInfo : %@", self, exception.name, exception.reason, exception.userInfo);
         }
         self.writingHandle = nil;
@@ -271,66 +236,57 @@
 
 - (void)callbackForPrepared
 {
-    if (self.didClosed)
-    {
+    if (self.isClosed) {
         return;
     }
-    if (self.didPrepared)
-    {
+    if (self.isPrepared) {
         return;
     }
-    _didPrepared = YES;
-    if ([self.delegate respondsToSelector:@selector(networkSourceDidPrepared:)])
-    {
+    self->_prepared = YES;
+    if ([self.delegate respondsToSelector:@selector(ktv_networkSourceDidPrepare:)]) {
         KTVHCLogDataNetworkSource(@"%p, Callback for prepared - Begin", self);
         [KTVHCDataCallback callbackWithQueue:self.delegateQueue block:^{
             KTVHCLogDataNetworkSource(@"%p, Callback for prepared - End", self);
-            [self.delegate networkSourceDidPrepared:self];
+            [self.delegate ktv_networkSourceDidPrepare:self];
         }];
     }
 }
 
 - (void)callbackForHasAvailableData
 {
-    if (self.didClosed)
-    {
+    if (self.isClosed) {
         return;
     }
-    if (!self.needCallHasAvailableData)
-    {
+    if (!self.callHasAvailableData) {
         return;
     }
-    self.needCallHasAvailableData = NO;
-    if ([self.delegate respondsToSelector:@selector(networkSourceHasAvailableData:)])
-    {
+    self.callHasAvailableData = NO;
+    if ([self.delegate respondsToSelector:@selector(ktv_networkSourceHasAvailableData:)]) {
         KTVHCLogDataNetworkSource(@"%p, Callback for has available data - Begin", self);
         [KTVHCDataCallback callbackWithQueue:self.delegateQueue block:^{
             KTVHCLogDataNetworkSource(@"%p, Callback for has available data - End", self);
-            [self.delegate networkSourceHasAvailableData:self];
+            [self.delegate ktv_networkSourceHasAvailableData:self];
         }];
     }
 }
 
 - (void)callbackForFailed:(NSError *)error
 {
-    if (self.didClosed || !error || self.error)
-    {
+    if (self.isClosed || !error || self.error) {
         return;
     }
-    self.error = error;
+    self->_error = error;
     KTVHCLogDataNetworkSource(@"%p, Callback for failed\nError : %@", self, self.error);
-    if ([self.delegate respondsToSelector:@selector(networkSource:didFailed:)])
-    {
+    if ([self.delegate respondsToSelector:@selector(ktv_networkSource:didFailWithError:)]) {
         [KTVHCDataCallback callbackWithQueue:self.delegateQueue block:^{
-            [self.delegate networkSource:self didFailed:self.error];
+            [self.delegate ktv_networkSource:self didFailWithError:self.error];
         }];
     }
 }
 
 - (void)lock
 {
-    if (!self.coreLock)
-    {
+    if (!self.coreLock) {
         self.coreLock = [[NSLock alloc] init];
     }
     [self.coreLock lock];

+ 11 - 13
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataReader.h

@@ -14,9 +14,9 @@
 
 @protocol KTVHCDataReaderDelegate <NSObject>
 
-- (void)readerDidPrepared:(KTVHCDataReader *)reader;
-- (void)readerHasAvailableData:(KTVHCDataReader *)reader;
-- (void)reader:(KTVHCDataReader *)reader didFailed:(NSError *)error;
+- (void)ktv_readerDidPrepare:(KTVHCDataReader *)reader;
+- (void)ktv_readerHasAvailableData:(KTVHCDataReader *)reader;
+- (void)ktv_reader:(KTVHCDataReader *)reader didFailWithError:(NSError *)error;
 
 @end
 
@@ -25,22 +25,20 @@
 + (instancetype)new NS_UNAVAILABLE;
 - (instancetype)init NS_UNAVAILABLE;
 
-+ (instancetype)readerWithRequest:(KTVHCDataRequest *)request;
-
 @property (nonatomic, weak) id <KTVHCDataReaderDelegate> delegate;
-
 @property (nonatomic, strong) id object;
 
-@property (nonatomic, strong, readonly) KTVHCDataRequest * request;
-@property (nonatomic, strong, readonly) KTVHCDataResponse * response;
+@property (nonatomic, strong, readonly) KTVHCDataRequest *request;
+@property (nonatomic, strong, readonly) KTVHCDataResponse *response;
 
-@property (nonatomic, strong, readonly) NSError * error;
+@property (nonatomic, copy, readonly) NSError *error;
 
-@property (nonatomic, assign, readonly) BOOL didClosed;
-@property (nonatomic, assign, readonly) BOOL didPrepared;
-@property (nonatomic, assign, readonly) BOOL didFinished;
+@property (nonatomic, readonly, getter=isPrepared) BOOL prepared;
+@property (nonatomic, readonly, getter=isFinished) BOOL finished;
+@property (nonatomic, readonly, getter=isClosed) BOOL closed;
 
-@property (nonatomic, assign, readonly) long long readOffset;
+@property (nonatomic, readonly) long long readedLength;
+@property (nonatomic, readonly) double progress;
 
 - (void)prepare;
 - (void)close;

+ 68 - 100
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataReader.m

@@ -7,6 +7,7 @@
 //
 
 #import "KTVHCDataReader.h"
+#import "KTVHCData+Internal.h"
 #import "KTVHCDataSourceManager.h"
 #import "KTVHCDataUnitPool.h"
 #import "KTVHCDataCallback.h"
@@ -14,31 +15,23 @@
 
 @interface KTVHCDataReader () <KTVHCDataSourceManagerDelegate>
 
-@property (nonatomic, strong) NSRecursiveLock * coreLock;
+@property (nonatomic, strong) KTVHCDataUnit *unit;
+@property (nonatomic, strong) NSRecursiveLock *coreLock;
 @property (nonatomic, strong) dispatch_queue_t delegateQueue;
 @property (nonatomic, strong) dispatch_queue_t internalDelegateQueue;
-@property (nonatomic, assign) BOOL didCalledPrepare;
-
-@property (nonatomic, strong) KTVHCDataUnit * unit;
-@property (nonatomic, strong) KTVHCDataSourceManager * sourceManager;
+@property (nonatomic, strong) KTVHCDataSourceManager *sourceManager;
+@property (nonatomic) BOOL calledPrepare;
 
 @end
 
 @implementation KTVHCDataReader
 
-+ (instancetype)readerWithRequest:(KTVHCDataRequest *)request
-{
-    return [[self alloc] initWithRequest:request];
-}
-
 - (instancetype)initWithRequest:(KTVHCDataRequest *)request
 {
-    if (self = [super init])
-    {
+    if (self = [super init]) {
         KTVHCLogAlloc(self);
         self.unit = [[KTVHCDataUnitPool pool] unitWithURL:request.URL];
-        _request = [request requestWithTotalLength:self.unit.totalLength];
-        [self.unit updateRequestHeaders:self.request.headers];
+        self->_request = [request newRequestWithTotalLength:self.unit.totalLength];
         self.delegateQueue = dispatch_queue_create("KTVHCDataReader_delegateQueue", DISPATCH_QUEUE_SERIAL);
         self.internalDelegateQueue = dispatch_queue_create("KTVHCDataReader_internalDelegateQueue", DISPATCH_QUEUE_SERIAL);
         KTVHCLogDataReader(@"%p, Create reader\norignalRequest : %@\nfinalRequest : %@\nUnit : %@", self, request, self.request, self.unit);
@@ -50,23 +43,21 @@
 {
     KTVHCLogDealloc(self);
     [self close];
-    KTVHCLogDataReader(@"%p, Destory reader\nError : %@\nreadOffset : %lld", self, self.error, self.readOffset);
+    KTVHCLogDataReader(@"%p, Destory reader\nError : %@\nreadOffset : %lld", self, self.error, self.readedLength);
 }
 
 - (void)prepare
 {
     [self lock];
-    if (self.didClosed)
-    {
+    if (self.isClosed) {
         [self unlock];
         return;
     }
-    if (self.didCalledPrepare)
-    {
+    if (self.calledPrepare) {
         [self unlock];
         return;
     }
-    _didCalledPrepare = YES;
+    self->_calledPrepare = YES;
     KTVHCLogDataReader(@"%p, Call prepare", self);
     [self prepareSourceManager];
     [self unlock];
@@ -75,12 +66,11 @@
 - (void)close
 {
     [self lock];
-    if (self.didClosed)
-    {
+    if (self.isClosed) {
         [self unlock];
         return;
     }
-    _didClosed = YES;
+    self->_closed = YES;
     KTVHCLogDataReader(@"%p, Call close", self);
     [self.sourceManager close];
     [self.unit workingRelease];
@@ -91,28 +81,29 @@
 - (NSData *)readDataOfLength:(NSUInteger)length
 {
     [self lock];
-    if (self.didClosed)
-    {
+    if (self.isClosed) {
         [self unlock];
         return nil;
     }
-    if (self.didFinished)
-    {
+    if (self.isFinished) {
         [self unlock];
         return nil;
     }
-    if (self.error)
-    {
+    if (self.error) {
         [self unlock];
         return nil;
     }
-    NSData * data = [self.sourceManager readDataOfLength:length];;
-    _readOffset += data.length;
+    NSData *data = [self.sourceManager readDataOfLength:length];
+    if (data.length > 0) {
+        self->_readedLength += data.length;
+        if (self.response.contentLength > 0) {
+            self->_progress = (double)self.readedLength / (double)self.response.contentLength;
+        }
+    }
     KTVHCLogDataReader(@"%p, Read data : %lld", self, (long long)data.length);
-    if (self.sourceManager.didFinished)
-    {
+    if (self.sourceManager.isFinished) {
         KTVHCLogDataReader(@"%p, Read data did finished", self);
-        _didFinished = YES;
+        self->_finished = YES;
         [self close];
     }
     [self unlock];
@@ -121,35 +112,30 @@
 
 - (void)prepareSourceManager
 {
-    self.sourceManager = [[KTVHCDataSourceManager alloc] initWithDelegate:self delegateQueue:self.internalDelegateQueue];
-    NSMutableArray <KTVHCDataFileSource *> * fileSources = [NSMutableArray array];
-    NSMutableArray <KTVHCDataNetworkSource *> * networkSources = [NSMutableArray array];
+    NSMutableArray<KTVHCDataFileSource *> *fileSources = [NSMutableArray array];
+    NSMutableArray<KTVHCDataNetworkSource *> *networkSources = [NSMutableArray array];
     long long min = self.request.range.start;
     long long max = self.request.range.end;
-    NSArray * unitItems = self.unit.unitItems;
-    for (KTVHCDataUnitItem * item in unitItems)
-    {
+    NSArray *unitItems = self.unit.unitItems;
+    for (KTVHCDataUnitItem *item in unitItems) {
         long long itemMin = item.offset;
         long long itemMax = item.offset + item.length - 1;
-        if (itemMax < min || itemMin > max)
-        {
+        if (itemMax < min || itemMin > max) {
             continue;
         }
-        if (min > itemMin)
-        {
+        if (min > itemMin) {
             itemMin = min;
         }
-        if (max < itemMax)
-        {
+        if (max < itemMax) {
             itemMax = max;
         }
         min = itemMax + 1;
         KTVHCRange range = KTVHCMakeRange(item.offset, item.offset + item.length - 1);
         KTVHCRange readRange = KTVHCMakeRange(itemMin - item.offset, itemMax - item.offset);
-        KTVHCDataFileSource * source = [[KTVHCDataFileSource alloc] initWithPath:item.absolutePath range:range readRange:readRange];
+        KTVHCDataFileSource *source = [[KTVHCDataFileSource alloc] initWithPath:item.absolutePath range:range readRange:readRange];
         [fileSources addObject:source];
     }
-    [fileSources sortUsingComparator:^NSComparisonResult(KTVHCDataFileSource * obj1, KTVHCDataFileSource * obj2) {
+    [fileSources sortUsingComparator:^NSComparisonResult(KTVHCDataFileSource *obj1, KTVHCDataFileSource *obj2) {
         if (obj1.range.start < obj2.range.start) {
             return NSOrderedAscending;
         }
@@ -157,14 +143,12 @@
     }];
     long long offset = self.request.range.start;
     long long length = KTVHCRangeIsFull(self.request.range) ? KTVHCRangeGetLength(self.request.range) : (self.request.range.end - offset + 1);
-    for (KTVHCDataFileSource * obj in fileSources)
-    {
+    for (KTVHCDataFileSource *obj in fileSources) {
         long long delta = obj.range.start + obj.readRange.start - offset;
-        if (delta > 0)
-        {
+        if (delta > 0) {
             KTVHCRange range = KTVHCMakeRange(offset, offset + delta - 1);
-            KTVHCDataRequest * request = [self.request requestWithRange:range];
-            KTVHCDataNetworkSource * source = [[KTVHCDataNetworkSource alloc] initWithRequest:request];
+            KTVHCDataRequest *request = [self.request newRequestWithRange:range];
+            KTVHCDataNetworkSource *source = [[KTVHCDataNetworkSource alloc] initWithRequest:request];
             [networkSources addObject:source];
             offset += delta;
             length -= delta;
@@ -172,32 +156,27 @@
         offset += KTVHCRangeGetLength(obj.readRange);
         length -= KTVHCRangeGetLength(obj.readRange);
     }
-    if (length > 0)
-    {
+    if (length > 0) {
         KTVHCRange range = KTVHCMakeRange(offset, self.request.range.end);
-        KTVHCDataRequest * request = [self.request requestWithRange:range];
-        KTVHCDataNetworkSource * source = [[KTVHCDataNetworkSource alloc] initWithRequest:request];
+        KTVHCDataRequest *request = [self.request newRequestWithRange:range];
+        KTVHCDataNetworkSource *source = [[KTVHCDataNetworkSource alloc] initWithRequest:request];
         [networkSources addObject:source];
     }
-    for (KTVHCDataFileSource * obj in fileSources)
-    {
-        [self.sourceManager putSource:obj];
-    }
-    for (KTVHCDataNetworkSource * obj in networkSources)
-    {
-        [self.sourceManager putSource:obj];
-    }
+    NSMutableArray<id<KTVHCDataSource>> *sources = [NSMutableArray array];
+    [sources addObjectsFromArray:fileSources];
+    [sources addObjectsFromArray:networkSources];
+    self.sourceManager = [[KTVHCDataSourceManager alloc] initWithSources:sources delegate:self delegateQueue:self.internalDelegateQueue];
     [self.sourceManager prepare];
 }
 
-- (void)sourceManagerDidPrepared:(KTVHCDataSourceManager *)sourceManager
+- (void)ktv_sourceManagerDidPrepare:(KTVHCDataSourceManager *)sourceManager
 {
     [self lock];
     [self callbackForPrepared];
     [self unlock];
 }
 
-- (void)sourceManager:(KTVHCDataSourceManager *)sourceManager didReceiveResponse:(KTVHCDataResponse *)response
+- (void)ktv_sourceManager:(KTVHCDataSourceManager *)sourceManager didReceiveResponse:(KTVHCDataResponse *)response
 {
     [self lock];
     [self.unit updateResponseHeaders:response.headers totalLength:response.totalLength];
@@ -205,51 +184,45 @@
     [self unlock];
 }
 
-- (void)sourceManagerHasAvailableData:(KTVHCDataSourceManager *)sourceManager
+- (void)ktv_sourceManagerHasAvailableData:(KTVHCDataSourceManager *)sourceManager
 {
     [self lock];
-    if (self.didClosed)
-    {
+    if (self.isClosed) {
         [self unlock];
         return;
     }
-    if ([self.delegate respondsToSelector:@selector(readerHasAvailableData:)])
-    {
+    if ([self.delegate respondsToSelector:@selector(ktv_readerHasAvailableData:)]) {
         KTVHCLogDataReader(@"%p, Callback for has available data - Begin", self);
         [KTVHCDataCallback callbackWithQueue:self.delegateQueue block:^{
             KTVHCLogDataReader(@"%p, Callback for has available data - End", self);
-            [self.delegate readerHasAvailableData:self];
+            [self.delegate ktv_readerHasAvailableData:self];
         }];
     }
     [self unlock];
 }
 
-- (void)sourceManager:(KTVHCDataSourceManager *)sourceManager didFailed:(NSError *)error
+- (void)ktv_sourceManager:(KTVHCDataSourceManager *)sourceManager didFailWithError:(NSError *)error
 {
-    if (!error)
-    {
+    if (!error) {
         return;
     }
     [self lock];
-    if (self.didClosed)
-    {
+    if (self.isClosed) {
         [self unlock];
         return;
     }
-    if (self.error)
-    {
+    if (self.error) {
         [self unlock];
         return;
     }
-    _error = error;
+    self->_error = error;
     [self close];
-    [[KTVHCLog log] addError:self.error];
-    if ([self.delegate respondsToSelector:@selector(reader:didFailed:)])
-    {
+    [[KTVHCLog log] addError:self.error forURL:self.request.URL];
+    if ([self.delegate respondsToSelector:@selector(ktv_reader:didFailWithError:)]) {
         KTVHCLogDataReader(@"%p, Callback for failed - Begin\nError : %@", self, self.error);
         [KTVHCDataCallback callbackWithQueue:self.delegateQueue block:^{
             KTVHCLogDataReader(@"%p, Callback for failed - End", self);
-            [self.delegate reader:self didFailed:self.error];
+            [self.delegate ktv_reader:self didFailWithError:self.error];
         }];
     }
     [self unlock];
@@ -257,28 +230,24 @@
 
 - (void)callbackForPrepared
 {
-    if (self.didClosed)
-    {
+    if (self.isClosed) {
         return;
     }
-    if (self.didPrepared)
-    {
+    if (self.isPrepared) {
         return;
     }
-    if (self.sourceManager.didPrepared && self.unit.totalLength > 0)
-    {
+    if (self.sourceManager.isPrepared && self.unit.totalLength > 0) {
         long long totalLength = self.unit.totalLength;
         KTVHCRange range = KTVHCRangeWithEnsureLength(self.request.range, totalLength);
-        NSDictionary * headers = KTVHCRangeFillToResponseHeaders(range, self.unit.responseHeaders, totalLength);
-        _response = [[KTVHCDataResponse alloc] initWithURL:self.request.URL headers:headers];
-        _didPrepared = YES;
+        NSDictionary *headers = KTVHCRangeFillToResponseHeaders(range, self.unit.responseHeaders, totalLength);
+        self->_response = [[KTVHCDataResponse alloc] initWithURL:self.request.URL headers:headers];
+        self->_prepared = YES;
         KTVHCLogDataReader(@"%p, Reader did prepared\nResponse : %@", self, self.response);
-        if ([self.delegate respondsToSelector:@selector(readerDidPrepared:)])
-        {
+        if ([self.delegate respondsToSelector:@selector(ktv_readerDidPrepare:)]) {
             KTVHCLogDataReader(@"%p, Callback for prepared - Begin", self);
             [KTVHCDataCallback callbackWithQueue:self.delegateQueue block:^{
                 KTVHCLogDataReader(@"%p, Callback for prepared - End", self);
-                [self.delegate readerDidPrepared:self];
+                [self.delegate ktv_readerDidPrepare:self];
             }];
         }
     }
@@ -286,8 +255,7 @@
 
 - (void)lock
 {
-    if (!self.coreLock)
-    {
+    if (!self.coreLock) {
         self.coreLock = [[NSRecursiveLock alloc] init];
     }
     [self.coreLock lock];

+ 4 - 7
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataRequest.h

@@ -14,13 +14,10 @@
 + (instancetype)new NS_UNAVAILABLE;
 - (instancetype)init NS_UNAVAILABLE;
 
-- (instancetype)initWithURL:(NSURL *)URL headers:(NSDictionary *)headers;
+- (instancetype)initWithURL:(NSURL *)URL headers:(NSDictionary *)headers NS_DESIGNATED_INITIALIZER;
 
-@property (nonatomic, copy, readonly) NSURL * URL;
-@property (nonatomic, copy, readonly) NSDictionary * headers;
-@property (nonatomic, assign, readonly) KTVHCRange range;
-
-- (KTVHCDataRequest *)requestWithRange:(KTVHCRange)range;
-- (KTVHCDataRequest *)requestWithTotalLength:(long long)totalLength;
+@property (nonatomic, copy, readonly) NSURL *URL;
+@property (nonatomic, copy, readonly) NSDictionary *headers;
+@property (nonatomic, readonly) KTVHCRange range;
 
 @end

+ 11 - 19
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataRequest.m

@@ -7,22 +7,18 @@
 //
 
 #import "KTVHCDataRequest.h"
+#import "KTVHCData+Internal.h"
 #import "KTVHCLog.h"
 
 @implementation KTVHCDataRequest
 
 - (instancetype)initWithURL:(NSURL *)URL headers:(NSDictionary *)headers
 {
-    if (self = [super init])
-    {
+    if (self = [super init]) {
         KTVHCLogAlloc(self);
-        _URL = URL;
-        if (![headers objectForKey:@"Range"]) {
-            _headers = KTVHCRangeFillToRequestHeaders(KTVHCRangeFull(), headers);
-        } else {
-            _headers = headers;
-        }
-        _range = KTVHCRangeWithRequestHeaderValue([_headers objectForKey:@"Range"]);
+        self->_URL = URL;
+        self->_headers = KTVHCRangeFillToRequestHeadersIfNeeded(KTVHCRangeFull(), headers);
+        self->_range = KTVHCRangeWithRequestHeaderValue([self.headers objectForKey:@"Range"]);
         KTVHCLogDataRequest(@"%p Create data request\nURL : %@\nHeaders : %@\nRange : %@", self, self.URL, self.headers, KTVHCStringFromRange(self.range));
     }
     return self;
@@ -33,21 +29,17 @@
     KTVHCLogDealloc(self);
 }
 
-- (KTVHCDataRequest *)requestWithRange:(KTVHCRange)range
+- (KTVHCDataRequest *)newRequestWithRange:(KTVHCRange)range
 {
-    if (!KTVHCEqualRanges(self.range, range))
-    {
-        NSDictionary * headers = KTVHCRangeFillToRequestHeaders(range, self.headers);
-        KTVHCDataRequest * obj = [[KTVHCDataRequest alloc] initWithURL:self.URL headers:headers];
-        return obj;
-    }
-    return self;
+    NSDictionary *headers = KTVHCRangeFillToRequestHeaders(range, self.headers);
+    KTVHCDataRequest *obj = [[KTVHCDataRequest alloc] initWithURL:self.URL headers:headers];
+    return obj;
 }
 
-- (KTVHCDataRequest *)requestWithTotalLength:(long long)totalLength
+- (KTVHCDataRequest *)newRequestWithTotalLength:(long long)totalLength
 {
     KTVHCRange range = KTVHCRangeWithEnsureLength(self.range, totalLength);
-    return [self requestWithRange:range];
+    return [self newRequestWithRange:range];
 }
 
 @end

+ 7 - 12
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataResponse.h

@@ -14,17 +14,12 @@
 + (instancetype)new NS_UNAVAILABLE;
 - (instancetype)init NS_UNAVAILABLE;
 
-- (instancetype)initWithURL:(NSURL *)URL headers:(NSDictionary *)headers;
-
-@property (nonatomic, copy, readonly) NSURL * URL;
-@property (nonatomic, copy, readonly) NSDictionary * headers;
-@property (nonatomic, copy, readonly) NSDictionary * headersWithoutRangeAndLength;
-
-@property (nonatomic, copy, readonly) NSString * contentType;
-@property (nonatomic, assign, readonly) KTVHCRange range;
-@property (nonatomic, assign, readonly) long long totalLength;
-@property (nonatomic, assign, readonly) long long currentLength;
-
-- (KTVHCDataResponse *)responseWithRange:(KTVHCRange)range;
+@property (nonatomic, copy, readonly) NSURL *URL;
+@property (nonatomic, copy, readonly) NSDictionary *headers;
+@property (nonatomic, copy, readonly) NSString *contentType;
+@property (nonatomic, copy, readonly) NSString *contentRangeString;
+@property (nonatomic, readonly) KTVHCRange contentRange;
+@property (nonatomic, readonly) long long contentLength;
+@property (nonatomic, readonly) long long totalLength;
 
 @end

+ 11 - 41
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataResponse.m

@@ -7,27 +7,22 @@
 //
 
 #import "KTVHCDataResponse.h"
+#import "KTVHCData+Internal.h"
 #import "KTVHCLog.h"
 
 @implementation KTVHCDataResponse
 
 - (instancetype)initWithURL:(NSURL *)URL headers:(NSDictionary *)headers
 {
-    if (self = [super init])
-    {
+    if (self = [super init]) {
         KTVHCLogAlloc(self);
-        _URL = URL;
-        _headers = headers;
-        NSMutableDictionary * headersWithoutRangeAndLength = [headers mutableCopy];
-        for (NSString * key in [self withoutHeaderKeys])
-        {
-            [headersWithoutRangeAndLength removeObjectForKey:key];
-        }
-        _headersWithoutRangeAndLength = [headersWithoutRangeAndLength copy];
-        _contentType = [self headerValueWithKey:@"Content-Type"];
-        _currentLength = [self headerValueWithKey:@"Content-Length"].longLongValue;
-        _range = KTVHCRangeWithResponseHeaderValue([self headerValueWithKey:@"Content-Range"], &_totalLength);
-        KTVHCLogDataResponse(@"%p Create data response\nURL : %@\nHeaders : %@\nheadersWithoutRangeAndLength : %@\ncontentType : %@\ntotalLength : %lld\ncurrentLength : %lld", self, self.URL, self.headers, self.headersWithoutRangeAndLength, self.contentType, self.totalLength, self.currentLength);
+        self->_URL = URL;
+        self->_headers = headers;
+        self->_contentType = [self headerValueWithKey:@"Content-Type"];
+        self->_contentRangeString = [self headerValueWithKey:@"Content-Range"];
+        self->_contentLength = [self headerValueWithKey:@"Content-Length"].longLongValue;
+        self->_contentRange = KTVHCRangeWithResponseHeaderValue(self.contentRangeString, &self->_totalLength);
+        KTVHCLogDataResponse(@"%p Create data response\nURL : %@\nHeaders : %@\ncontentType : %@\ntotalLength : %lld\ncurrentLength : %lld", self, self.URL, self.headers, self.contentType, self.totalLength, self.contentLength);
     }
     return self;
 }
@@ -39,36 +34,11 @@
 
 - (NSString *)headerValueWithKey:(NSString *)key
 {
-    NSString * value = [self.headers objectForKey:key];
-    if (!value)
-    {
+    NSString *value = [self.headers objectForKey:key];
+    if (!value) {
         value = [self.headers objectForKey:[key lowercaseString]];
     }
     return value;
 }
 
-- (NSArray <NSString *> *)withoutHeaderKeys
-{
-    static NSArray * obj = nil;
-    static dispatch_once_t onceToken;
-    dispatch_once(&onceToken, ^{
-        obj = @[@"Content-Length",
-                @"content-length",
-                @"Content-Range",
-                @"content-range"];
-    });
-    return obj;
-}
-
-- (KTVHCDataResponse *)responseWithRange:(KTVHCRange)range
-{
-    if (!KTVHCEqualRanges(self.range, range))
-    {
-        NSDictionary * headers = KTVHCRangeFillToResponseHeaders(range, self.headers, self.totalLength);
-        KTVHCDataResponse * obj = [[KTVHCDataResponse alloc] initWithURL:self.URL headers:headers];
-        return obj;
-    }
-    return self;
-}
-
 @end

+ 9 - 20
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataSourceManager.h

@@ -7,41 +7,30 @@
 //
 
 #import <Foundation/Foundation.h>
-#import "KTVHCDataFileSource.h"
 #import "KTVHCDataNetworkSource.h"
+#import "KTVHCDataFileSource.h"
 
 @class KTVHCDataSourceManager;
 
 @protocol KTVHCDataSourceManagerDelegate <NSObject>
 
-- (void)sourceManagerDidPrepared:(KTVHCDataSourceManager *)sourceManager;
-- (void)sourceManagerHasAvailableData:(KTVHCDataSourceManager *)sourceManager;
-- (void)sourceManager:(KTVHCDataSourceManager *)sourceManager didFailed:(NSError *)error;
-- (void)sourceManager:(KTVHCDataSourceManager *)sourceManager didReceiveResponse:(KTVHCDataResponse *)response;
+- (void)ktv_sourceManagerDidPrepare:(KTVHCDataSourceManager *)sourceManager;
+- (void)ktv_sourceManagerHasAvailableData:(KTVHCDataSourceManager *)sourceManager;
+- (void)ktv_sourceManager:(KTVHCDataSourceManager *)sourceManager didFailWithError:(NSError *)error;
+- (void)ktv_sourceManager:(KTVHCDataSourceManager *)sourceManager didReceiveResponse:(KTVHCDataResponse *)response;
 
 @end
 
-@interface KTVHCDataSourceManager : NSObject
+@interface KTVHCDataSourceManager : NSObject <KTVHCDataSource>
 
 + (instancetype)new NS_UNAVAILABLE;
 - (instancetype)init NS_UNAVAILABLE;
 
-- (instancetype)initWithDelegate:(id <KTVHCDataSourceManagerDelegate>)delegate delegateQueue:(dispatch_queue_t)delegateQueue;
+- (instancetype)initWithSources:(NSArray<id<KTVHCDataSource>> *)sources
+                       delegate:(id <KTVHCDataSourceManagerDelegate>)delegate
+                  delegateQueue:(dispatch_queue_t)delegateQueue NS_DESIGNATED_INITIALIZER;
 
 @property (nonatomic, weak, readonly) id <KTVHCDataSourceManagerDelegate> delegate;
 @property (nonatomic, strong, readonly) dispatch_queue_t delegateQueue;
 
-@property (nonatomic, strong, readonly) NSError * error;
-
-@property (nonatomic, assign, readonly) BOOL didClosed;
-@property (nonatomic, assign, readonly) BOOL didPrepared;
-@property (nonatomic, assign, readonly) BOOL didFinished;
-
-- (void)putSource:(id<KTVHCDataSourceProtocol>)source;
-
-- (void)prepare;
-- (void)close;
-
-- (NSData *)readDataOfLength:(NSUInteger)length;
-
 @end

+ 121 - 91
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataSourceManager.m

@@ -7,32 +7,36 @@
 //
 
 #import "KTVHCDataSourceManager.h"
-#import "KTVHCDataSourceQueue.h"
 #import "KTVHCDataCallback.h"
 #import "KTVHCLog.h"
 
 @interface KTVHCDataSourceManager () <NSLocking, KTVHCDataFileSourceDelegate, KTVHCDataNetworkSourceDelegate>
 
-@property (nonatomic, strong) NSLock * coreLock;
-@property (nonatomic, assign) BOOL didCalledPrepare;
-@property (nonatomic, assign) BOOL didCalledReceiveResponse;
-
-@property (nonatomic, strong) KTVHCDataSourceQueue * sourceQueue;
-@property (nonatomic, strong) id <KTVHCDataSourceProtocol> currentSource;
-@property (nonatomic, strong) KTVHCDataNetworkSource * currentNetworkSource;
+@property (nonatomic, strong) NSLock *coreLock;
+@property (nonatomic, strong) id <KTVHCDataSource> currentSource;
+@property (nonatomic, strong) KTVHCDataNetworkSource *currentNetworkSource;
+@property (nonatomic, strong) NSMutableArray<id<KTVHCDataSource>> *sources;
+@property (nonatomic) BOOL calledPrepare;
+@property (nonatomic) BOOL calledReceiveResponse;
 
 @end
 
 @implementation KTVHCDataSourceManager
 
-- (instancetype)initWithDelegate:(id <KTVHCDataSourceManagerDelegate>)delegate delegateQueue:(dispatch_queue_t)delegateQueue
+@synthesize error = _error;
+@synthesize range = _range;
+@synthesize closed = _closed;
+@synthesize prepared = _prepared;
+@synthesize finished = _finished;
+@synthesize readedLength = _readedLength;
+
+- (instancetype)initWithSources:(NSArray<id<KTVHCDataSource>> *)sources delegate:(id<KTVHCDataSourceManagerDelegate>)delegate delegateQueue:(dispatch_queue_t)delegateQueue
 {
-    if (self = [super init])
-    {
+    if (self = [super init]) {
         KTVHCLogAlloc(self);
-        _delegate = delegate;
-        _delegateQueue = delegateQueue;
-        self.sourceQueue = [KTVHCDataSourceQueue sourceQueue];
+        self->_sources = [sources mutableCopy];
+        self->_delegate = delegate;
+        self->_delegateQueue = delegateQueue;
     }
     return self;
 }
@@ -43,108 +47,141 @@
     KTVHCLogDataReader(@"%p, Destory reader\nError : %@\ncurrentSource : %@\ncurrentNetworkSource : %@", self, self.error, self.currentSource, self.currentNetworkSource);
 }
 
-- (void)putSource:(id<KTVHCDataSourceProtocol>)source
-{
-    KTVHCLogDataSourceManager(@"%p, Put source : %@", self, source);
-    [self.sourceQueue putSource:source];
-}
-
 - (void)prepare
 {
     [self lock];
-    if (self.didClosed)
-    {
+    if (self.isClosed) {
         [self unlock];
         return;
     }
-    if (self.didCalledPrepare)
-    {
+    if (self.calledPrepare) {
         [self unlock];
         return;
     }
-    _didCalledPrepare = YES;
+    self->_calledPrepare = YES;
     KTVHCLogDataSourceManager(@"%p, Call prepare", self);
-    [self.sourceQueue sortSources];
-    [self.sourceQueue setAllSourceDelegate:self delegateQueue:self.delegateQueue];
-    self.currentSource = [self.sourceQueue firstSource];
-    self.currentNetworkSource = [self.sourceQueue firstNetworkSource];
+    KTVHCLogDataSourceManager(@"%p, Sort sources - Begin\nSources : %@", self, self.sources);
+    [self.sources sortUsingComparator:^NSComparisonResult(id <KTVHCDataSource> obj1, id <KTVHCDataSource> obj2) {
+        if (obj1.range.start < obj2.range.start) {
+            return NSOrderedAscending;
+        }
+        return NSOrderedDescending;
+    }];
+    KTVHCLogDataSourceManager(@"%p, Sort sources - End  \nSources : %@", self, self.sources);
+    for (id <KTVHCDataSource> obj in self.sources) {
+        if ([obj isKindOfClass:[KTVHCDataFileSource class]]) {
+            KTVHCDataFileSource *source = (KTVHCDataFileSource *)obj;
+            [source setDelegate:self delegateQueue:self.delegateQueue];
+        }
+        else if ([obj isKindOfClass:[KTVHCDataNetworkSource class]]) {
+            KTVHCDataNetworkSource *source = (KTVHCDataNetworkSource *)obj;
+            [source setDelegate:self delegateQueue:self.delegateQueue];
+        }
+    }
+    self.currentSource = self.sources.firstObject;
+    for (id<KTVHCDataSource> obj in self.sources) {
+        if ([obj isKindOfClass:[KTVHCDataNetworkSource class]]) {
+            self.currentNetworkSource = obj;
+            break;
+        }
+    }
     KTVHCLogDataSourceManager(@"%p, Sort source\ncurrentSource : %@\ncurrentNetworkSource : %@", self, self.currentSource, self.currentNetworkSource);
     [self.currentSource prepare];
-    if (self.currentSource != self.currentNetworkSource)
-    {
-        [self.currentNetworkSource prepare];
-    }
+    [self.currentNetworkSource prepare];
     [self unlock];
 }
 
 - (void)close
 {
     [self lock];
-    if (self.didClosed)
-    {
+    if (self.isClosed) {
         [self unlock];
         return;
     }
-    _didClosed = YES;
+    self->_closed = YES;
     KTVHCLogDataSourceManager(@"%p, Call close", self);
-    [self.sourceQueue closeAllSource];
+    for (id <KTVHCDataSource> obj in self.sources) {
+        [obj close];
+    }
     [self unlock];
 }
 
 - (NSData *)readDataOfLength:(NSUInteger)length
 {
     [self lock];
-    if (self.didClosed)
-    {
+    if (self.isClosed) {
         [self unlock];
         return nil;
     }
-    if (self.didFinished)
-    {
+    if (self.isFinished) {
         [self unlock];
         return nil;
     }
-    if (self.error)
-    {
+    if (self.error) {
         [self unlock];
         return nil;
     }
-    NSData * data = [self.currentSource readDataOfLength:length];
+    NSData *data = [self.currentSource readDataOfLength:length];
+    self->_readedLength += data.length;
     KTVHCLogDataSourceManager(@"%p, Read data : %lld", self, (long long)data.length);
-    if (self.currentSource.didFinished)
-    {
-        self.currentSource = [self.sourceQueue nextSource:self.currentSource];
-        if (self.currentSource)
-        {
+    if (self.currentSource.isFinished) {
+        self.currentSource = [self nextSource];
+        if (self.currentSource) {
             KTVHCLogDataSourceManager(@"%p, Switch to next source, %@", self, self.currentSource);
-            if ([self.currentSource isKindOfClass:[KTVHCDataFileSource class]])
-            {
+            if ([self.currentSource isKindOfClass:[KTVHCDataFileSource class]]) {
                 [self.currentSource prepare];
             }
-        }
-        else
-        {
+        } else {
             KTVHCLogDataSourceManager(@"%p, Read data did finished", self);
-            _didFinished = YES;
+            self->_finished = YES;
         }
     }
     [self unlock];
     return data;
 }
 
-- (void)fileSourceDidPrepared:(KTVHCDataFileSource *)fileSource
+- (id<KTVHCDataSource>)nextSource
+{
+    NSUInteger index = [self.sources indexOfObject:self.currentSource] + 1;
+    if (index < self.sources.count) {
+        KTVHCLogDataSourceManager(@"%p, Fetch next source : %@", self, [self.sources objectAtIndex:index]);
+        return [self.sources objectAtIndex:index];
+    }
+    KTVHCLogDataSourceManager(@"%p, Fetch netxt source failed", self);
+    return nil;
+}
+
+- (KTVHCDataNetworkSource *)nextNetworkSource
+{
+    NSUInteger index = [self.sources indexOfObject:self.currentNetworkSource] + 1;
+    for (; index < self.sources.count; index++) {
+        id <KTVHCDataSource> obj = [self.sources objectAtIndex:index];
+        if ([obj isKindOfClass:[KTVHCDataNetworkSource class]]) {
+            KTVHCLogDataSourceManager(@"%p, Fetch next network source : %@", self, obj);
+            return obj;
+        }
+    }
+    KTVHCLogDataSourceManager(@"%p, Fetch netxt network source failed", self);
+    return nil;
+}
+
+#pragma mark - KTVHCDataFileSourceDelegate
+
+- (void)ktv_fileSourceDidPrepare:(KTVHCDataFileSource *)fileSource
 {
     [self lock];
     [self callbackForPrepared];
     [self unlock];
 }
 
-- (void)fileSource:(KTVHCDataFileSource *)fileSource didFailed:(NSError *)error
+- (void)ktv_fileSource:(KTVHCDataFileSource *)fileSource didFailWithError:(NSError *)error
 {
     [self callbackForFailed:error];
 }
 
-- (void)networkSourceDidPrepared:(KTVHCDataNetworkSource *)networkSource
+#pragma mark - KTVHCDataNetworkSourceDelegate
+
+- (void)ktv_networkSourceDidPrepare:(KTVHCDataNetworkSource *)networkSource
 {
     [self lock];
     [self callbackForPrepared];
@@ -152,105 +189,98 @@
     [self unlock];
 }
 
-- (void)networkSourceHasAvailableData:(KTVHCDataNetworkSource *)networkSource
+- (void)ktv_networkSourceHasAvailableData:(KTVHCDataNetworkSource *)networkSource
 {
     [self lock];
-    if ([self.delegate respondsToSelector:@selector(sourceManagerHasAvailableData:)])
-    {
+    if ([self.delegate respondsToSelector:@selector(ktv_sourceManagerHasAvailableData:)]) {
         KTVHCLogDataSourceManager(@"%p, Callback for has available data - Begin\nSource : %@", self, networkSource);
         [KTVHCDataCallback callbackWithQueue:self.delegateQueue block:^{
             KTVHCLogDataSourceManager(@"%p, Callback for has available data - End", self);
-            [self.delegate sourceManagerHasAvailableData:self];
+            [self.delegate ktv_sourceManagerHasAvailableData:self];
         }];
     }
     [self unlock];
 }
 
-- (void)networkSourceDidFinishedDownload:(KTVHCDataNetworkSource *)networkSource
+- (void)ktv_networkSourceDidFinisheDownload:(KTVHCDataNetworkSource *)networkSource
 {
     [self lock];
-    self.currentNetworkSource = [self.sourceQueue nextNetworkSource:self.currentNetworkSource];
+    self.currentNetworkSource = [self nextNetworkSource];
     [self.currentNetworkSource prepare];
     [self unlock];
 }
 
-- (void)networkSource:(KTVHCDataNetworkSource *)networkSource didFailed:(NSError *)error
+- (void)ktv_networkSource:(KTVHCDataNetworkSource *)networkSource didFailWithError:(NSError *)error
 {
     [self callbackForFailed:error];
 }
 
+#pragma mark - Callback
+
 - (void)callbackForPrepared
 {
-    if (self.didClosed)
-    {
+    if (self.isClosed) {
         return;
     }
-    if (self.didPrepared)
-    {
+    if (self.isPrepared) {
         return;
     }
-    _didPrepared = YES;
-    if ([self.delegate respondsToSelector:@selector(sourceManagerDidPrepared:)])
-    {
+    self->_prepared = YES;
+    if ([self.delegate respondsToSelector:@selector(ktv_sourceManagerDidPrepare:)]) {
         KTVHCLogDataSourceManager(@"%p, Callback for prepared - Begin", self);
         [KTVHCDataCallback callbackWithQueue:self.delegateQueue block:^{
             KTVHCLogDataSourceManager(@"%p, Callback for prepared - End", self);
-            [self.delegate sourceManagerDidPrepared:self];
+            [self.delegate ktv_sourceManagerDidPrepare:self];
         }];
     }
 }
 
 - (void)callbackForReceiveResponse:(KTVHCDataResponse *)response
 {
-    if (self.didClosed)
-    {
+    if (self.isClosed) {
         return;
     }
-    if (self.didCalledReceiveResponse)
-    {
+    if (self.calledReceiveResponse) {
         return;
     }
-    _didCalledReceiveResponse = YES;
-    if ([self.delegate respondsToSelector:@selector(sourceManager:didReceiveResponse:)])
-    {
+    self->_calledReceiveResponse = YES;
+    if ([self.delegate respondsToSelector:@selector(ktv_sourceManager:didReceiveResponse:)]) {
         KTVHCLogDataSourceManager(@"%p, Callback for did receive response - End", self);
         [KTVHCDataCallback callbackWithQueue:self.delegateQueue block:^{
             KTVHCLogDataSourceManager(@"%p, Callback for did receive response - End", self);
-            [self.delegate sourceManager:self didReceiveResponse:response];
+            [self.delegate ktv_sourceManager:self didReceiveResponse:response];
         }];
     }
 }
 
 - (void)callbackForFailed:(NSError *)error
 {
-    if (!error)
-    {
+    if (!error) {
         return;
     }
     [self lock];
-    if (self.didClosed)
-    {
+    if (self.isClosed) {
         [self unlock];
         return;
     }
-    if (self.error)
-    {
+    if (self.error) {
         [self unlock];
         return;
     }
-    _error = error;
+    self->_error = error;
     KTVHCLogDataSourceManager(@"failure, %d", (int)self.error.code);
-    if (self.error && [self.delegate respondsToSelector:@selector(sourceManager:didFailed:)])
-    {
+    if (self.error && [self.delegate respondsToSelector:@selector(ktv_sourceManager:didFailWithError:)]) {
         KTVHCLogDataSourceManager(@"%p, Callback for network source failed - Begin\nError : %@", self, self.error);
         [KTVHCDataCallback callbackWithQueue:self.delegateQueue block:^{
             KTVHCLogDataSourceManager(@"%p, Callback for network source failed - End", self);
-            [self.delegate sourceManager:self didFailed:self.error];
+            [self.delegate ktv_sourceManager:self didFailWithError:self.error];
         }];
     }
     [self unlock];
 }
 
+#pragma mark - NSLocking
+
 - (void)lock
 {
     if (!self.coreLock) {

+ 3 - 3
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataStorage.h

@@ -23,7 +23,7 @@
 /**
  *  Return file path if the content did finished cache.
  */
-- (NSURL *)completeFileURLIfExistedWithURL:(NSURL *)URL;
+- (NSURL *)completeFileURLWithURL:(NSURL *)URL;
 
 /**
  *  Reader for certain request.
@@ -39,12 +39,12 @@
  *  Get cache item.
  */
 - (KTVHCDataCacheItem *)cacheItemWithURL:(NSURL *)URL;
-- (NSArray <KTVHCDataCacheItem *> *)allCacheItems;
+- (NSArray<KTVHCDataCacheItem *> *)allCacheItems;
 
 /**
  *  Get cache length.
  */
-@property (nonatomic, assign) long long maxCacheLength;     // Default is 500M.
+@property (nonatomic) long long maxCacheLength;     // Default is 500M.
 - (long long)totalCacheLength;
 
 /**

+ 11 - 13
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataStorage.m

@@ -7,6 +7,7 @@
 //
 
 #import "KTVHCDataStorage.h"
+#import "KTVHCData+Internal.h"
 #import "KTVHCDataUnitPool.h"
 #import "KTVHCLog.h"
 
@@ -14,7 +15,7 @@
 
 + (instancetype)storage
 {
-    static KTVHCDataStorage * obj = nil;
+    static KTVHCDataStorage *obj = nil;
     static dispatch_once_t onceToken;
     dispatch_once(&onceToken, ^{
         obj = [[self alloc] init];
@@ -24,40 +25,37 @@
 
 - (instancetype)init
 {
-    if (self = [super init])
-    {
+    if (self = [super init]) {
         self.maxCacheLength = 500 * 1024 * 1024;
     }
     return self;
 }
 
-- (NSURL *)completeFileURLIfExistedWithURL:(NSURL *)URL
+- (NSURL *)completeFileURLWithURL:(NSURL *)URL
 {
-    KTVHCDataUnit * unit = [[KTVHCDataUnitPool pool] unitWithURL:URL];
-    NSURL * fileURL = unit.fileURL;
+    KTVHCDataUnit *unit = [[KTVHCDataUnitPool pool] unitWithURL:URL];
+    NSURL *completeURL = unit.completeURL;
     [unit workingRelease];
-    return fileURL;
+    return completeURL;
 }
 
 - (KTVHCDataReader *)readerWithRequest:(KTVHCDataRequest *)request
 {
-    if (!request || request.URL.absoluteString.length <= 0)
-    {
+    if (!request || request.URL.absoluteString.length <= 0) {
         KTVHCLogDataStorage(@"Invaild reader request, %@", request.URL);
         return nil;
     }
-    KTVHCDataReader * reader = [KTVHCDataReader readerWithRequest:request];
+    KTVHCDataReader *reader = [[KTVHCDataReader alloc] initWithRequest:request];
     return reader;
 }
 
 - (KTVHCDataLoader *)loaderWithRequest:(KTVHCDataRequest *)request
 {
-    if (!request || request.URL.absoluteString.length <= 0)
-    {
+    if (!request || request.URL.absoluteString.length <= 0) {
         KTVHCLogDataStorage(@"Invaild loader request, %@", request.URL);
         return nil;
     }
-    KTVHCDataLoader * loader = [KTVHCDataLoader loaderWithRequest:request];
+    KTVHCDataLoader *loader = [[KTVHCDataLoader alloc] initWithRequest:request];
     return loader;
 }
 

+ 16 - 21
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataUnit.h

@@ -11,9 +11,9 @@
 
 @class KTVHCDataUnit;
 
-@protocol KTVHCDataUnitFileDelegate <NSObject>
+@protocol KTVHCDataUnitDelegate <NSObject>
 
-- (void)unitShouldRearchive:(KTVHCDataUnit *)unit;
+- (void)ktv_unitDidChangeMetadata:(KTVHCDataUnit *)unit;
 
 @end
 
@@ -22,40 +22,35 @@
 + (instancetype)new NS_UNAVAILABLE;
 - (instancetype)init NS_UNAVAILABLE;
 
-+ (instancetype)unitWithURL:(NSURL *)URL;
+- (instancetype)initWithURL:(NSURL *)URL;
 
-@property (nonatomic, assign, readonly) BOOL valid;
+@property (nonatomic, copy, readonly) NSError *error;
 
-@property (nonatomic, copy, readonly) NSURL * URL;
-@property (nonatomic, copy, readonly) NSURL * fileURL;
-@property (nonatomic, copy, readonly) NSString * key;       // Unique Identifier.
-
-@property (nonatomic, assign, readonly) NSTimeInterval createTimeInterval;
-@property (nonatomic, assign, readonly) NSTimeInterval lastItemCreateInterval;
-
-@property (nonatomic, copy, readonly) NSDictionary * requestHeaders;
-@property (nonatomic, copy, readonly) NSDictionary * responseHeaders;
-
-@property (nonatomic, assign, readonly) long long totalLength;
-@property (nonatomic, assign, readonly) long long cacheLength;
-@property (nonatomic, assign, readonly) long long validLength;
+@property (nonatomic, copy, readonly) NSURL *URL;
+@property (nonatomic, copy, readonly) NSURL *completeURL;
+@property (nonatomic, copy, readonly) NSString *key;       // Unique Identifier.
+@property (nonatomic, copy, readonly) NSDictionary *responseHeaders;
+@property (nonatomic, readonly) NSTimeInterval createTimeInterval;
+@property (nonatomic, readonly) NSTimeInterval lastItemCreateInterval;
+@property (nonatomic, readonly) long long totalLength;
+@property (nonatomic, readonly) long long cacheLength;
+@property (nonatomic, readonly) long long validLength;
 
 /**
  *  Unit Item
  */
-- (NSArray <KTVHCDataUnitItem *> *)unitItems;
+- (NSArray<KTVHCDataUnitItem *> *)unitItems;
 - (void)insertUnitItem:(KTVHCDataUnitItem *)unitItem;
 
 /**
  *  Info Sync
  */
-- (void)updateRequestHeaders:(NSDictionary *)requestHeaders;
 - (void)updateResponseHeaders:(NSDictionary *)responseHeaders totalLength:(long long)totalLength;
 
 /**
  *  Working
  */
-@property (nonatomic, assign, readonly) NSInteger workingCount;
+@property (nonatomic, readonly) NSInteger workingCount;
 
 - (void)workingRetain;
 - (void)workingRelease;
@@ -63,7 +58,7 @@
 /**
  *  File Control
  */
-@property (nonatomic, weak) id <KTVHCDataUnitFileDelegate> fileDelegate;
+@property (nonatomic, weak) id <KTVHCDataUnitDelegate> delegate;
 
 - (void)deleteFiles;
 

+ 127 - 175
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataUnit.m

@@ -7,61 +7,49 @@
 //
 
 #import "KTVHCDataUnit.h"
-#import "KTVHCURLTools.h"
-#import "KTVHCPathTools.h"
+#import "KTVHCPathTool.h"
+#import "KTVHCURLTool.h"
+#import "KTVHCError.h"
 #import "KTVHCLog.h"
 
 @interface KTVHCDataUnit ()
 
-@property (nonatomic, strong) NSRecursiveLock * coreLock;
-@property (nonatomic, strong) NSMutableArray <KTVHCDataUnitItem *> * unitItemsInternal;
-@property (nonatomic, strong) NSMutableArray <NSArray <KTVHCDataUnitItem *> *> * lockingUnitItems;
+@property (nonatomic, strong) NSRecursiveLock *coreLock;
+@property (nonatomic, strong) NSMutableArray<KTVHCDataUnitItem *> *unitItemsInternal;
+@property (nonatomic, strong) NSMutableArray<NSArray<KTVHCDataUnitItem *> *> *lockingUnitItems;
 
 @end
 
 @implementation KTVHCDataUnit
 
-+ (instancetype)unitWithURL:(NSURL *)URL
-{
-    return [[self alloc] initWithURL:URL];
-}
-
 - (instancetype)initWithURL:(NSURL *)URL
 {
-    if (self = [super init])
-    {
-        KTVHCLogAlloc(self);
-        _URL = URL;
-        _key = [KTVHCURLTools keyWithURL:self.URL];
-        _createTimeInterval = [NSDate date].timeIntervalSince1970;
-        _valid = YES;
-        [self prepare];
+    if (self = [super init]) {
+        self->_URL = [URL copy];
+        self->_key = [[KTVHCURLTool tool] keyWithURL:self.URL];
+        self->_createTimeInterval = [NSDate date].timeIntervalSince1970;
+        [self commonInit];
     }
     return self;
 }
 
 - (instancetype)initWithCoder:(NSCoder *)aDecoder
 {
-    if (self = [super init])
-    {
-        KTVHCLogAlloc(self);
+    if (self = [super init]) {
         @try {
-            _URL = [NSURL URLWithString:[aDecoder decodeObjectForKey:@"URLString"]];
-            _key = [aDecoder decodeObjectForKey:@"uniqueIdentifier"];
-            _valid = YES;
-        } @catch (NSException * exception) {
-            _valid = NO;
+            self->_URL = [NSURL URLWithString:[aDecoder decodeObjectForKey:@"URLString"]];
+            self->_key = [aDecoder decodeObjectForKey:@"uniqueIdentifier"];
+        } @catch (NSException *exception) {
+            self->_error = [KTVHCError errorForException:exception];
         }
         @try {
-            _createTimeInterval = [[aDecoder decodeObjectForKey:@"createTimeInterval"] doubleValue];
-            _requestHeaders = [aDecoder decodeObjectForKey:@"requestHeaderFields"];
-            _responseHeaders = [aDecoder decodeObjectForKey:@"responseHeaderFields"];
-            _totalLength = [[aDecoder decodeObjectForKey:@"totalContentLength"] longLongValue];
-            self.unitItemsInternal = [aDecoder decodeObjectForKey:@"unitItems"];
-            [self prepare];
-            _valid = _valid && YES;
-        } @catch (NSException * exception) {
-            _valid = NO;
+            self->_createTimeInterval = [[aDecoder decodeObjectForKey:@"createTimeInterval"] doubleValue];
+            self->_responseHeaders = [aDecoder decodeObjectForKey:@"responseHeaderFields"];
+            self->_totalLength = [[aDecoder decodeObjectForKey:@"totalContentLength"] longLongValue];
+            self->_unitItemsInternal = [[aDecoder decodeObjectForKey:@"unitItems"] mutableCopy];
+            [self commonInit];
+        } @catch (NSException *exception) {
+            self->_error = [KTVHCError errorForException:exception];
         }
     }
     return self;
@@ -73,7 +61,6 @@
     [aCoder encodeObject:self.URL.absoluteString forKey:@"URLString"];
     [aCoder encodeObject:self.key forKey:@"uniqueIdentifier"];
     [aCoder encodeObject:@(self.createTimeInterval) forKey:@"createTimeInterval"];
-    [aCoder encodeObject:self.requestHeaders forKey:@"requestHeaderFields"];
     [aCoder encodeObject:self.responseHeaders forKey:@"responseHeaderFields"];
     [aCoder encodeObject:@(self.totalLength) forKey:@"totalContentLength"];
     [aCoder encodeObject:self.unitItemsInternal forKey:@"unitItems"];
@@ -85,63 +72,53 @@
     KTVHCLogDealloc(self);
 }
 
-- (void)prepare
+- (void)commonInit
 {
+    KTVHCLogAlloc(self);
     [self lock];
-    if (!self.unitItemsInternal)
-    {
+    if (!self.unitItemsInternal) {
         self.unitItemsInternal = [NSMutableArray array];
     }
-    if (self.unitItemsInternal.count > 0)
-    {
-        NSMutableArray * removeArray = [NSMutableArray array];
-        for (KTVHCDataUnitItem * obj in self.unitItemsInternal)
-        {
-            if (obj.length <= 0)
-            {
-                [KTVHCPathTools deleteFileAtPath:obj.absolutePath];
-                [removeArray addObject:obj];
-            }
+    NSMutableArray *removal = [NSMutableArray array];
+    for (KTVHCDataUnitItem *obj in self.unitItemsInternal) {
+        if (obj.length == 0) {
+            [KTVHCPathTool deleteFileAtPath:obj.absolutePath];
+            [removal addObject:obj];
         }
-        [self.unitItemsInternal removeObjectsInArray:removeArray];
-        [removeArray removeAllObjects];
-        [self sortUnitItems];
     }
-    KTVHCLogDataUnit(@"%p, Create Unit\nURL : %@\nkey : %@\ntimeInterval : %@\ntotalLength : %lld\ncacheLength : %lld\nvaildLength : %lld\nrequestHeaders : %@\nresponseHeaders : %@\nunitItems : %@", self, self.URL, self.key, [NSDate dateWithTimeIntervalSince1970:self.createTimeInterval], self.totalLength, self.cacheLength, self.validLength, self.requestHeaders, self.responseHeaders, self.unitItemsInternal);
+    [self.unitItemsInternal removeObjectsInArray:removal];
+    [self sortUnitItems];
+    KTVHCLogDataUnit(@"%p, Create Unit\nURL : %@\nkey : %@\ntimeInterval : %@\ntotalLength : %lld\ncacheLength : %lld\nvaildLength : %lld\nresponseHeaders : %@\nunitItems : %@", self, self.URL, self.key, [NSDate dateWithTimeIntervalSince1970:self.createTimeInterval], self.totalLength, self.cacheLength, self.validLength, self.responseHeaders, self.unitItemsInternal);
     [self unlock];
 }
 
 - (void)sortUnitItems
 {
     [self lock];
-    KTVHCLogDataSourceQueue(@"%p, Sort unitItems - Begin\n%@", self, self.unitItemsInternal);
-    [self.unitItemsInternal sortUsingComparator:^NSComparisonResult(KTVHCDataUnitItem * obj1, KTVHCDataUnitItem * obj2) {
+    KTVHCLogDataUnit(@"%p, Sort unitItems - Begin\n%@", self, self.unitItemsInternal);
+    [self.unitItemsInternal sortUsingComparator:^NSComparisonResult(KTVHCDataUnitItem *obj1, KTVHCDataUnitItem *obj2) {
         NSComparisonResult result = NSOrderedDescending;
-        if (obj1.offset < obj2.offset)
-        {
+        if (obj1.offset < obj2.offset) {
             result = NSOrderedAscending;
-        }
-        else if ((obj1.offset == obj2.offset) && (obj1.length > obj2.length))
-        {
+        } else if ((obj1.offset == obj2.offset) && (obj1.length > obj2.length)) {
             result = NSOrderedAscending;
         }
         return result;
     }];
-    KTVHCLogDataSourceQueue(@"%p, Sort unitItems - End  \n%@", self, self.unitItemsInternal);
+    KTVHCLogDataUnit(@"%p, Sort unitItems - End  \n%@", self, self.unitItemsInternal);
     [self unlock];
 }
 
-- (NSArray <KTVHCDataUnitItem *> *)unitItems
+- (NSArray<KTVHCDataUnitItem *> *)unitItems
 {
     [self lock];
-    NSMutableArray * objs = [NSMutableArray array];
-    for (KTVHCDataUnitItem * obj in self.unitItemsInternal)
-    {
+    NSMutableArray *objs = [NSMutableArray array];
+    for (KTVHCDataUnitItem *obj in self.unitItemsInternal) {
         [objs addObject:[obj copy]];
     }
-    KTVHCLogDataSourceQueue(@"%p, Get unitItems\n%@", self, self.unitItemsInternal);
+    KTVHCLogDataUnit(@"%p, Get unitItems\n%@", self, self.unitItemsInternal);
     [self unlock];
-    return [objs copy];
+    return objs;
 }
 
 - (void)insertUnitItem:(KTVHCDataUnitItem *)unitItem
@@ -151,48 +128,58 @@
     [self sortUnitItems];
     KTVHCLogDataUnit(@"%p, Insert unitItem, %@", self, unitItem);
     [self unlock];
-    [self.fileDelegate unitShouldRearchive:self];
-}
-
-- (void)updateRequestHeaders:(NSDictionary *)requestHeaders
-{
-    [self lock];
-    _requestHeaders = requestHeaders;
-    KTVHCLogDataUnit(@"%p, Update requestHeaders\n%@", self, self.requestHeaders);
-    [self unlock];
-    [self.fileDelegate unitShouldRearchive:self];
+    [self.delegate ktv_unitDidChangeMetadata:self];
 }
 
 - (void)updateResponseHeaders:(NSDictionary *)responseHeaders totalLength:(long long)totalLength
 {
     [self lock];
-    _responseHeaders = responseHeaders;
-    _totalLength = totalLength;
+    BOOL needs = NO;
+    static NSArray *whiteList = nil;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        whiteList = @[@"Accept-Ranges",
+                      @"Connection",
+                      @"Content-Type",
+                      @"Server"];
+    });
+    NSMutableDictionary *headers = [NSMutableDictionary dictionary];
+    for (NSString *key in whiteList) {
+        NSString *value = [responseHeaders objectForKey:key];
+        if (value) {
+            [headers setObject:value forKey:key];
+        }
+    }
+    if (self.totalLength != totalLength || ![self.responseHeaders isEqualToDictionary:headers]) {
+        self->_responseHeaders = headers;
+        self->_totalLength = totalLength;
+        needs = YES;
+    }
     KTVHCLogDataUnit(@"%p, Update responseHeaders\ntotalLength : %lld\n%@", self, self.totalLength, self.responseHeaders);
     [self unlock];
-    [self.fileDelegate unitShouldRearchive:self];
+    if (needs) {
+        [self.delegate ktv_unitDidChangeMetadata:self];
+    }
 }
 
-- (NSURL *)fileURL
+- (NSURL *)completeURL
 {
     [self lock];
-    NSURL * fileURL = nil;
-    KTVHCDataUnitItem * item = self.unitItemsInternal.firstObject;
-    if (item.offset == 0 && item.length > 0 && item.length == self.totalLength)
-    {
-        fileURL = [NSURL fileURLWithPath:item.absolutePath];
-        KTVHCLogDataUnit(@"%p, Get file path\n%@", self, fileURL);
+    NSURL *completeURL = nil;
+    KTVHCDataUnitItem *item = self.unitItemsInternal.firstObject;
+    if (item.offset == 0 && item.length > 0 && item.length == self.totalLength) {
+        completeURL = [NSURL fileURLWithPath:item.absolutePath];
+        KTVHCLogDataUnit(@"%p, Get file path\n%@", self, completeURL);
     }
     [self unlock];
-    return fileURL;
+    return completeURL;
 }
 
 - (long long)cacheLength
 {
     [self lock];
     long long length = 0;
-    for (KTVHCDataUnitItem * obj in self.unitItemsInternal)
-    {
+    for (KTVHCDataUnitItem *obj in self.unitItemsInternal) {
         length += obj.length;
     }
     [self unlock];
@@ -204,8 +191,7 @@
     [self lock];
     long long offset = 0;
     long long length = 0;
-    for (KTVHCDataUnitItem * obj in self.unitItemsInternal)
-    {
+    for (KTVHCDataUnitItem *obj in self.unitItemsInternal) {
         long long invalidLength = MAX(offset - obj.offset, 0);
         long long vaildLength = MAX(obj.length - invalidLength, 0);
         offset = MAX(offset, obj.offset + obj.length);
@@ -219,10 +205,8 @@
 {
     [self lock];
     NSTimeInterval timeInterval = self.createTimeInterval;
-    for (KTVHCDataUnitItem * obj in self.unitItemsInternal)
-    {
-        if (obj.createTimeInterval > timeInterval)
-        {
+    for (KTVHCDataUnitItem *obj in self.unitItemsInternal) {
+        if (obj.createTimeInterval > timeInterval) {
             timeInterval = obj.createTimeInterval;
         }
     }
@@ -233,37 +217,31 @@
 - (void)workingRetain
 {
     [self lock];
-    _workingCount++;
+    self->_workingCount += 1;
     KTVHCLogDataUnit(@"%p, Working retain  : %ld", self, (long)self.workingCount);
     [self unlock];
 }
 
 - (void)workingRelease
 {
-    BOOL mergeSuccess = NO;
     [self lock];
-    _workingCount--;
+    self->_workingCount -= 1;
     KTVHCLogDataUnit(@"%p, Working release : %ld", self, (long)self.workingCount);
-    if (self.workingCount <= 0)
-    {
-        mergeSuccess = [self mergeFilesIfNeeded];
-    }
+    BOOL needs = [self mergeFilesIfNeeded];
     [self unlock];
-    if (mergeSuccess)
-    {
-        [self.fileDelegate unitShouldRearchive:self];
+    if (needs) {
+        [self.delegate ktv_unitDidChangeMetadata:self];
     }
 }
 
 - (void)deleteFiles
 {
-    if (!self.URL)
-    {
+    if (!self.URL) {
         return;
     }
     [self lock];
-    NSString * path = [KTVHCPathTools directoryPathWithURL:self.URL];
-    [KTVHCPathTools deleteDirectoryAtPath:path];
+    NSString *path = [KTVHCPathTool directoryPathWithURL:self.URL];
+    [KTVHCPathTool deleteDirectoryAtPath:path];
     KTVHCLogDataUnit(@"%p, Delete files", self);
     [self unlock];
 }
@@ -271,72 +249,56 @@
 - (BOOL)mergeFilesIfNeeded
 {
     [self lock];
-    if (self.workingCount > 0 || self.totalLength <= 0 || self.unitItemsInternal.count <= 0)
-    {
+    if (self.workingCount > 0 || self.totalLength == 0 || self.unitItemsInternal.count == 0) {
         [self unlock];
         return NO;
     }
-    NSString * path = [KTVHCPathTools completeFilePathWithURL:self.URL];
-    if ([self.unitItemsInternal.firstObject.absolutePath isEqualToString:path])
-    {
+    NSString *path = [KTVHCPathTool completeFilePathWithURL:self.URL];
+    if ([self.unitItemsInternal.firstObject.absolutePath isEqualToString:path]) {
         [self unlock];
         return NO;
     }
-    if (self.totalLength != self.validLength)
-    {
+    if (self.totalLength != self.validLength) {
         [self unlock];
         return NO;
     }
-    BOOL failed = NO;
+    NSError *error = nil;
     long long offset = 0;
-    [KTVHCPathTools deleteFileAtPath:path];
-    [KTVHCPathTools createFileAtPath:path];
-    NSFileHandle * writingHandle = [NSFileHandle fileHandleForWritingAtPath:path];
-    for (KTVHCDataUnitItem * obj in self.unitItemsInternal)
-    {
-        if (failed)
-        {
+    [KTVHCPathTool deleteFileAtPath:path];
+    [KTVHCPathTool createFileAtPath:path];
+    NSFileHandle *writingHandle = [NSFileHandle fileHandleForWritingAtPath:path];
+    for (KTVHCDataUnitItem *obj in self.unitItemsInternal) {
+        if (error) {
             break;
         }
         NSAssert(offset >= obj.offset, @"invaild unit item.");
-        if (offset >= (obj.offset + obj.length))
-        {
+        if (offset >= (obj.offset + obj.length)) {
             KTVHCLogDataUnit(@"%p, Merge files continue", self);
             continue;
         }
-        NSFileHandle * readingHandle = [NSFileHandle fileHandleForReadingAtPath:obj.absolutePath];
-        @try
-        {
+        NSFileHandle *readingHandle = [NSFileHandle fileHandleForReadingAtPath:obj.absolutePath];
+        @try {
             [readingHandle seekToFileOffset:offset - obj.offset];
-        }
-        @catch (NSException * exception)
-        {
+        } @catch (NSException *exception) {
             KTVHCLogDataUnit(@"%p, Merge files seek exception\n%@", self, exception);
-            failed = YES;
+            error = [KTVHCError errorForException:exception];
         }
-        if (failed)
-        {
+        if (error) {
             break;
         }
-        while (!failed)
-        {
-            @autoreleasepool
-            {
-                NSData * data = [readingHandle readDataOfLength:1024 * 1024 * 1];
-                if (data.length <= 0)
-                {
+        while (!error) {
+            @autoreleasepool {
+                NSData *data = [readingHandle readDataOfLength:1024 * 1024 * 1];
+                if (data.length == 0) {
                     KTVHCLogDataUnit(@"%p, Merge files break", self);
                     break;
                 }
                 KTVHCLogDataUnit(@"%p, Merge write data : %lld", self, (long long)data.length);
-                @try
-                {
+                @try {
                     [writingHandle writeData:data];
-                }
-                @catch (NSException * exception)
-                {
+                } @catch (NSException *exception) {
                     KTVHCLogDataUnit(@"%p, Merge files write exception\n%@", self, exception);
-                    failed = YES;
+                    error = [KTVHCError errorForException:exception];
                 }
             }
         }
@@ -344,28 +306,23 @@
         offset = obj.offset + obj.length;
         KTVHCLogDataUnit(@"%p, Merge next : %lld", self, offset);
     }
-    @try
-    {
+    @try {
         [writingHandle synchronizeFile];
         [writingHandle closeFile];
-    }
-    @catch (NSException * exception)
-    {
-        KTVHCLogDataUnit(@"%p, Merge files close exception, %d\n%@", self, failed, exception);
-        failed = YES;
+    } @catch (NSException *exception) {
+        KTVHCLogDataUnit(@"%p, Merge files close exception, %@", self, exception);
+        error = [KTVHCError errorForException:exception];
     }
     KTVHCLogDataUnit(@"%p, Merge finished\ntotalLength : %lld\noffset : %lld", self, self.totalLength, offset);
-    if (failed || [KTVHCPathTools sizeOfItemAtPath:path] != self.totalLength)
-    {
-        [KTVHCPathTools deleteFileAtPath:path];
+    if (error || [KTVHCPathTool sizeAtPath:path] != self.totalLength) {
+        [KTVHCPathTool deleteFileAtPath:path];
         [self unlock];
         return NO;
     }
     KTVHCLogDataUnit(@"%p, Merge replace items", self);
-    KTVHCDataUnitItem * item = [[KTVHCDataUnitItem alloc] initWithPath:path offset:0];
-    for (KTVHCDataUnitItem * obj in self.unitItemsInternal)
-    {
-        [KTVHCPathTools deleteFileAtPath:obj.absolutePath];
+    KTVHCDataUnitItem *item = [[KTVHCDataUnitItem alloc] initWithPath:path];
+    for (KTVHCDataUnitItem *obj in self.unitItemsInternal) {
+        [KTVHCPathTool deleteFileAtPath:obj.absolutePath];
     }
     [self.unitItemsInternal removeAllObjects];
     [self.unitItemsInternal addObject:item];
@@ -375,33 +332,28 @@
 
 - (void)lock
 {
-    if (!self.coreLock)
-    {
+    if (!self.coreLock) {
         self.coreLock = [[NSRecursiveLock alloc] init];
     }
     [self.coreLock lock];
-    if (!self.lockingUnitItems)
-    {
+    if (!self.lockingUnitItems) {
         self.lockingUnitItems = [NSMutableArray array];
     }
-    NSArray <KTVHCDataUnitItem *> * objs = [NSArray arrayWithArray:self.unitItemsInternal];
+    NSArray<KTVHCDataUnitItem *> *objs = [NSArray arrayWithArray:self.unitItemsInternal];
     [self.lockingUnitItems addObject:objs];
-    for (KTVHCDataUnitItem * obj in objs)
-    {
+    for (KTVHCDataUnitItem *obj in objs) {
         [obj lock];
     }
 }
 
 - (void)unlock
 {
-    NSArray <KTVHCDataUnitItem *> * objs = self.lockingUnitItems.lastObject;
+    NSArray<KTVHCDataUnitItem *> *objs = self.lockingUnitItems.lastObject;
     [self.lockingUnitItems removeLastObject];
-    if (self.lockingUnitItems.count <= 0)
-    {
+    if (self.lockingUnitItems.count <= 0) {
         self.lockingUnitItems = nil;
     }
-    for (KTVHCDataUnitItem * obj in objs)
-    {
+    for (KTVHCDataUnitItem *obj in objs) {
         [obj unlock];
     }
     [self.coreLock unlock];

+ 8 - 10
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataUnitItem.h

@@ -11,18 +11,16 @@
 @interface KTVHCDataUnitItem : NSObject <NSCopying, NSCoding, NSLocking>
 
 + (instancetype)new NS_UNAVAILABLE;
-- (instancetype)init NS_UNAVAILABLE;
 
-- (instancetype)initWithPath:(NSString *)path offset:(long long)offset;
+- (instancetype)initWithPath:(NSString *)path;
+- (instancetype)initWithPath:(NSString *)path offset:(uint64_t)offset;
 
-@property (nonatomic, assign, readonly) NSTimeInterval createTimeInterval;
+@property (nonatomic, copy, readonly) NSString *relativePath;
+@property (nonatomic, copy, readonly) NSString *absolutePath;
+@property (nonatomic, readonly) NSTimeInterval createTimeInterval;
+@property (nonatomic, readonly) long long offset;
+@property (nonatomic, readonly) long long length;
 
-@property (nonatomic, copy, readonly) NSString * relativePath;
-@property (nonatomic, copy, readonly) NSString * absolutePath;
-
-@property (nonatomic, assign, readonly) long long offset;
-@property (nonatomic, assign, readonly) long long length;
-
-- (void)setLength:(long long)length;
+- (void)updateLength:(long long)length;
 
 @end

+ 25 - 31
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataUnitItem.m

@@ -7,12 +7,12 @@
 //
 
 #import "KTVHCDataUnitItem.h"
-#import "KTVHCPathTools.h"
+#import "KTVHCPathTool.h"
 #import "KTVHCLog.h"
 
 @interface KTVHCDataUnitItem ()
 
-@property (nonatomic, strong) NSRecursiveLock * coreLock;
+@property (nonatomic, strong) NSRecursiveLock *coreLock;
 
 @end
 
@@ -21,7 +21,7 @@
 - (id)copyWithZone:(NSZone *)zone
 {
     [self lock];
-    KTVHCDataUnitItem * obj = [[KTVHCDataUnitItem alloc] initForCopy];
+    KTVHCDataUnitItem *obj = [[KTVHCDataUnitItem alloc] init];
     obj->_relativePath = self.relativePath;
     obj->_absolutePath = self.absolutePath;
     obj->_createTimeInterval = self.createTimeInterval;
@@ -31,37 +31,33 @@
     return obj;
 }
 
-- (instancetype)initForCopy
+- (instancetype)initWithPath:(NSString *)path
 {
-    if (self = [super init])
-    {
-        
-    }
-    return self;
+    return [self initWithPath:path offset:0];
 }
 
-- (instancetype)initWithPath:(NSString *)path offset:(long long)offset
+- (instancetype)initWithPath:(NSString *)path offset:(uint64_t)offset
 {
-    if (self = [super init])
-    {
-        KTVHCLogAlloc(self);
-        _createTimeInterval = [NSDate date].timeIntervalSince1970;
-        _relativePath = [KTVHCPathTools relativePathWithAbsoultePath:path];
-        _offset = offset;
-        [self prepare];
+    if (self = [super init]) {
+        self->_createTimeInterval = [NSDate date].timeIntervalSince1970;
+        self->_relativePath = [KTVHCPathTool converToRelativePath:path];
+        self->_absolutePath = [KTVHCPathTool converToAbsoultePath:path];
+        self->_offset = offset;
+        self->_length = [KTVHCPathTool sizeAtPath:self.absolutePath];
+        [self commonInit];
     }
     return self;
 }
 
 - (instancetype)initWithCoder:(NSCoder *)aDecoder
 {
-    if (self = [super init])
-    {
-        KTVHCLogAlloc(self);
-        _createTimeInterval = [[aDecoder decodeObjectForKey:@"createTimeInterval"] doubleValue];
-        _relativePath = [aDecoder decodeObjectForKey:@"relativePath"];
-        _offset = [[aDecoder decodeObjectForKey:@"offset"] longLongValue];
-        [self prepare];
+    if (self = [super init]) {
+        self->_createTimeInterval = [[aDecoder decodeObjectForKey:@"createTimeInterval"] doubleValue];
+        self->_relativePath = [aDecoder decodeObjectForKey:@"relativePath"];
+        self->_absolutePath = [KTVHCPathTool converToAbsoultePath:self.relativePath];
+        self->_offset = [[aDecoder decodeObjectForKey:@"offset"] longLongValue];
+        self->_length = [KTVHCPathTool sizeAtPath:self.absolutePath];
+        [self commonInit];
     }
     return self;
 }
@@ -78,25 +74,23 @@
     KTVHCLogDealloc(self);
 }
 
-- (void)prepare
+- (void)commonInit
 {
-    _absolutePath = [KTVHCPathTools absoultePathWithRelativePath:self.relativePath];
-    self.length = [KTVHCPathTools sizeOfItemAtPath:self.absolutePath];
+    KTVHCLogAlloc(self);
     KTVHCLogDataUnitItem(@"%p, Create Unit Item\nabsolutePath : %@\nrelativePath : %@\nOffset : %lld\nLength : %lld", self, self.absolutePath, self.relativePath, self.offset, self.length);
 }
 
-- (void)setLength:(long long)length
+- (void)updateLength:(long long)length
 {
     [self lock];
-    _length = length;
+    self->_length = length;
     KTVHCLogDataUnitItem(@"%p, Set length : %lld", self, length);
     [self unlock];
 }
 
 - (void)lock
 {
-    if (!self.coreLock)
-    {
+    if (!self.coreLock) {
         self.coreLock = [[NSRecursiveLock alloc] init];
     }
     [self.coreLock lock];

+ 1 - 1
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataUnitPool.h

@@ -21,7 +21,7 @@
 
 - (long long)totalCacheLength;
 
-- (NSArray <KTVHCDataCacheItem *> *)allCacheItem;
+- (NSArray<KTVHCDataCacheItem *> *)allCacheItem;
 - (KTVHCDataCacheItem *)cacheItemWithURL:(NSURL *)URL;
 
 - (void)deleteUnitWithURL:(NSURL *)URL;

+ 71 - 91
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataUnitPool.m

@@ -8,20 +8,20 @@
 
 #import "KTVHCDataUnitPool.h"
 #import "KTVHCDataUnitQueue.h"
-#import "KTVHCDataPrivate.h"
-#import "KTVHCPathTools.h"
-#import "KTVHCURLTools.h"
+#import "KTVHCData+Internal.h"
+#import "KTVHCPathTool.h"
+#import "KTVHCURLTool.h"
 #import "KTVHCLog.h"
 
 #import <UIKit/UIKit.h>
 
-@interface KTVHCDataUnitPool () <NSLocking, KTVHCDataUnitFileDelegate>
+@interface KTVHCDataUnitPool () <NSLocking, KTVHCDataUnitDelegate>
 
-@property (nonatomic, strong) NSRecursiveLock * coreLock;
-@property (nonatomic, strong) KTVHCDataUnitQueue * unitQueue;
-@property (nonatomic, assign) int64_t expectArchiveIndex;
-@property (nonatomic, assign) int64_t actualArchiveIndex;
+@property (nonatomic, strong) NSRecursiveLock *coreLock;
+@property (nonatomic, strong) KTVHCDataUnitQueue *unitQueue;
 @property (nonatomic, strong) dispatch_queue_t archiveQueue;
+@property (nonatomic) int64_t expectArchiveIndex;
+@property (nonatomic) int64_t actualArchiveIndex;
 
 @end
 
@@ -29,7 +29,7 @@
 
 + (instancetype)pool
 {
-    static KTVHCDataUnitPool * obj = nil;
+    static KTVHCDataUnitPool *obj = nil;
     static dispatch_once_t onceToken;
     dispatch_once(&onceToken, ^{
         obj = [[self alloc] init];
@@ -39,12 +39,10 @@
 
 - (instancetype)init
 {
-    if (self = [super init])
-    {
-        self.unitQueue = [KTVHCDataUnitQueue queueWithPath:[KTVHCPathTools archivePath]];
-        for (KTVHCDataUnit * obj in self.unitQueue.allUnits)
-        {
-            obj.fileDelegate = self;
+    if (self = [super init]) {
+        self.unitQueue = [[KTVHCDataUnitQueue alloc] initWithPath:[KTVHCPathTool archivePath]];
+        for (KTVHCDataUnit *obj in self.unitQueue.allUnits) {
+            obj.delegate = self;
         }
         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillTerminate:) name:UIApplicationWillTerminateNotification object:nil];
         [[NSNotificationCenter defaultCenter]  addObserver:self selector:@selector(applicationDidEnterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil];
@@ -61,17 +59,15 @@
 
 - (KTVHCDataUnit *)unitWithURL:(NSURL *)URL
 {
-    if (URL.absoluteString.length <= 0)
-    {
+    if (URL.absoluteString.length <= 0) {
         return nil;
     }
     [self lock];
-    NSString * key = [KTVHCURLTools keyWithURL:URL];
-    KTVHCDataUnit * unit = [self.unitQueue unitWithKey:key];
-    if (!unit)
-    {
-        unit = [KTVHCDataUnit unitWithURL:URL];
-        unit.fileDelegate = self;
+    NSString *key = [[KTVHCURLTool tool] keyWithURL:URL];
+    KTVHCDataUnit *unit = [self.unitQueue unitWithKey:key];
+    if (!unit) {
+        unit = [[KTVHCDataUnit alloc] initWithURL:URL];
+        unit.delegate = self;
         KTVHCLogDataUnitPool(@"%p, Insert Unit, %@", self, unit);
         [self.unitQueue putUnit:unit];
         [self setNeedsArchive];
@@ -85,9 +81,8 @@
 {
     [self lock];
     long long length = 0;
-    NSArray <KTVHCDataUnit *> * units = [self.unitQueue allUnits];
-    for (KTVHCDataUnit * obj in units)
-    {
+    NSArray<KTVHCDataUnit *> *units = [self.unitQueue allUnits];
+    for (KTVHCDataUnit *obj in units) {
         length += obj.cacheLength;
     }
     [self unlock];
@@ -96,48 +91,45 @@
 
 - (KTVHCDataCacheItem *)cacheItemWithURL:(NSURL *)URL
 {
-    if (URL.absoluteString.length <= 0)
-    {
+    if (URL.absoluteString.length <= 0) {
         return nil;
     }
     [self lock];
-    KTVHCDataCacheItem * cacheItem = nil;
-    NSString * key = [KTVHCURLTools keyWithURL:URL];
-    KTVHCDataUnit * obj = [self.unitQueue unitWithKey:key];
-    if (obj)
-    {
-        NSArray * items = obj.unitItems;
-        NSMutableArray * itemZones = [NSMutableArray array];
-        for (KTVHCDataUnitItem * unitItem in items)
-        {
-            KTVHCDataCacheItemZone * itemZone = [KTVHCDataCacheItemZone itemZoneWithOffset:unitItem.offset length:unitItem.length];
-            [itemZones addObject:itemZone];
+    KTVHCDataCacheItem *cacheItem = nil;
+    NSString *key = [[KTVHCURLTool tool] keyWithURL:URL];
+    KTVHCDataUnit *obj = [self.unitQueue unitWithKey:key];
+    if (obj) {
+        NSArray *items = obj.unitItems;
+        NSMutableArray *zones = [NSMutableArray array];
+        for (KTVHCDataUnitItem *item in items) {
+            KTVHCDataCacheItemZone *zone = [[KTVHCDataCacheItemZone alloc] initWithOffset:item.offset length:item.length];
+            [zones addObject:zone];
         }
-        if (itemZones.count <= 0)
-        {
-            itemZones = nil;
+        if (zones.count == 0) {
+            zones = nil;
         }
-        cacheItem = [KTVHCDataCacheItem itemWithURL:obj.URL totalLength:obj.totalLength cacheLength:obj.cacheLength vaildLength:obj.validLength zones:itemZones];
+        cacheItem = [[KTVHCDataCacheItem alloc] initWithURL:obj.URL
+                                                      zones:zones
+                                                totalLength:obj.totalLength
+                                                cacheLength:obj.cacheLength
+                                                vaildLength:obj.validLength];
     }
     [self unlock];
     return cacheItem;
 }
 
-- (NSArray <KTVHCDataCacheItem *> *)allCacheItem
+- (NSArray<KTVHCDataCacheItem *> *)allCacheItem
 {
     [self lock];
-    NSMutableArray * cacheItems = [NSMutableArray array];
-    NSArray <KTVHCDataUnit *> * units = [self.unitQueue allUnits];
-    for (KTVHCDataUnit * obj in units)
-    {
-        KTVHCDataCacheItem * cacheItem = [self cacheItemWithURL:obj.URL];
-        if (cacheItem)
-        {
+    NSMutableArray *cacheItems = [NSMutableArray array];
+    NSArray<KTVHCDataUnit *> *units = [self.unitQueue allUnits];
+    for (KTVHCDataUnit *obj in units) {
+        KTVHCDataCacheItem *cacheItem = [self cacheItemWithURL:obj.URL];
+        if (cacheItem) {
             [cacheItems addObject:cacheItem];
         }
     }
-    if (cacheItems.count <= 0)
-    {
+    if (cacheItems.count == 0) {
         cacheItems = nil;
     }
     [self unlock];
@@ -146,15 +138,13 @@
 
 - (void)deleteUnitWithURL:(NSURL *)URL
 {
-    if (URL.absoluteString.length <= 0)
-    {
+    if (URL.absoluteString.length <= 0) {
         return;
     }
     [self lock];
-    NSString * key = [KTVHCURLTools keyWithURL:URL];
-    KTVHCDataUnit * obj = [self.unitQueue unitWithKey:key];
-    if (obj && obj.workingCount <= 0)
-    {
+    NSString *key = [[KTVHCURLTool tool] keyWithURL:URL];
+    KTVHCDataUnit *obj = [self.unitQueue unitWithKey:key];
+    if (obj && obj.workingCount <= 0) {
         KTVHCLogDataUnit(@"%p, Delete Unit\nUnit : %@\nFunc : %s", self, obj, __func__);
         [obj deleteFiles];
         [self.unitQueue popUnit:obj];
@@ -165,15 +155,14 @@
 
 - (void)deleteUnitsWithLength:(long long)length
 {
-    if (length <= 0)
-    {
+    if (length <= 0) {
         return;
     }
     [self lock];
     BOOL needArchive = NO;
     long long currentLength = 0;
-    NSArray <KTVHCDataUnit *> * units = [self.unitQueue allUnits];
-    [units sortedArrayUsingComparator:^NSComparisonResult(KTVHCDataUnit * obj1, KTVHCDataUnit * obj2) {
+    NSArray<KTVHCDataUnit *> *units = [self.unitQueue allUnits];
+    [units sortedArrayUsingComparator:^NSComparisonResult(KTVHCDataUnit *obj1, KTVHCDataUnit *obj2) {
         NSComparisonResult result = NSOrderedDescending;
         [obj1 lock];
         [obj2 lock];
@@ -188,10 +177,8 @@
         [obj2 unlock];
         return result;
     }];
-    for (KTVHCDataUnit * obj in units)
-    {
-        if (obj.workingCount <= 0)
-        {
+    for (KTVHCDataUnit *obj in units) {
+        if (obj.workingCount <= 0) {
             [obj lock];
             currentLength += obj.cacheLength;
             KTVHCLogDataUnit(@"%p, Delete Unit\nUnit : %@\nFunc : %s", self, obj, __func__);
@@ -200,13 +187,11 @@
             [self.unitQueue popUnit:obj];
             needArchive = YES;
         }
-        if (currentLength >= length)
-        {
+        if (currentLength >= length) {
             break;
         }
     }
-    if (needArchive)
-    {
+    if (needArchive) {
         [self setNeedsArchive];
     }
     [self unlock];
@@ -216,43 +201,33 @@
 {
     [self lock];
     BOOL needArchive = NO;
-    NSArray <KTVHCDataUnit *> * units = [self.unitQueue allUnits];
-    for (KTVHCDataUnit * obj in units)
-    {
-        if (obj.workingCount <= 0)
-        {
+    NSArray<KTVHCDataUnit *> *units = [self.unitQueue allUnits];
+    for (KTVHCDataUnit *obj in units) {
+        if (obj.workingCount <= 0) {
             KTVHCLogDataUnit(@"%p, Delete Unit\nUnit : %@\nFunc : %s", self, obj, __func__);
             [obj deleteFiles];
             [self.unitQueue popUnit:obj];
             needArchive = YES;
         }
     }
-    if (needArchive)
-    {
+    if (needArchive) {
         [self setNeedsArchive];
     }
     [self unlock];
 }
 
-- (void)unitShouldRearchive:(KTVHCDataUnit *)unit
-{
-    [self setNeedsArchive];
-}
-
 - (void)setNeedsArchive
 {
     [self lock];
     self.expectArchiveIndex += 1;
     int64_t expectArchiveIndex = self.expectArchiveIndex;
     [self unlock];
-    if (!self.archiveQueue)
-    {
+    if (!self.archiveQueue) {
         self.archiveQueue = dispatch_queue_create("KTVHTTPCache-archiveQueue", DISPATCH_QUEUE_SERIAL);
     }
     dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), self.archiveQueue, ^{
         [self lock];
-        if (self.expectArchiveIndex == expectArchiveIndex)
-        {
+        if (self.expectArchiveIndex == expectArchiveIndex) {
             [self archiveIfNeeded];
         }
         [self unlock];
@@ -262,14 +237,20 @@
 - (void)archiveIfNeeded
 {
     [self lock];
-    if (self.actualArchiveIndex != self.expectArchiveIndex)
-    {
+    if (self.actualArchiveIndex != self.expectArchiveIndex) {
         self.actualArchiveIndex = self.expectArchiveIndex;
         [self.unitQueue archive];
     }
     [self unlock];
 }
 
+#pragma mark - KTVHCDataUnitDelegate
+
+- (void)ktv_unitDidChangeMetadata:(KTVHCDataUnit *)unit
+{
+    [self setNeedsArchive];
+}
+
 #pragma mark - UIApplicationWillTerminateNotification
 
 - (void)applicationWillTerminate:(NSNotification *)notification
@@ -291,8 +272,7 @@
 
 - (void)lock
 {
-    if (!self.coreLock)
-    {
+    if (!self.coreLock) {
         self.coreLock = [[NSRecursiveLock alloc] init];
     }
     [self.coreLock lock];

+ 2 - 2
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataUnitQueue.h

@@ -14,9 +14,9 @@
 + (instancetype)new NS_UNAVAILABLE;
 - (instancetype)init NS_UNAVAILABLE;
 
-+ (instancetype)queueWithPath:(NSString *)path;
+- (instancetype)initWithPath:(NSString *)path NS_DESIGNATED_INITIALIZER;
 
-- (NSArray <KTVHCDataUnit *> *)allUnits;
+- (NSArray<KTVHCDataUnit *> *)allUnits;
 - (KTVHCDataUnit *)unitWithKey:(NSString *)key;
 
 - (void)putUnit:(KTVHCDataUnit *)unit;

+ 20 - 35
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDataStorage/KTVHCDataUnitQueue.m

@@ -11,62 +11,51 @@
 
 @interface KTVHCDataUnitQueue ()
 
-@property (nonatomic, copy) NSString * path;
-@property (nonatomic, strong) NSMutableArray <KTVHCDataUnit *> * unitArray;
+@property (nonatomic, copy) NSString *path;
+@property (nonatomic, strong) NSMutableArray<KTVHCDataUnit *> *unitArray;
 
 @end
 
 @implementation KTVHCDataUnitQueue
 
-+ (instancetype)queueWithPath:(NSString *)path
-{
-    return [[self alloc] initWithPath:path];
-}
-
 - (instancetype)initWithPath:(NSString *)path
 {
-    if (self = [super init])
-    {
+    if (self = [super init]) {
         self.path = path;
-        NSMutableArray * unitArray = nil;
+        NSMutableArray *unitArray = nil;
         @try {
             unitArray = [NSKeyedUnarchiver unarchiveObjectWithFile:self.path];
-        } @catch (NSException * exception) {
+        } @catch (NSException *exception) {
             KTVHCLogDataUnitQueue(@"%p, Init exception\nname : %@\breason : %@\nuserInfo : %@", self, exception.name, exception.reason, exception.userInfo);
         }
         self.unitArray = [NSMutableArray array];
-        for (KTVHCDataUnit * obj in unitArray) {
-            if (obj.valid) {
-                [self.unitArray addObject:obj];
-            } else {
+        for (KTVHCDataUnit *obj in unitArray) {
+            if (obj.error) {
                 [obj deleteFiles];
+            } else {
+                [self.unitArray addObject:obj];
             }
         }
     }
     return self;
 }
 
-- (NSArray <KTVHCDataUnit *> *)allUnits
+- (NSArray<KTVHCDataUnit *> *)allUnits
 {
-    if (self.unitArray.count <= 0)
-    {
+    if (self.unitArray.count <= 0) {
         return nil;
     }
-    NSArray <KTVHCDataUnit *> * units = [self.unitArray copy];
-    return units;
+    return [self.unitArray copy];
 }
 
 - (KTVHCDataUnit *)unitWithKey:(NSString *)key
 {
-    if (key.length <= 0)
-    {
+    if (key.length <= 0) {
         return nil;
     }
-    KTVHCDataUnit * unit = nil;
-    for (KTVHCDataUnit * obj in self.unitArray)
-    {
-        if ([obj.key isEqualToString:key])
-        {
+    KTVHCDataUnit *unit = nil;
+    for (KTVHCDataUnit *obj in self.unitArray) {
+        if ([obj.key isEqualToString:key]) {
             unit = obj;
             break;
         }
@@ -76,24 +65,20 @@
 
 - (void)putUnit:(KTVHCDataUnit *)unit
 {
-    if (!unit)
-    {
+    if (!unit) {
         return;
     }
-    if (![self.unitArray containsObject:unit])
-    {
+    if (![self.unitArray containsObject:unit]) {
         [self.unitArray addObject:unit];
     }
 }
 
 - (void)popUnit:(KTVHCDataUnit *)unit
 {
-    if (!unit)
-    {
+    if (!unit) {
         return;
     }
-    if ([self.unitArray containsObject:unit])
-    {
+    if ([self.unitArray containsObject:unit]) {
         [self.unitArray removeObject:unit];
     }
 }

+ 10 - 10
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDownload/KTVHCDownload.h

@@ -7,9 +7,9 @@
 //
 
 #import <Foundation/Foundation.h>
-#import "KTVHCDataRequest.h"
 #import "KTVHCDataResponse.h"
-#import "KTVHCCommon.h"
+#import "KTVHCDataRequest.h"
+#import "KTVHCMacro.h"
 
 KTVHTTPCACHE_EXTERN NSString * const KTVHCContentTypeVideo;
 KTVHTTPCACHE_EXTERN NSString * const KTVHCContentTypeAudio;
@@ -21,9 +21,9 @@ KTVHTTPCACHE_EXTERN NSString * const KTVHCContentTypeBinaryOctetStream;
 
 @protocol KTVHCDownloadDelegate <NSObject>
 
-- (void)download:(KTVHCDownload *)download didCompleteWithError:(NSError *)error;
-- (void)download:(KTVHCDownload *)download didReceiveResponse:(KTVHCDataResponse *)response;
-- (void)download:(KTVHCDownload *)download didReceiveData:(NSData *)data;
+- (void)ktv_download:(KTVHCDownload *)download didCompleteWithError:(NSError *)error;
+- (void)ktv_download:(KTVHCDownload *)download didReceiveResponse:(KTVHCDataResponse *)response;
+- (void)ktv_download:(KTVHCDownload *)download didReceiveData:(NSData *)data;
 
 @end
 
@@ -34,19 +34,19 @@ KTVHTTPCACHE_EXTERN NSString * const KTVHCContentTypeBinaryOctetStream;
 
 + (instancetype)download;
 
-@property (nonatomic, assign) NSTimeInterval timeoutInterval;
+@property (nonatomic) NSTimeInterval timeoutInterval;
 
 /**
  *  Header Fields
  */
-@property (nonatomic, copy) NSArray <NSString *> * whitelistHeaderKeys;
-@property (nonatomic, copy) NSDictionary <NSString *, NSString *> * additionalHeaders;
+@property (nonatomic, copy) NSArray<NSString *> *whitelistHeaderKeys;
+@property (nonatomic, copy) NSDictionary<NSString *, NSString *> *additionalHeaders;
 
 /**
  *  Content-Type
  */
-@property (nonatomic, copy) NSArray <NSString *> * acceptContentTypes;
-@property (nonatomic, copy) BOOL (^unsupportContentTypeFilter)(NSURL * URL, NSString * contentType);
+@property (nonatomic, copy) NSArray<NSString *> *acceptableContentTypes;
+@property (nonatomic, copy) BOOL (^unacceptableContentTypeDisposer)(NSURL *URL, NSString *contentType);
 
 - (NSURLSessionTask *)downloadWithRequest:(KTVHCDataRequest *)request delegate:(id<KTVHCDownloadDelegate>)delegate;
 

+ 118 - 135
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCDownload/KTVHCDownload.m

@@ -7,6 +7,7 @@
 //
 
 #import "KTVHCDownload.h"
+#import "KTVHCData+Internal.h"
 #import "KTVHCDataUnitPool.h"
 #import "KTVHCDataStorage.h"
 #import "KTVHCError.h"
@@ -22,13 +23,14 @@ NSString * const KTVHCContentTypeBinaryOctetStream      = @"binary/octet-stream"
 
 @interface KTVHCDownload () <NSURLSessionDataDelegate, NSLocking>
 
-@property (nonatomic, strong) NSLock * coreLock;
-@property (nonatomic, strong) NSURLSession * session;
-@property (nonatomic, strong) NSOperationQueue * sessionDelegateQueue;
-@property (nonatomic, strong) NSURLSessionConfiguration * sessionConfiguration;
-@property (nonatomic, strong) NSMutableDictionary <NSURLSessionTask *, NSError *> * errorDictionary;
-@property (nonatomic, strong) NSMutableDictionary <NSURLSessionTask *, KTVHCDataRequest *> * requestDictionary;
-@property (nonatomic, strong) NSMutableDictionary <NSURLSessionTask *, id<KTVHCDownloadDelegate>> * delegateDictionary;
+@property (nonatomic, strong) NSLock *coreLock;
+@property (nonatomic, strong) NSURLSession *session;
+@property (nonatomic, strong) NSOperationQueue *sessionDelegateQueue;
+@property (nonatomic, strong) NSURLSessionConfiguration *sessionConfiguration;
+@property (nonatomic, strong) NSMutableDictionary<NSURLSessionTask *, NSError *> *errorDictionary;
+@property (nonatomic, strong) NSMutableDictionary<NSURLSessionTask *, KTVHCDataRequest *> *requestDictionary;
+@property (nonatomic, strong) NSMutableDictionary<NSURLSessionTask *, id<KTVHCDownloadDelegate>> *delegateDictionary;
+@property (nonatomic) UIBackgroundTaskIdentifier backgroundTask;
 
 @end
 
@@ -36,7 +38,7 @@ NSString * const KTVHCContentTypeBinaryOctetStream      = @"binary/octet-stream"
 
 + (instancetype)download
 {
-    static KTVHCDownload * obj = nil;
+    static KTVHCDownload *obj = nil;
     static dispatch_once_t onceToken;
     dispatch_once(&onceToken, ^{
         obj = [[self alloc] init];
@@ -46,10 +48,10 @@ NSString * const KTVHCContentTypeBinaryOctetStream      = @"binary/octet-stream"
 
 - (instancetype)init
 {
-    if (self = [super init])
-    {
+    if (self = [super init]) {
         KTVHCLogAlloc(self);
         self.timeoutInterval = 30.0f;
+        self.backgroundTask = UIBackgroundTaskInvalid;
         self.errorDictionary = [NSMutableDictionary dictionary];
         self.requestDictionary = [NSMutableDictionary dictionary];
         self.delegateDictionary = [NSMutableDictionary dictionary];
@@ -61,11 +63,11 @@ NSString * const KTVHCContentTypeBinaryOctetStream      = @"binary/octet-stream"
         self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration
                                                      delegate:self
                                                 delegateQueue:self.sessionDelegateQueue];
-        self.acceptContentTypes = @[KTVHCContentTypeVideo,
-                                    KTVHCContentTypeAudio,
-                                    KTVHCContentTypeApplicationMPEG4,
-                                    KTVHCContentTypeApplicationOctetStream,
-                                    KTVHCContentTypeBinaryOctetStream];
+        self.acceptableContentTypes = @[KTVHCContentTypeVideo,
+                                        KTVHCContentTypeAudio,
+                                        KTVHCContentTypeApplicationMPEG4,
+                                        KTVHCContentTypeApplicationOctetStream,
+                                        KTVHCContentTypeBinaryOctetStream];
         [[NSNotificationCenter defaultCenter] addObserver:self
                                                  selector:@selector(applicationDidEnterBackground:)
                                                      name:UIApplicationDidEnterBackgroundNotification
@@ -81,43 +83,45 @@ NSString * const KTVHCContentTypeBinaryOctetStream      = @"binary/octet-stream"
 - (void)dealloc
 {
     KTVHCLogDealloc(self);
+    [[NSNotificationCenter defaultCenter] removeObserver:self];
 }
 
-- (NSArray <NSString *> *)availableHeaderKeys
+- (NSArray<NSString *> *)availableHeaderKeys
 {
-    static NSArray <NSString *> * availableHeaderKeys = nil;
+    static NSArray<NSString *> *obj = nil;
     static dispatch_once_t onceToken;
     dispatch_once(&onceToken, ^{
-        availableHeaderKeys = @[@"User-Agent",
-                                @"Connection",
-                                @"Accept",
-                                @"Accept-Encoding",
-                                @"Accept-Language",
-                                @"Range"];
+        obj = @[@"User-Agent",
+                @"Connection",
+                @"Accept",
+                @"Accept-Encoding",
+                @"Accept-Language",
+                @"Range"];
     });
-    return availableHeaderKeys;
+    return obj;
 }
 
 - (NSURLSessionTask *)downloadWithRequest:(KTVHCDataRequest *)request delegate:(id<KTVHCDownloadDelegate>)delegate
 {
     [self lock];
-    NSMutableURLRequest * HTTPRequest = [NSMutableURLRequest requestWithURL:request.URL];
-    [request.headers enumerateKeysAndObjectsUsingBlock:^(NSString * key, NSString * obj, BOOL * stop) {
-        if ([[self availableHeaderKeys] containsObject:key] || [self.whitelistHeaderKeys containsObject:key]) {
-            [HTTPRequest setValue:obj forHTTPHeaderField:key];
+    NSMutableURLRequest *mRequest = [NSMutableURLRequest requestWithURL:request.URL];
+    mRequest.timeoutInterval = self.timeoutInterval;
+    mRequest.cachePolicy = NSURLRequestReloadIgnoringCacheData;
+    [request.headers enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *obj, BOOL *stop) {
+        if ([self.availableHeaderKeys containsObject:key] ||
+            [self.whitelistHeaderKeys containsObject:key]) {
+            [mRequest setValue:obj forHTTPHeaderField:key];
         }
     }];
-    HTTPRequest.timeoutInterval = self.timeoutInterval;
-    HTTPRequest.cachePolicy = NSURLRequestReloadIgnoringCacheData;
-    [self.additionalHeaders enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSString * _Nonnull obj, BOOL * _Nonnull stop) {
-        [HTTPRequest setValue:obj forHTTPHeaderField:key];
+    [self.additionalHeaders enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *obj, BOOL *stop) {
+        [mRequest setValue:obj forHTTPHeaderField:key];
     }];
-    NSURLSessionDataTask * task = [self.session dataTaskWithRequest:HTTPRequest];
-    task.priority = 1.0;
+    NSURLSessionDataTask *task = [self.session dataTaskWithRequest:mRequest];
     [self.requestDictionary setObject:request forKey:task];
     [self.delegateDictionary setObject:delegate forKey:task];
-    KTVHCLogDownload(@"%p, Add Request\nrequest : %@\nURL : %@\nheaders : %@\nHTTPRequest headers : %@\nCount : %d", self, request, request.URL, request.headers, HTTPRequest.allHTTPHeaderFields, (int)self.delegateDictionary.count);
+    task.priority = 1.0;
     [task resume];
+    KTVHCLogDownload(@"%p, Add Request\nrequest : %@\nURL : %@\nheaders : %@\nHTTPRequest headers : %@\nCount : %d", self, request, request.URL, request.headers, mRequest.allHTTPHeaderFields, (int)self.delegateDictionary.count);
     [self unlock];
     return task;
 }
@@ -126,92 +130,84 @@ NSString * const KTVHCContentTypeBinaryOctetStream      = @"binary/octet-stream"
 {
     [self lock];
     KTVHCLogDownload(@"%p, Complete\nError : %@", self, error);
-    id <KTVHCDownloadDelegate> delegate = [self.delegateDictionary objectForKey:task];
-    NSError * cancelError = [self.errorDictionary objectForKey:task];
-    if (cancelError)
-    {
-        error = cancelError;
+    if ([self.errorDictionary objectForKey:task]) {
+        error = [self.errorDictionary objectForKey:task];
     }
-    [delegate download:self didCompleteWithError:error];
+    id<KTVHCDownloadDelegate> delegate = [self.delegateDictionary objectForKey:task];
+    [delegate ktv_download:self didCompleteWithError:error];
     [self.delegateDictionary removeObjectForKey:task];
     [self.requestDictionary removeObjectForKey:task];
     [self.errorDictionary removeObjectForKey:task];
-    if (self.delegateDictionary.count <= 0)
-    {
-        [self cleanBackgroundTaskAsync];
+    if (self.delegateDictionary.count <= 0) {
+        [self endBackgroundTaskDelay];
     }
     [self unlock];
 }
 
-- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
+- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)task didReceiveResponse:(NSHTTPURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
 {
     [self lock];
-    NSHTTPURLResponse * HTTPResponse = (NSHTTPURLResponse *)response;
-    KTVHCDataRequest * dataRequest = [self.requestDictionary objectForKey:dataTask];
-    KTVHCDataResponse * dataResponse = [[KTVHCDataResponse alloc] initWithURL:dataRequest.URL headers:HTTPResponse.allHeaderFields];
-    KTVHCLogDownload(@"%p, Receive response\nrequest : %@\nresponse : %@\nHTTPResponse : %@", self, dataRequest, dataResponse, [(NSHTTPURLResponse *)response allHeaderFields]);
-    NSError * error = nil;
-    if (!error)
-    {
-        if (HTTPResponse.statusCode > 400)
-        {
-            error = [KTVHCError errorForResponseUnavailable:dataTask.currentRequest.URL request:dataTask.currentRequest response:dataTask.response];
+    KTVHCDataRequest *dataRequest = [self.requestDictionary objectForKey:task];
+    KTVHCDataResponse *dataResponse = [[KTVHCDataResponse alloc] initWithURL:dataRequest.URL headers:response.allHeaderFields];
+    KTVHCLogDownload(@"%p, Receive response\nrequest : %@\nresponse : %@\nHTTPResponse : %@", self, dataRequest, dataResponse, response.allHeaderFields);
+    NSError *error = nil;
+    if (!error) {
+        if (response.statusCode > 400) {
+            error = [KTVHCError errorForResponseUnavailable:task.currentRequest.URL
+                                                    request:task.currentRequest
+                                                   response:task.response];
         }
-        if (!error)
-        {
-            BOOL contentTypeVaild = NO;
-            if (dataResponse.contentType.length > 0)
-            {
-                for (NSString * obj in self.acceptContentTypes)
-                {
-                    if ([[dataResponse.contentType lowercaseString] containsString:[obj lowercaseString]])
-                    {
-                        contentTypeVaild = YES;
-                    }
-                }
-                if (!contentTypeVaild && self.unsupportContentTypeFilter)
-                {
-                    contentTypeVaild = self.unsupportContentTypeFilter(dataRequest.URL, dataResponse.contentType);
+    }
+    if (!error) {
+        BOOL vaild = NO;
+        if (dataResponse.contentType.length > 0) {
+            for (NSString *obj in self.acceptableContentTypes) {
+                if ([[dataResponse.contentType lowercaseString] containsString:[obj lowercaseString]]) {
+                    vaild = YES;
                 }
             }
-            if (!contentTypeVaild)
-            {
-                error = [KTVHCError errorForUnsupportContentType:dataTask.currentRequest.URL request:dataTask.currentRequest response:dataTask.response];
+            if (!vaild && self.unacceptableContentTypeDisposer) {
+                vaild = self.unacceptableContentTypeDisposer(dataRequest.URL, dataResponse.contentType);
             }
-            if (!error)
-            {
-                if (dataResponse.currentLength <= 0 ||
-                    (!KTVHCRangeIsFull(dataRequest.range) &&
-                     (dataResponse.currentLength != KTVHCRangeGetLength(dataRequest.range))))
-                {
-                    error = [KTVHCError errorForUnsupportContentType:dataTask.currentRequest.URL request:dataTask.currentRequest response:dataTask.response];
-                }
-                if (!error)
-                {
-                    long long length = dataResponse.currentLength + [KTVHCDataStorage storage].totalCacheLength - [KTVHCDataStorage storage].maxCacheLength;
-                    if (length > 0)
-                    {
-                        [[KTVHCDataUnitPool pool] deleteUnitsWithLength:length];
-                        length = dataResponse.currentLength + [KTVHCDataStorage storage].totalCacheLength - [KTVHCDataStorage storage].maxCacheLength;
-                        if (length > 0)
-                        {
-                            error = [KTVHCError errorForNotEnoughDiskSpace:dataResponse.totalLength request:dataResponse.currentLength totalCacheLength:[KTVHCDataStorage storage].totalCacheLength maxCacheLength:[KTVHCDataStorage storage].maxCacheLength];
-                        }
-                    }
-                }
+        }
+        if (!vaild) {
+            error = [KTVHCError errorForUnsupportContentType:task.currentRequest.URL
+                                                     request:task.currentRequest
+                                                    response:task.response];
+        }
+    }
+    if (!error) {
+        if (dataResponse.contentLength <= 0 ||
+            (!KTVHCRangeIsFull(dataRequest.range) &&
+             (dataResponse.contentLength != KTVHCRangeGetLength(dataRequest.range)))) {
+                error = [KTVHCError errorForUnsupportContentType:task.currentRequest.URL
+                                                         request:task.currentRequest
+                                                        response:task.response];
+            }
+    }
+    if (!error) {
+        long long (^getDeletionLength)(long long) = ^(long long desireLength){
+            return desireLength + [KTVHCDataStorage storage].totalCacheLength - [KTVHCDataStorage storage].maxCacheLength;
+        };
+        long long length = getDeletionLength(dataResponse.contentLength);
+        if (length > 0) {
+            [[KTVHCDataUnitPool pool] deleteUnitsWithLength:length];
+            length = getDeletionLength(dataResponse.contentLength);
+            if (length > 0) {
+                error = [KTVHCError errorForNotEnoughDiskSpace:dataResponse.totalLength
+                                                       request:dataResponse.contentLength
+                                              totalCacheLength:[KTVHCDataStorage storage].totalCacheLength
+                                                maxCacheLength:[KTVHCDataStorage storage].maxCacheLength];
             }
         }
     }
-    if (error)
-    {
+    if (error) {
         KTVHCLogDownload(@"%p, Invaild response\nError : %@", self, error);
-        [self.errorDictionary setObject:error forKey:dataTask];
+        [self.errorDictionary setObject:error forKey:task];
         completionHandler(NSURLSessionResponseCancel);
-    }
-    else
-    {
-        id <KTVHCDownloadDelegate> delegate = [self.delegateDictionary objectForKey:dataTask];
-        [delegate download:self didReceiveResponse:dataResponse];
+    } else {
+        id<KTVHCDownloadDelegate> delegate = [self.delegateDictionary objectForKey:task];
+        [delegate ktv_download:self didReceiveResponse:dataResponse];
         completionHandler(NSURLSessionResponseAllow);
     }
     [self unlock];
@@ -229,16 +225,15 @@ NSString * const KTVHCContentTypeBinaryOctetStream      = @"binary/octet-stream"
 {
     [self lock];
     KTVHCLogDownload(@"%p, Receive data - Begin\nLength : %lld\nURL : %@", self, (long long)data.length, dataTask.originalRequest.URL.absoluteString);
-    id <KTVHCDownloadDelegate> delegate = [self.delegateDictionary objectForKey:dataTask];
-    [delegate download:self didReceiveData:data];
+    id<KTVHCDownloadDelegate> delegate = [self.delegateDictionary objectForKey:dataTask];
+    [delegate ktv_download:self didReceiveData:data];
     KTVHCLogDownload(@"%p, Receive data - End\nLength : %lld\nURL : %@", self, (long long)data.length, dataTask.originalRequest.URL.absoluteString);
     [self unlock];
 }
 
 - (void)lock
 {
-    if (!self.coreLock)
-    {
+    if (!self.coreLock) {
         self.coreLock = [[NSLock alloc] init];
     }
     [self.coreLock lock];
@@ -251,53 +246,41 @@ NSString * const KTVHCContentTypeBinaryOctetStream      = @"binary/octet-stream"
 
 #pragma mark - Background Task
 
-static UIBackgroundTaskIdentifier backgroundTaskIdentifier = -1;
-
 - (void)applicationDidEnterBackground:(NSNotification *)notification
 {
-    [self cleanBackgroundTask];
     [self lock];
-    if (self.delegateDictionary.count > 0)
-    {
-        backgroundTaskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
-            [self cleanBackgroundTask];
-        }];
-        UIBackgroundTaskIdentifier blockIdentifier = backgroundTaskIdentifier;
-        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(300 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
-            if (blockIdentifier == backgroundTaskIdentifier)
-            {
-                [self cleanBackgroundTask];
-            }
-        });
+    if (self.delegateDictionary.count > 0) {
+        [self beginBackgroundTask];
     }
     [self unlock];
 }
 
 - (void)applicationWillEnterForeground:(NSNotification *)notification
 {
-    [self cleanBackgroundTask];
+    [self endBackgroundTask];
 }
 
-- (void)cleanBackgroundTask
+- (void)beginBackgroundTask
 {
-    static dispatch_once_t onceToken;
-    dispatch_once(&onceToken, ^{
-        backgroundTaskIdentifier = UIBackgroundTaskInvalid;
-    });
-    if (backgroundTaskIdentifier != UIBackgroundTaskInvalid)
-    {
-        [[UIApplication sharedApplication] endBackgroundTask:backgroundTaskIdentifier];
-        backgroundTaskIdentifier = UIBackgroundTaskInvalid;
+    self.backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
+        [self endBackgroundTask];
+    }];
+}
+
+- (void)endBackgroundTask
+{
+    if (self.backgroundTask != UIBackgroundTaskInvalid) {
+        [[UIApplication sharedApplication] endBackgroundTask:self.backgroundTask];
+        self.backgroundTask = UIBackgroundTaskInvalid;
     }
 }
 
-- (void)cleanBackgroundTaskAsync
+- (void)endBackgroundTaskDelay
 {
     dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
         [self lock];
-        if (self.delegateDictionary.count <= 0)
-        {
-            [self cleanBackgroundTask];
+        if (self.delegateDictionary.count <= 0) {
+            [self endBackgroundTask];
         }
         [self unlock];
     });

+ 0 - 2
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCHTTPServer/KTVHCHTTPConnection.h

@@ -11,6 +11,4 @@
 
 @interface KTVHCHTTPConnection : HTTPConnection
 
-+ (NSString *)pingResponseValue;
-
 @end

+ 8 - 30
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCHTTPServer/KTVHCHTTPConnection.m

@@ -7,23 +7,16 @@
 //
 
 #import "KTVHCHTTPConnection.h"
-#import "KTVHCHTTPRequest.h"
 #import "KTVHCHTTPResponse.h"
-#import "KTVHCHTTPPingResponse.h"
-#import "KTVHCHTTPURL.h"
+#import "KTVHCDataStorage.h"
+#import "KTVHCURLTool.h"
 #import "KTVHCLog.h"
 
 @implementation KTVHCHTTPConnection
 
-+ (NSString *)pingResponseValue
-{
-    return KTVHCHTTPPingResponseResponseValue;
-}
-
 - (id)initWithAsyncSocket:(GCDAsyncSocket *)newSocket configuration:(HTTPConfig *)aConfig
 {
-    if (self = [super initWithAsyncSocket:newSocket configuration:aConfig])
-    {
+    if (self = [super initWithAsyncSocket:newSocket configuration:aConfig]) {
         KTVHCLogAlloc(self);
     }
     return self;
@@ -37,26 +30,11 @@
 - (NSObject<HTTPResponse> *)httpResponseForMethod:(NSString *)method URI:(NSString *)path
 {
     KTVHCLogHTTPConnection(@"%p, Receive request\nmethod : %@\npath : %@\nURL : %@", self, method, path, request.url);
-    KTVHCHTTPURL * URL = [[KTVHCHTTPURL alloc] initWithProxyURL:request.url];
-    switch (URL.type)
-    {
-        case KTVHCHTTPURLTypeUnknown:
-            return nil;
-        case KTVHCHTTPURLTypePing:
-        {
-            KTVHCHTTPPingResponse * currentResponse = [KTVHCHTTPPingResponse responseWithConnection:self];
-            return currentResponse;
-        }
-        case KTVHCHTTPURLTypeContent:
-        {
-            KTVHCHTTPRequest * currentRequest = [[KTVHCHTTPRequest alloc] initWithURL:URL.URL headers:request.allHeaderFields];
-            currentRequest.method = request.method;
-            currentRequest.version = request.version;
-            KTVHCHTTPResponse * currentResponse = [[KTVHCHTTPResponse alloc] initWithConnection:self request:currentRequest];
-            return currentResponse;
-        }
-    }
-    return nil;
+    NSDictionary<NSString *,NSString *> *parameters = [[KTVHCURLTool tool] parseQuery:request.url.query];
+    NSURL *URL = [NSURL URLWithString:[parameters objectForKey:@"url"]];
+    KTVHCDataRequest *dataRequest = [[KTVHCDataRequest alloc] initWithURL:URL headers:request.allHeaderFields];
+    KTVHCHTTPResponse *response = [[KTVHCHTTPResponse alloc] initWithConnection:self dataRequest:dataRequest];
+    return response;
 }
 
 

+ 2 - 2
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCHTTPServer/KTVHCHTTPResponse.h

@@ -10,13 +10,13 @@
 #import "KTVHCHTTPHeader.h"
 
 @class KTVHCHTTPConnection;
-@class KTVHCHTTPRequest;
+@class KTVHCDataRequest;
 
 @interface KTVHCHTTPResponse : NSObject <HTTPResponse>
 
 + (instancetype)new NS_UNAVAILABLE;
 - (instancetype)init NS_UNAVAILABLE;
 
-- (instancetype)initWithConnection:(KTVHCHTTPConnection *)connection request:(KTVHCHTTPRequest *)request;
+- (instancetype)initWithConnection:(KTVHCHTTPConnection *)connection dataRequest:(KTVHCDataRequest *)dataRequest NS_DESIGNATED_INITIALIZER;
 
 @end

+ 28 - 31
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCHTTPServer/KTVHCHTTPResponse.m

@@ -8,34 +8,28 @@
 
 #import "KTVHCHTTPResponse.h"
 #import "KTVHCHTTPConnection.h"
-#import "KTVHCHTTPRequest.h"
 #import "KTVHCDataStorage.h"
 #import "KTVHCLog.h"
 
 @interface KTVHCHTTPResponse () <KTVHCDataReaderDelegate>
 
-@property (nonatomic, weak) KTVHCHTTPConnection * connection;
-@property (nonatomic, strong) KTVHCHTTPRequest * request;
-@property (nonatomic, strong) KTVHCDataRequest * dataRequest;
-@property (nonatomic, strong) KTVHCDataReader * reader;
-@property (nonatomic, assign) BOOL waitingResponseHeader;
+@property (nonatomic) BOOL waitingResponse;
+@property (nonatomic, strong) KTVHCDataReader *reader;
+@property (nonatomic, weak) KTVHCHTTPConnection *connection;
 
 @end
 
 @implementation KTVHCHTTPResponse
 
-- (instancetype)initWithConnection:(KTVHCHTTPConnection *)connection request:(KTVHCHTTPRequest *)request
+- (instancetype)initWithConnection:(KTVHCHTTPConnection *)connection dataRequest:(KTVHCDataRequest *)dataRequest
 {
-    if (self = [super init])
-    {
+    if (self = [super init]) {
         KTVHCLogAlloc(self);
         self.connection = connection;
-        self.request = request;
-        KTVHCDataRequest * dataRequest = [[KTVHCDataRequest alloc] initWithURL:self.request.URL headers:self.request.headers];
         self.reader = [[KTVHCDataStorage storage] readerWithRequest:dataRequest];
         self.reader.delegate = self;
         [self.reader prepare];
-        KTVHCLogHTTPResponse(@"%p, Create response\nrequest : %@", self, self.request);
+        KTVHCLogHTTPResponse(@"%p, Create response\nrequest : %@", self, dataRequest);
     }
     return self;
 }
@@ -50,10 +44,9 @@
 
 - (NSData *)readDataOfLength:(NSUInteger)length
 {
-    NSData * data = [self.reader readDataOfLength:length];
+    NSData *data = [self.reader readDataOfLength:length];
     KTVHCLogHTTPResponse(@"%p, Read data : %lld", self, (long long)data.length);
-    if (self.reader.didFinished)
-    {
+    if (self.reader.isFinished) {
         KTVHCLogHTTPResponse(@"%p, Read data did finished", self);
         [self.reader close];
         [self.connection responseDidAbort:self];
@@ -63,9 +56,9 @@
 
 - (BOOL)delayResponseHeaders
 {
-    BOOL waiting = !self.reader.didPrepared;
-    self.waitingResponseHeader = waiting;
-    KTVHCLogHTTPResponse(@"%p, Delay response : %d", self, self.waitingResponseHeader);
+    BOOL waiting = !self.reader.isPrepared;
+    self.waitingResponse = waiting;
+    KTVHCLogHTTPResponse(@"%p, Delay response : %d", self, self.waitingResponse);
     return waiting;
 }
 
@@ -77,52 +70,56 @@
 
 - (NSDictionary *)httpHeaders
 {
-    KTVHCLogHTTPResponse(@"%p, Header\n%@", self, self.reader.response.headersWithoutRangeAndLength);
-    return self.reader.response.headersWithoutRangeAndLength;
+    NSMutableDictionary *headers = [self.reader.response.headers mutableCopy];
+    [headers removeObjectForKey:@"Content-Range"];
+    [headers removeObjectForKey:@"content-range"];
+    [headers removeObjectForKey:@"Content-Length"];
+    [headers removeObjectForKey:@"content-length"];
+    KTVHCLogHTTPResponse(@"%p, Header\n%@", self, headers);
+    return headers;
 }
 
 - (UInt64)offset
 {
-    KTVHCLogHTTPResponse(@"%p, Offset : %lld", self, self.reader.readOffset);
-    return self.reader.readOffset;
+    KTVHCLogHTTPResponse(@"%p, Offset : %lld", self, self.reader.readedLength);
+    return self.reader.readedLength;
 }
 
 - (void)setOffset:(UInt64)offset
 {
-    KTVHCLogHTTPResponse(@"%p, Set offset : %lld, %lld", self, offset, self.reader.readOffset);
+    KTVHCLogHTTPResponse(@"%p, Set offset : %lld, %lld", self, offset, self.reader.readedLength);
 }
 
 - (BOOL)isDone
 {
-    KTVHCLogHTTPResponse(@"%p, Check done : %d", self, self.reader.didFinished);
-    return self.reader.didFinished;
+    KTVHCLogHTTPResponse(@"%p, Check done : %d", self, self.reader.isFinished);
+    return self.reader.isFinished;
 }
 
 - (void)connectionDidClose
 {
-    KTVHCLogHTTPResponse(@"%p, Connection did closed : %lld, %lld", self, self.reader.response.currentLength, self.reader.readOffset);
+    KTVHCLogHTTPResponse(@"%p, Connection did closed : %lld, %lld", self, self.reader.response.contentLength, self.reader.readedLength);
     [self.reader close];
 }
 
 #pragma mark - KTVHCDataReaderDelegate
 
-- (void)readerDidPrepared:(KTVHCDataReader *)reader
+- (void)ktv_readerDidPrepare:(KTVHCDataReader *)reader
 {
     KTVHCLogHTTPResponse(@"%p, Prepared", self);
-    if (self.reader.didPrepared && self.waitingResponseHeader == YES)
-    {
+    if (self.reader.isPrepared && self.waitingResponse == YES) {
         KTVHCLogHTTPResponse(@"%p, Call connection did prepared", self);
         [self.connection responseHasAvailableData:self];
     }
 }
 
-- (void)readerHasAvailableData:(KTVHCDataReader *)reader
+- (void)ktv_readerHasAvailableData:(KTVHCDataReader *)reader
 {
     KTVHCLogHTTPResponse(@"%p, Has available data", self);
     [self.connection responseHasAvailableData:self];
 }
 
-- (void)reader:(KTVHCDataReader *)reader didFailed:(NSError *)error
+- (void)ktv_reader:(KTVHCDataReader *)reader didFailWithError:(NSError *)error
 {
     KTVHCLogHTTPResponse(@"%p, Failed\nError : %@", self, error);
     [self.reader close];

+ 2 - 2
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCHTTPServer/KTVHCHTTPServer.h

@@ -15,9 +15,9 @@
 
 + (instancetype)server;
 
-@property (nonatomic, assign, readonly) BOOL running;
+@property (nonatomic, readonly, getter=isRunning) BOOL running;
 
-- (void)start:(NSError **)error;
+- (BOOL)start:(NSError **)error;
 - (void)stop;
 
 - (NSURL *)URLWithOriginalURL:(NSURL *)URL;

+ 108 - 100
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/Classes/KTVHCHTTPServer/KTVHCHTTPServer.m

@@ -7,20 +7,16 @@
 //
 
 #import "KTVHCHTTPServer.h"
-#import "KTVHCHTTPHeader.h"
 #import "KTVHCHTTPConnection.h"
-#import "KTVHCHTTPURL.h"
+#import "KTVHCHTTPHeader.h"
+#import "KTVHCURLTool.h"
 #import "KTVHCLog.h"
 
 @interface KTVHCHTTPServer ()
 
-@property (nonatomic, strong) HTTPServer * coreHTTPServer;
-
-@property (nonatomic, assign) BOOL pinging;
-@property (nonatomic, assign) BOOL pingResult;
-@property (nonatomic, strong) NSCondition * pingCondition;
-@property (nonatomic, strong) NSURLSession * pingSession;
-@property (nonatomic, strong) NSURLSessionDataTask * pingTask;
+@property (nonatomic, strong) HTTPServer *server;
+@property (nonatomic) UIBackgroundTaskIdentifier backgroundTask;
+@property (nonatomic) BOOL wantsRunning;
 
 @end
 
@@ -28,7 +24,7 @@
 
 + (instancetype)server
 {
-    static KTVHCHTTPServer * obj = nil;
+    static KTVHCHTTPServer *obj = nil;
     static dispatch_once_t onceToken;
     dispatch_once(&onceToken, ^{
         obj = [[self alloc] init];
@@ -38,9 +34,21 @@
 
 - (instancetype)init
 {
-    if (self = [super init])
-    {
+    if (self = [super init]) {
         KTVHCLogAlloc(self);
+        self.backgroundTask = UIBackgroundTaskInvalid;
+        [[NSNotificationCenter defaultCenter] addObserver:self
+                                                 selector:@selector(applicationDidEnterBackground)
+                                                     name:UIApplicationDidEnterBackgroundNotification
+                                                   object:nil];
+        [[NSNotificationCenter defaultCenter] addObserver:self
+                                                 selector:@selector(applicationWillEnterForeground)
+                                                     name:UIApplicationWillEnterForegroundNotification
+                                                   object:nil];
+        [[NSNotificationCenter defaultCenter] addObserver:self
+                                                 selector:@selector(HTTPConnectionDidDie)
+                                                     name:HTTPConnectionDidDieNotification
+                                                   object:nil];
     }
     return self;
 }
@@ -48,119 +56,119 @@
 - (void)dealloc
 {
     KTVHCLogDealloc(self);
-    [self stop];
+    [self stopInternal];
 }
 
-- (BOOL)restart
+- (BOOL)isRunning
 {
-    KTVHCLogHTTPServer(@"%p, Restart connection count : %lld", self, (long long)[self.coreHTTPServer numberOfHTTPConnections]);
-    [self.coreHTTPServer stop];
-    NSError * error = nil;
-    [self.coreHTTPServer start:&error];
-    if (error) {
-        KTVHCLogHTTPServer(@"%p, Restart server failed : %@", self, error);
-    } else {
-        KTVHCLogHTTPServer(@"%p, Restart server success", self);
-    }
-    return error == nil;
+    return self.server.isRunning;
 }
 
-- (void)start:(NSError * __autoreleasing *)error
+- (BOOL)start:(NSError **)error
 {
-    self.coreHTTPServer = [[HTTPServer alloc] init];
-    [self.coreHTTPServer setConnectionClass:[KTVHCHTTPConnection class]];
-    [self.coreHTTPServer setType:@"_http._tcp."];
-    NSError * tempError = nil;
-    [self.coreHTTPServer start:&tempError];
-    if (tempError) {
-        * error = tempError;
-        KTVHCLogHTTPServer(@"%p, Start server failed : %@", self, tempError);
-    } else {
-        KTVHCLogHTTPServer(@"%p, Start server success", self);
-    }
+    self.wantsRunning = YES;
+    return [self startInternal:error];
 }
 
 - (void)stop
 {
-    if (self.running)
-    {
-        [self.coreHTTPServer stop];
-        [self.pingSession invalidateAndCancel];
-        [self.pingTask cancel];
-        self.pingTask = nil;
-        self.pingSession = nil;
-        KTVHCLogHTTPServer(@"%p, Stop server", self);
-    }
+    self.wantsRunning = NO;
+    [self stopInternal];
 }
 
 - (NSURL *)URLWithOriginalURL:(NSURL *)URL
 {
-    BOOL success = NO;
-    for (int i = 0; i < 2 && !success && self.running && [URL.scheme hasPrefix:@"http"]; i++)
-    {
-        if (i > 0)
-        {
-            [self restart];
-        }
-        success = [self ping];
-        KTVHCLogHTTPServer(@"%p, Ping\nsuccess : %d\nindex : %d", self, success, i);
+    if (!URL || URL.isFileURL || URL.absoluteString.length == 0) {
+        return URL;
     }
-    if (success)
-    {
-        KTVHCHTTPURL * HCURL = [[KTVHCHTTPURL alloc] initWithOriginalURL:URL];
-        URL = [HCURL proxyURLWithPort:self.coreHTTPServer.listeningPort];
+    if (!self.isRunning) {
+        return URL;
     }
+    NSString *original = [[KTVHCURLTool tool] URLEncode:URL.absoluteString];
+    NSString *server = [NSString stringWithFormat:@"http://localhost:%d/", self.server.listeningPort];
+    NSString *extension = URL.pathExtension ? [NSString stringWithFormat:@".%@", URL.pathExtension] : @"";
+    NSString *URLString = [NSString stringWithFormat:@"%@request%@?url=%@", server, extension, original];
+    URL = [NSURL URLWithString:URLString];
     KTVHCLogHTTPServer(@"%p, Return URL\nURL : %@", self, URL);
     return URL;
 }
 
-- (BOOL)ping
+#pragma mark - Internal
+
+- (BOOL)startInternal:(NSError **)error
 {
-    if (self.running)
-    {
-        if (!self.pingCondition)
-        {
-            self.pingCondition = [[NSCondition alloc] init];
-        }
-        [self.pingCondition lock];
-        if (self.pinging)
-        {
-            [self.pingCondition wait];
-        }
-        else
-        {
-            NSURL * pingURL = [[KTVHCHTTPURL pingURL] proxyURLWithPort:self.coreHTTPServer.listeningPort];
-            if (!self.pingSession)
-            {
-                NSURLSessionConfiguration * sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
-                sessionConfiguration.timeoutIntervalForRequest = 3;
-                self.pingSession = [NSURLSession sessionWithConfiguration:sessionConfiguration];
-            }
-            self.pingTask = [self.pingSession dataTaskWithURL:pingURL completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
-                [self.pingCondition lock];
-                if (!error && data.length > 0) {
-                    NSString * pang = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
-                    self.pingResult = [pang isEqualToString:[KTVHCHTTPConnection pingResponseValue]];
-                } else {
-                    self.pingResult = NO;
-                }
-                self.pinging = NO;
-                [self.pingCondition broadcast];
-                [self.pingCondition unlock];
-            }];
-            self.pinging = YES;
-            [self.pingTask resume];
-            [self.pingCondition wait];
-        }
-        [self.pingCondition unlock];
+    self.server = [[HTTPServer alloc] init];
+    [self.server setConnectionClass:[KTVHCHTTPConnection class]];
+    [self.server setType:@"_http._tcp."];
+    [self.server setPort:80];
+    BOOL ret = [self.server start:error];
+    if (ret) {
+        KTVHCLogHTTPServer(@"%p, Start server success", self);
+    } else {
+        KTVHCLogHTTPServer(@"%p, Start server failed", self);
+    }
+    return ret;
+}
+
+- (void)stopInternal
+{
+    [self.server stop];
+    self.server = nil;
+}
+
+#pragma mark - Background Task
+
+- (void)applicationDidEnterBackground
+{
+    if (self.server.numberOfHTTPConnections > 0) {
+        KTVHCLogHTTPServer(@"%p, enter background", self);
+        [self beginBackgroundTask];
+    } else {
+        KTVHCLogHTTPServer(@"%p, enter background and stop server", self);
+        [self stopInternal];
+    }
+}
+
+- (void)applicationWillEnterForeground
+{
+    KTVHCLogHTTPServer(@"%p, enter foreground", self);
+    if (self.backgroundTask == UIBackgroundTaskInvalid && self.wantsRunning) {
+        KTVHCLogHTTPServer(@"%p, restart server", self);
+        [self startInternal:nil];
     }
-    KTVHCLogHTTPServer(@"%p, Ping result : %d", self, self.pingResult);
-    return self.pingResult;
+    [self endBackgroundTask];
 }
 
-- (BOOL)running
+- (void)HTTPConnectionDidDie
 {
-    return self.coreHTTPServer.isRunning;
+    KTVHCLogHTTPServer(@"%p, connection did die", self);
+    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+        if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground &&
+            self.server.numberOfHTTPConnections == 0) {
+            KTVHCLogHTTPServer(@"%p, server idle", self);
+            [self endBackgroundTask];
+            [self stopInternal];
+        }
+    });
+}
+
+- (void)beginBackgroundTask
+{
+    KTVHCLogHTTPServer(@"%p, begin background task", self);
+    self.backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
+        KTVHCLogHTTPServer(@"%p, background task expiration", self);
+        [self endBackgroundTask];
+        [self stopInternal];
+    }];
+}
+
+- (void)endBackgroundTask
+{
+    if (self.backgroundTask != UIBackgroundTaskInvalid) {
+        KTVHCLogHTTPServer(@"%p, end background task", self);
+        [[UIApplication sharedApplication] endBackgroundTask:self.backgroundTask];
+        self.backgroundTask = UIBackgroundTaskInvalid;
+    }
 }
 
 @end

+ 335 - 8
Carthage/Checkouts/KTVHTTPCache/KTVHTTPCache/KTVHTTPCache.h

@@ -2,18 +2,28 @@
 //  KTVHTTPCache.h
 //  KTVHTTPCache
 //
-//  Created by Single on 2017/8/10.
+//  Created by Single on 2017/8/13.
 //  Copyright © 2017年 Single. All rights reserved.
 //
 
-#import <UIKit/UIKit.h>
+#import <Foundation/Foundation.h>
 
-#pragma mark - Interface
+#if __has_include(<KTVHTTPCache/KTVHTTPCache.h>)
 
-#import "KTVHTTPCacheImp.h"
+FOUNDATION_EXPORT double KTVHTTPCacheVersionNumber;
+FOUNDATION_EXPORT const unsigned char KTVHTTPCacheVersionString[];
 
-#pragma mark - Data Storage
+#import <KTVHTTPCache/KTVHCRange.h>
+#import <KTVHTTPCache/KTVHCDataReader.h>
+#import <KTVHTTPCache/KTVHCDataLoader.h>
+#import <KTVHTTPCache/KTVHCDataRequest.h>
+#import <KTVHTTPCache/KTVHCDataResponse.h>
+#import <KTVHTTPCache/KTVHCDataCacheItem.h>
+#import <KTVHTTPCache/KTVHCDataCacheItemZone.h>
+
+#else
 
+#import "KTVHCRange.h"
 #import "KTVHCDataReader.h"
 #import "KTVHCDataLoader.h"
 #import "KTVHCDataRequest.h"
@@ -21,7 +31,324 @@
 #import "KTVHCDataCacheItem.h"
 #import "KTVHCDataCacheItemZone.h"
 
-#pragma mark - Common
+#endif
 
-#import "KTVHCRange.h"
-#import "KTVHCCommon.h"
+/**
+ *  KTVHTTPCache is a smart media cache framework.
+ */
+@interface KTVHTTPCache : NSObject
+
+/**
+ *  HTTP Server
+ *
+ *  This part is used to access the local HTTP server module.
+ *  The prefix for API is 'proxy'.
+ */
+#pragma mark - HTTP Server
+
+/**
+ *  Start the proxy service.
+ *
+ *  @param error : Pointer to receive service error.
+ *  @return YES when the proxy service is successfully started, otherwise NO.
+ */
++ (BOOL)proxyStart:(NSError **)error;
+
+/**
+ *  Stop the proxy service.
+ */
++ (void)proxyStop;
+
+/**
+ *  Proxy service running status.
+ *
+ *  @return YES when the proxy service is running, otherwise NO.
+ */
++ (BOOL)proxyIsRunning;
+
+/**
+ *  Convert the URL to the proxy URL.
+ *
+ *  @param URL : The URL for HTTP content.
+ *  @return If the param is a file URL or the proxy service isn't running, return URL. Otherwise reutrn the proxy URL.
+ */
++ (NSURL *)proxyURLWithOriginalURL:(NSURL *)URL;
+
+/**
+ *  Data Storage
+ *
+ *  This part is used to access the data storage module.
+ *  The prefix for API is 'cache'.
+ */
+#pragma mark - Data Storage
+
+/**
+ *  Convert the URL to the file URL if the cache is complete.
+ *
+ *  @param URL : The URL for HTTP content.
+ *  @return If the contents of the URL have all been cached, return the complete file URL. Otherwise return nil.
+ */
++ (NSURL *)cacheCompleteFileURLWithURL:(NSURL *)URL;
+
+/**
+ *  Create the data reader for the request.
+ *
+ *  @param request : The request of the expected data.
+ *  @return The data reader for request.
+ */
++ (KTVHCDataReader *)cacheReaderWithRequest:(KTVHCDataRequest *)request;
+
+/**
+ *  Create the data loader for the request.
+ *
+ *  @param request : The request of the expected data.
+ *  @return The data loader for request.
+ */
++ (KTVHCDataLoader *)cacheLoaderWithRequest:(KTVHCDataRequest *)request;
+
+/**
+ *  Set the maximum cache length.
+ *  If the current cache length exceeds the maximum length, it will be deleted starting with the oldest cached data.
+ *
+ *  @param maxCacheLength : The maximum cache length.
+ */
++ (void)cacheSetMaxCacheLength:(long long)maxCacheLength;
+
+/**
+ *  Get the maximum cache length.
+ *
+ *  @return Maximum cache length.
+ */
++ (long long)cacheMaxCacheLength;
+
+/**
+ *  Get the current cached length.
+ *
+ *  @return Current cached length
+ */
++ (long long)cacheTotalCacheLength;
+
+/**
+ *  Create the cache item for the URL.
+ *
+ *  @param URL : The URL for HTTP content.
+ *  @return The cache item for URL.
+ */
++ (KTVHCDataCacheItem *)cacheCacheItemWithURL:(NSURL *)URL;
+
+/**
+ *  Get all cache items.
+ *
+ *  @return All cache items.
+ */
++ (NSArray<KTVHCDataCacheItem *> *)cacheAllCacheItems;
+
+/**
+ *  Delete cache for URL.
+ *
+ *  @param URL : The URL for HTTP content.
+ */
++ (void)cacheDeleteCacheWithURL:(NSURL *)URL;
+
+/**
+ *  Delete all caches.
+ */
++ (void)cacheDeleteAllCaches;
+
+/**
+ *  Encode
+ *
+ *  This part is used to access the encode module.
+ *  The prefix for API is 'encode'.
+ */
+#pragma mark - Encode
+
+/**
+ *  Set URL converter.
+ *  If the URL contains authentication parameters. It can be removed here to ensure that the indeterminate URL can use the same cache.
+ *
+ *  @warning High frequency call. Make it simple.
+ *
+ *  @param URLConverter : The URLConverter.
+ */
++ (void)encodeSetURLConverter:(NSURL * (^)(NSURL *URL))URLConverter;
+
+/**
+ *  Download
+ *
+ *  This part is used to access the download module.
+ *  The prefix for API is 'download'.
+ */
+#pragma mark - Download
+
+/**
+ *  Set the HTTP timeout interval.
+ *
+ *  @param timeoutInterval : The HTTP timeout interval.
+ */
++ (void)downloadSetTimeoutInterval:(NSTimeInterval)timeoutInterval;
+
+/**
+ *  Set HTTP timeout interval.
+ *
+ *  @return The current HTTP timeout interval.
+ */
++ (NSTimeInterval)downloadTimeoutInterval;
+
+/**
+ *  Set the whitelist header keys.
+ *  The following keys are only supported by default:
+ *      User-Agent, Connection, Accept, Accept-Encoding, Accept-Language, Range
+ *  If you want to allow other keys, set them here.
+ *
+ *  @param whitelistHeaderKeys : The keys can be allowed.
+ */
++ (void)downloadSetWhitelistHeaderKeys:(NSArray<NSString *> *)whitelistHeaderKeys;
+
+/**
+ *  Get the current whitelist header keys.
+ */
++ (NSArray<NSString *> *)downloadWhitelistHeaderKeys;
+
+/**
+ *  Set the additional headers.
+ *  If you want to add extra headers, set them here.
+ *
+ *  @param additionalHeaders : The headers will be added.
+ */
++ (void)downloadSetAdditionalHeaders:(NSDictionary<NSString *, NSString *> *)additionalHeaders;
+
+/**
+ *  Get the current additional headers.
+ */
++ (NSDictionary<NSString *, NSString *> *)downloadAdditionalHeaders;
+
+/**
+ *  Set the acceptable content types.
+ *  The following values are only supported by default:
+ *      video/x, audio/x, application/mp4, application/octet-stream, binary/octet-stream
+ *  If you want to allow other content types, set them here.
+ *
+ *  @param acceptableContentTypes : The content types can be allowed.
+ */
++ (void)downloadSetAcceptableContentTypes:(NSArray<NSString *> *)acceptableContentTypes;
+
+/**
+ *  Get the current acceptable content types.
+ */
++ (NSArray<NSString *> *)downloadAcceptableContentTypes;
+
+/**
+ *  Set the unacceptable content type disposer.
+ *  If the receive response's Content-Type not included in acceptContentTypes, this method will be called.
+ *  If the return value of block is YES, you can continue to load resources. Otherwise the HTTP task will be rejected.
+ *
+ *  @param unacceptableContentTypeDisposer : The unacceptable content type disposer.
+ */
++ (void)downloadSetUnacceptableContentTypeDisposer:(BOOL(^)(NSURL *URL, NSString *contentType))unacceptableContentTypeDisposer;
+
+/**
+ *  Log
+ *
+ *  This part is used to access the Log module.
+ *  The prefix for API is 'log'.
+ */
+#pragma mark - Log
+
+/**
+ *  Add an external log.
+ *
+ *  @param log : An external log.
+ */
++ (void)logAddLog:(NSString *)log;
+
+/**
+ *  Set whether to enable the console log.
+ *  Default is NO.
+ *
+ *  @param consoleLogEnable : The value to enable the console log.
+ */
++ (void)logSetConsoleLogEnable:(BOOL)consoleLogEnable;
+
+/**
+ *  Get the value that enables the console log.
+ *
+ *  @return The value that enables the console log.
+ */
++ (BOOL)logConsoleLogEnable;
+
+/**
+ *  Set whether to enable the record log.
+ *  Default is NO.
+ *
+ *  @param recordLogEnable : The value to enable the record log.
+ */
++ (void)logSetRecordLogEnable:(BOOL)recordLogEnable;
+
+/**
+ *  Get the value that enables the record log.
+ *
+ *  @return The value that enables the record log.
+ */
++ (BOOL)logRecordLogEnable;
+
+/**
+ *  Get the path to the log file.
+ *
+ *  @return The path to the log file.
+ */
++ (NSURL *)logRecordLogFileURL;
+
+/**
+ *  Delete the log file.
+ */
++ (void)logDeleteRecordLogFile;
+
+/**
+ *  Get all errors
+ *
+ *  @return All errors.
+ */
++ (NSDictionary<NSURL *, NSError *> *)logErrors;
+
+/**
+ *  Get the error for the URL.
+ *
+ *  @param URL : The URL for HTTP content.
+ *  @return The error for the URL.
+ */
++ (NSError *)logErrorForURL:(NSURL *)URL;
+
+/**
+ *  Delete the error for the URL.
+ *
+ *  @param URL : The URL for HTTP content.
+ */
++ (void)logCleanErrorForURL:(NSURL *)URL;
+
+@end
+
+/**
+ *  Deprecated
+ *
+ *  This part is for compatibility with historical versions.
+ *
+ *  @warning This part will be removed in future versions.
+ */
+#pragma mark - Deprecated
+
+@interface KTVHTTPCache (Deprecated)
+
++ (void)logDeleteRecordLog                                                      __attribute__((deprecated("Use +logDeleteRecordLogFile instead.")));
++ (NSString *)logRecordLogFilePath                                              __attribute__((deprecated("Use +logRecordLogFileURL instead.")));
++ (NSString *)proxyURLStringWithOriginalURLString:(NSString *)URLString         __attribute__((deprecated("Use +proxyURLWithOriginalURL: instead.")));
++ (NSURL *)cacheCompleteFileURLIfExistedWithURL:(NSURL *)URL                    __attribute__((deprecated("Use +cacheCompleteFileURLWithURL: instead.")));
++ (NSString *)cacheCompleteFilePathIfExistedWithURLString:(NSString *)URLString __attribute__((deprecated("Use +cacheCompleteFileURLWithURL: instead.")));
++ (KTVHCDataCacheItem *)cacheCacheItemWithURLString:(NSString *)URLString       __attribute__((deprecated("Use +cacheCacheItemWithURL: instead.")));
++ (void)cacheDeleteCacheWithURLString:(NSString *)URLString                     __attribute__((deprecated("Use +cacheDeleteCacheWithURL: instead.")));
++ (void)tokenSetURLFilter:(NSURL * (^)(NSURL * URL))URLFilter                   __attribute__((deprecated("Use +encodeSetURLConverter: instead.")));
++ (void)downloadSetAcceptContentTypes:(NSArray<NSString *> *)acceptContentTypes __attribute__((deprecated("Use +downloadSetAcceptableContentTypes: instead.")));
++ (NSArray<NSString *> *)downloadAcceptContentTypes                             __attribute__((deprecated("Use +downloadAcceptableContentTypes instead.")));
++ (void)downloadSetUnsupportContentTypeFilter:(BOOL(^)(NSURL *URL, NSString *contentType))contentTypeFilter __attribute__((deprecated("Use +downloadSetUnacceptableContentTypeDisposer: instead.")));
+
+@end

+ 1 - 1
Carthage/Checkouts/KTVHTTPCache/LICENSE

@@ -1,6 +1,6 @@
 MIT License
 
-Copyright (c) 2017 唱吧
+Copyright (c) 2017 Single
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal

+ 2 - 2
Carthage/Checkouts/PDFGenerator/PDFGenerator.podspec

@@ -1,6 +1,6 @@
 Pod::Spec.new do |s|
   s.name             = "PDFGenerator"
-  s.version          = "2.1.1"
+  s.version          = "2.1"
   s.summary          = "A simple PDF generator."
   s.homepage         = "https://github.com/sgr-ksmt/PDFGenerator"
   # s.screenshots     = ""
@@ -9,6 +9,6 @@ Pod::Spec.new do |s|
   s.source           = { :git => "https://github.com/sgr-ksmt/PDFGenerator.git", :tag => s.version.to_s }
   s.platform         = :ios, '8.0'
   s.requires_arc     = true
-  s.source_files     = "PDFGenerator/**/*.swift"
+  s.source_files     = "PDFGenerator/**/*"
   s.frameworks   = 'WebKit'
 end

+ 1 - 1
Carthage/Checkouts/SVGKit/Source/DOM classes/Core DOM/DOMGlobalSettings.h

@@ -1 +1 @@
-#define DEBUG_DOM_PARSING 0
+#define DEBUG_DOM_PARSING 0

+ 1 - 1
Carthage/Checkouts/SVGKit/Source/DOM classes/SVG-DOM/SVGNumber.h

@@ -9,4 +9,4 @@
 typedef struct
 {
 	float value;
-} SVGNumber;
+} SVGNumber;

+ 1 - 1
Carthage/Checkouts/SVGKit/Source/DOM classes/Unported or Partial DOM/SVGElement.h

@@ -61,4 +61,4 @@
 -(NSString*) cascadedValueForStylableProperty:(NSString*) stylableProperty;
 -(NSString*) cascadedValueForStylableProperty:(NSString*) stylableProperty inherit:(BOOL)inherit;
 
-@end
+@end

+ 1 - 1
Carthage/Checkouts/SVGKit/Source/Foundation additions/NSData+NSInputStream.h

@@ -17,4 +17,4 @@
  */
 +(NSData*)dataWithContentsOfStream:(NSInputStream*)input initialCapacity:(NSUInteger)capacity error:(NSError **)error;
 
-@end
+@end

+ 1 - 1
Carthage/Checkouts/SVGKit/Source/Foundation additions/NSData+NSInputStream.m

@@ -57,4 +57,4 @@
 }
 
 
-@end
+@end

+ 6 - 1
Carthage/Checkouts/SVGKit/Source/UIKit additions/SVGKFastImageView.m

@@ -39,7 +39,12 @@
 	self = [super initWithFrame:frame];
 	if( self )
 	{
-        [self populateFromImage:nil];
+#if SVGKIT_UIKIT
+		self.backgroundColor = [UIColor clearColor];
+#else
+        self.layer.backgroundColor = [NSColor clearColor].CGColor;
+#endif
+        
 	}
 	return self;
 }

+ 5 - 1
Carthage/Checkouts/SVGKit/Source/UIKit additions/SVGKLayeredImageView.m

@@ -46,7 +46,11 @@
 	self = [super initWithFrame:frame];
 	if( self )
 	{
-        [self populateFromImage:nil];
+#if SVGKIT_UIKIT
+		self.backgroundColor = [UIColor clearColor];
+#else
+        self.layer.backgroundColor = [NSColor clearColor].CGColor;
+#endif
 	}
 	return self;
 }

+ 1 - 1
Carthage/Checkouts/TLPhotoPicker/.swift-version

@@ -1 +1 @@
-4.2
+5.0

+ 3 - 3
Carthage/Checkouts/TLPhotoPicker/TLPhotoPicker.podspec

@@ -8,7 +8,7 @@
 
 Pod::Spec.new do |s|
   s.name             = 'TLPhotoPicker'
-  s.version          = '1.8.3'
+  s.version          = '1.8.5'
   s.summary          = 'multiple phassets picker for iOS lib. like facebook'
 
 # This description is used to generate tags and improve search results.
@@ -29,8 +29,8 @@ TODO: Add long description of the pod here.
   # s.social_media_url = 'https://twitter.com/<TWITTER_USERNAME>'
 
   s.ios.deployment_target = '9.1'
-  s.swift_version = '4.2'
-  s.pod_target_xcconfig = { 'SWIFT_VERSION' => '4.2' }
+  s.swift_version = '5.0'
+  s.pod_target_xcconfig = { 'SWIFT_VERSION' => '5.0' }
 
   s.source_files = 'TLPhotoPicker/Classes/**/*'
   

+ 5 - 2
Carthage/Checkouts/TLPhotoPicker/TLPhotoPicker/Classes/TLAssetsCollection.swift

@@ -26,6 +26,8 @@ public struct TLPHAsset {
     
     var state = CloudDownloadState.ready
     public var phAsset: PHAsset? = nil
+    //Bool to check if TLPHAsset returned is created using camera.
+    public var isSelectedFromCamera = false
     public var selectedOrder: Int = 0
     public var type: AssetType {
         get {
@@ -137,7 +139,7 @@ public struct TLPHAsset {
     }
     
     @discardableResult
-    //convertLivePhotosToPNG
+    //convertLivePhotosToJPG
     // false : If you want mov file at live photos
     // true  : If you want png file at live photos ( HEIC )
     public func tempCopyMediaFile(videoRequestOptions: PHVideoRequestOptions? = nil, imageRequestOptions: PHImageRequestOptions? = nil, exportPreset: String = AVAssetExportPresetHighestQuality, convertLivePhotosToJPG: Bool = false, progressBlock:((Double) -> Void)? = nil, completionBlock:@escaping ((URL,String) -> Void)) -> PHImageRequestID? {
@@ -202,7 +204,8 @@ public struct TLPHAsset {
             return PHImageManager.default().requestImageData(for: phAsset, options: requestOptions, resultHandler: { (data, uti, orientation, info) in
                 do {
                     var data = data
-                    if convertLivePhotosToJPG == true, let imgData = data, let rawImage = UIImage(data: imgData)?.upOrientationImage() {
+                    let needConvertLivePhotoToJPG = phAsset.mediaSubtypes.contains(.photoLive) == true && convertLivePhotosToJPG == true
+                    if needConvertLivePhotoToJPG, let imgData = data, let rawImage = UIImage(data: imgData)?.upOrientationImage() {
                         data = rawImage.jpegData(compressionQuality: 1)
                     }
                     try data?.write(to: localURL)

+ 10 - 10
Carthage/Checkouts/TLPhotoPicker/TLPhotoPicker/Classes/TLPhotoLibrary.swift

@@ -34,13 +34,13 @@ class TLPhotoLibrary {
         options.progressHandler = progressBlock
         let scale = min(UIScreen.main.scale,2)
         let targetSize = CGSize(width: size.width*scale, height: size.height*scale)
-        let requestId = self.imageManager.requestLivePhoto(for: asset, targetSize: targetSize, contentMode: .aspectFill, options: options) { (livePhoto, info) in
+        let requestID = self.imageManager.requestLivePhoto(for: asset, targetSize: targetSize, contentMode: .aspectFill, options: options) { (livePhoto, info) in
             let complete = (info?["PHImageResultIsDegradedKey"] as? Bool) == false
             if let livePhoto = livePhoto {
                 completionBlock(livePhoto,complete)
             }
         }
-        return requestId
+        return requestID
     }
     
     @discardableResult
@@ -49,10 +49,10 @@ class TLPhotoLibrary {
         options.isNetworkAccessAllowed = true
         options.deliveryMode = .automatic
         options.progressHandler = progressBlock
-        let requestId = self.imageManager.requestPlayerItem(forVideo: asset, options: options, resultHandler: { playerItem, info in
+        let requestID = self.imageManager.requestPlayerItem(forVideo: asset, options: options, resultHandler: { playerItem, info in
             completionBlock(playerItem,info)
         })
-        return requestId
+        return requestID
     }
     
     @discardableResult
@@ -67,17 +67,17 @@ class TLPhotoLibrary {
         }
         let scale = min(UIScreen.main.scale,2)
         let targetSize = CGSize(width: size.width*scale, height: size.height*scale)
-        let requestId = self.imageManager.requestImage(for: asset, targetSize: targetSize, contentMode: .aspectFill, options: options) { image, info in
+        let requestID = self.imageManager.requestImage(for: asset, targetSize: targetSize, contentMode: .aspectFill, options: options) { image, info in
             let complete = (info?["PHImageResultIsDegradedKey"] as? Bool) == false
             if let image = image {
                 completionBlock(image,complete)
             }
         }
-        return requestId
+        return requestID
     }
     
-    func cancelPHImageRequest(requestId: PHImageRequestID) {
-        self.imageManager.cancelImageRequest(requestId)
+    func cancelPHImageRequest(requestID: PHImageRequestID) {
+        self.imageManager.cancelImageRequest(requestID)
     }
     
     @discardableResult
@@ -91,14 +91,14 @@ class TLPhotoLibrary {
         options.progressHandler = { (progress,error,stop,info) in
             progressBlock(progress)
         }
-        let requestId = PHCachingImageManager().requestImageData(for: asset, options: options) { (imageData, dataUTI, orientation, info) in
+        let requestID = PHCachingImageManager().requestImageData(for: asset, options: options) { (imageData, dataUTI, orientation, info) in
             if let data = imageData,let _ = info {
                 completionBlock(UIImage(data: data))
             }else{
                 completionBlock(nil)//error
             }
         }
-        return requestId
+        return requestID
     }
     
     @discardableResult

+ 44 - 38
Carthage/Checkouts/TLPhotoPicker/TLPhotoPicker/Classes/TLPhotosPickerViewController.swift

@@ -157,8 +157,8 @@ open class TLPhotosPickerViewController: UIViewController {
     
     private var collections = [TLAssetsCollection]()
     private var focusedCollection: TLAssetsCollection? = nil
-    private var requestIds = [IndexPath:PHImageRequestID]()
-    private var playRequestId: (indexPath: IndexPath, requestId: PHImageRequestID)? = nil
+    private var requestIDs = SynchronizedDictionary<IndexPath,PHImageRequestID>()
+    private var playRequestID: (indexPath: IndexPath, requestID: PHImageRequestID)? = nil
     private var photoLibrary = TLPhotoLibrary()
     private var queue = DispatchQueue(label: "tilltue.photos.pikcker.queue")
     private var queueForGroupedBy = DispatchQueue(label: "tilltue.photos.pikcker.queue.for.groupedBy", qos: .utility)
@@ -216,6 +216,8 @@ open class TLPhotosPickerViewController: UIViewController {
         case .restricted: fallthrough
         case .denied:
             handleDeniedAlbumsAuthorization()
+        @unknown default:
+            break
         }
     }
     
@@ -276,7 +278,7 @@ extension TLPhotosPickerViewController {
     }
     
     private func initItemSize() {
-        guard var layout = self.collectionView.collectionViewLayout as? UICollectionViewFlowLayout else {
+        guard let layout = self.collectionView.collectionViewLayout as? UICollectionViewFlowLayout else {
             return
         }
         let count = CGFloat(self.configure.numberOfColumn)
@@ -372,7 +374,7 @@ extension TLPhotosPickerViewController {
     }
     
     private func getfocusedIndex() -> Int {
-        guard let focused = self.focusedCollection, let result = self.collections.index(where: { $0 == focused }) else { return 0 }
+        guard let focused = self.focusedCollection, let result = self.collections.firstIndex(where: { $0 == focused }) else { return 0 }
         return result
     }
     
@@ -401,10 +403,10 @@ extension TLPhotosPickerViewController {
     }
     
     private func cancelAllImageAssets() {
-        for (_,requestId) in self.requestIds {
-            self.photoLibrary.cancelPHImageRequest(requestId: requestId)
+        self.requestIDs.forEach{ (indexPath, requestID) in
+            self.photoLibrary.cancelPHImageRequest(requestID: requestID)
         }
-        self.requestIds.removeAll()
+        self.requestIDs.removeAll()
     }
     
     // User Action
@@ -506,6 +508,8 @@ extension TLPhotosPickerViewController: UIImagePickerControllerDelegate, UINavig
             })
         case .restricted, .denied:
             self.handleDeniedCameraAuthorization()
+        @unknown default:
+            break
         }
     }
 
@@ -551,6 +555,7 @@ extension TLPhotosPickerViewController: UIImagePickerControllerDelegate, UINavig
                     guard let asset = PHAsset.fetchAssets(withLocalIdentifiers: [identifier], options: nil).firstObject else { return }
                     var result = TLPHAsset(asset: asset)
                     result.selectedOrder = self.selectedAssets.count + 1
+                    result.isSelectedFromCamera = true
                     self.selectedAssets.append(result)
                     self.logDelegate?.selectedPhoto(picker: self, at: 1)
                 }
@@ -566,6 +571,7 @@ extension TLPhotosPickerViewController: UIImagePickerControllerDelegate, UINavig
                     guard let asset = PHAsset.fetchAssets(withLocalIdentifiers: [identifier], options: nil).firstObject else { return }
                     var result = TLPHAsset(asset: asset)
                     result.selectedOrder = self.selectedAssets.count + 1
+                    result.isSelectedFromCamera = true
                     self.selectedAssets.append(result)
                     self.logDelegate?.selectedPhoto(picker: self, at: 1)
                 }
@@ -590,12 +596,12 @@ extension TLPhotosPickerViewController {
     
     private func videoCheck() {
         func play(asset: (IndexPath,TLPHAsset)) {
-            if self.playRequestId?.indexPath != asset.0 {
+            if self.playRequestID?.indexPath != asset.0 {
                 playVideo(asset: asset.1, indexPath: asset.0)
             }
         }
         guard self.configure.autoPlay else { return }
-        guard self.playRequestId == nil else { return }
+        guard self.playRequestID == nil else { return }
         let visibleIndexPaths = self.collectionView.indexPathsForVisibleItems.sorted(by: { $0.row < $1.row })
         #if swift(>=4.1)
         let boundAssets = visibleIndexPaths.compactMap{ indexPath -> (IndexPath,TLPHAsset)? in
@@ -619,8 +625,8 @@ extension TLPhotosPickerViewController {
 // MARK: - Video & LivePhotos Control PHLivePhotoViewDelegate
 extension TLPhotosPickerViewController: PHLivePhotoViewDelegate {
     private func stopPlay() {
-        guard let playRequest = self.playRequestId else { return }
-        self.playRequestId = nil
+        guard let playRequest = self.playRequestID else { return }
+        self.playRequestID = nil
         guard let cell = self.collectionView.cellForItem(at: playRequest.indexPath) as? TLPhotoCollectionViewCell else { return }
         cell.stopPlay()
     }
@@ -630,7 +636,7 @@ extension TLPhotosPickerViewController: PHLivePhotoViewDelegate {
         guard let phAsset = asset.phAsset else { return }
         if asset.type == .video {
             guard let cell = self.collectionView.cellForItem(at: indexPath) as? TLPhotoCollectionViewCell else { return }
-            let requestId = self.photoLibrary.videoAsset(asset: phAsset, completionBlock: { (playerItem, info) in
+            let requestID = self.photoLibrary.videoAsset(asset: phAsset, completionBlock: { (playerItem, info) in
                 DispatchQueue.main.sync { [weak self, weak cell] in
                     guard let `self` = self, let cell = cell, cell.player == nil else { return }
                     let player = AVPlayer(playerItem: playerItem)
@@ -639,19 +645,19 @@ extension TLPhotosPickerViewController: PHLivePhotoViewDelegate {
                     player.isMuted = self.configure.muteAudio
                 }
             })
-            if requestId > 0 {
-                self.playRequestId = (indexPath,requestId)
+            if requestID > 0 {
+                self.playRequestID = (indexPath,requestID)
             }
         }else if asset.type == .livePhoto && self.allowedLivePhotos {
             guard let cell = self.collectionView.cellForItem(at: indexPath) as? TLPhotoCollectionViewCell else { return }
-            let requestId = self.photoLibrary.livePhotoAsset(asset: phAsset, size: self.thumbnailSize, completionBlock: { [weak cell] (livePhoto,complete) in
+            let requestID = self.photoLibrary.livePhotoAsset(asset: phAsset, size: self.thumbnailSize, completionBlock: { [weak cell] (livePhoto,complete) in
                 cell?.livePhotoView?.isHidden = false
                 cell?.livePhotoView?.livePhoto = livePhoto
                 cell?.livePhotoView?.isMuted = true
                 cell?.livePhotoView?.startPlayback(with: .hint)
             })
-            if requestId > 0 {
-                self.playRequestId = (indexPath,requestId)
+            if requestID > 0 {
+                self.playRequestID = (indexPath,requestID)
             }
         }
     }
@@ -742,7 +748,7 @@ extension TLPhotosPickerViewController: PHPhotoLibraryChangeObserver {
 // MARK: - UICollectionView delegate & datasource
 extension TLPhotosPickerViewController: UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDataSourcePrefetching {
     private func getSelectedAssets(_ asset: TLPHAsset) -> TLPHAsset? {
-        if let index = self.selectedAssets.index(where: { $0.phAsset == asset.phAsset }) {
+        if let index = self.selectedAssets.firstIndex(where: { $0.phAsset == asset.phAsset }) {
             return self.selectedAssets[index]
         }
         return nil
@@ -782,7 +788,7 @@ extension TLPhotosPickerViewController: UICollectionViewDelegate,UICollectionVie
         }
         guard var asset = collection.getTLAsset(at: indexPath), let phAsset = asset.phAsset else { return }
         cell.popScaleAnim()
-        if let index = self.selectedAssets.index(where: { $0.phAsset == asset.phAsset }) {
+        if let index = self.selectedAssets.firstIndex(where: { $0.phAsset == asset.phAsset }) {
         //deselect
             self.logDelegate?.deselectedPhoto(picker: self, at: indexPath.row)
             self.selectedAssets.remove(at: index)
@@ -802,7 +808,7 @@ extension TLPhotosPickerViewController: UICollectionViewDelegate,UICollectionVie
             cell.selectedAsset = false
             cell.stopPlay()
             self.orderUpdateCells()
-            if self.playRequestId?.indexPath == indexPath {
+            if self.playRequestID?.indexPath == indexPath {
                 stopPlay()
             }
         }else {
@@ -824,13 +830,13 @@ extension TLPhotosPickerViewController: UICollectionViewDelegate,UICollectionVie
         if let cell = cell as? TLPhotoCollectionViewCell {
             cell.endDisplayingCell()
             cell.stopPlay()
-            if indexPath == self.playRequestId?.indexPath {
-                self.playRequestId = nil
+            if indexPath == self.playRequestID?.indexPath {
+                self.playRequestID = nil
             }
         }
-        guard let requestId = self.requestIds[indexPath] else { return }
-        self.requestIds.removeValue(forKey: indexPath)
-        self.photoLibrary.cancelPHImageRequest(requestId: requestId)
+        guard let requestID = self.requestIDs[indexPath] else { return }
+        self.requestIDs.removeValue(forKey: indexPath)
+        self.photoLibrary.cancelPHImageRequest(requestID: requestID)
     }
     
     //Datasource
@@ -873,10 +879,10 @@ extension TLPhotosPickerViewController: UICollectionViewDelegate,UICollectionVie
                 options.deliveryMode = .opportunistic
                 options.resizeMode = .exact
                 options.isNetworkAccessAllowed = true
-                let requestId = self.photoLibrary.imageAsset(asset: phAsset, size: self.thumbnailSize, options: options) { [weak self, weak cell] (image,complete) in
+                let requestID = self.photoLibrary.imageAsset(asset: phAsset, size: self.thumbnailSize, options: options) { [weak self, weak cell] (image,complete) in
                     guard let `self` = self else { return }
                     DispatchQueue.main.async {
-                        if self.requestIds[indexPath] != nil {
+                        if self.requestIDs[indexPath] != nil {
                             cell?.imageView?.image = image
                             cell?.update(with: phAsset)
                             if self.allowedVideo {
@@ -884,20 +890,20 @@ extension TLPhotosPickerViewController: UICollectionViewDelegate,UICollectionVie
                                 cell?.duration = asset.type == .video ? phAsset.duration : nil
                             }
                             if complete {
-                                self.requestIds.removeValue(forKey: indexPath)
+                                self.requestIDs.removeValue(forKey: indexPath)
                             }
                         }
                     }
                 }
-                if requestId > 0 {
-                    self.requestIds[indexPath] = requestId
+                if requestID > 0 {
+                    self.requestIDs[indexPath] = requestID
                 }
             }else {
                 queue.async { [weak self, weak cell] in
                     guard let `self` = self else { return }
-                    let requestId = self.photoLibrary.imageAsset(asset: phAsset, size: self.thumbnailSize, completionBlock: { (image,complete) in
+                    let requestID = self.photoLibrary.imageAsset(asset: phAsset, size: self.thumbnailSize, completionBlock: { (image,complete) in
                         DispatchQueue.main.async {
-                            if self.requestIds[indexPath] != nil {
+                            if self.requestIDs[indexPath] != nil {
                                 cell?.imageView?.image = image
                                 cell?.update(with: phAsset)
                                 if self.allowedVideo {
@@ -905,13 +911,13 @@ extension TLPhotosPickerViewController: UICollectionViewDelegate,UICollectionVie
                                     cell?.duration = asset.type == .video ? phAsset.duration : nil
                                 }
                                 if complete {
-                                    self.requestIds.removeValue(forKey: indexPath)
+                                    self.requestIDs.removeValue(forKey: indexPath)
                                 }
                             }
                         }
                     })
-                    if requestId > 0 {
-                        self.requestIds[indexPath] = requestId
+                    if requestID > 0 {
+                        self.requestIDs[indexPath] = requestID
                     }
                 }
             }
@@ -959,9 +965,9 @@ extension TLPhotosPickerViewController: UICollectionViewDelegate,UICollectionVie
     open func collectionView(_ collectionView: UICollectionView, cancelPrefetchingForItemsAt indexPaths: [IndexPath]) {
         if self.usedPrefetch {
             for indexPath in indexPaths {
-                guard let requestId = self.requestIds[indexPath] else { continue }
-                self.photoLibrary.cancelPHImageRequest(requestId: requestId)
-                self.requestIds.removeValue(forKey: indexPath)
+                guard let requestID = self.requestIDs[indexPath] else { continue }
+                self.photoLibrary.cancelPHImageRequest(requestID: requestID)
+                self.requestIDs.removeValue(forKey: indexPath)
             }
             queue.async { [weak self] in
                 guard let `self` = self, let collection = self.focusedCollection else { return }

+ 87 - 39
Carthage/Checkouts/realm-cocoa/.jenkins.yml

@@ -7,6 +7,7 @@ xcode_version:
   - 9.4
   - 10.0
   - 10.1
+  - 10.2
 target:
   - osx
   - docs
@@ -15,17 +16,21 @@ target:
   - ios-swift
   - osx-swift
   - watchos
-  - cocoapods
+  - cocoapods-ios
+  - cocoapods-osx
+  - cocoapods-watchos
   - swiftlint
   - tvos
   - osx-encryption
   - osx-object-server
 
-  - ios-device-objc-ios8
+  # These are disabled because the machinen with the devices attached is currently offline
+  # - ios-device-objc-ios8
+  # - ios-device-objc-ios10
+  # - tvos-device
+  # These are disabled because they were very unreliable on CI
   # - ios-device-swift-ios8
-  - ios-device-objc-ios10
   # - ios-device-swift-ios10
-  - tvos-device
 configuration:
   - Debug
   - Release
@@ -33,30 +38,33 @@ configuration:
 # Combinations have to be excluded in a way that's hard to read.
 # This table shows which jobs will run:
 
-# +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
-# | Configuration Matrix | osx | docs | ios-static | ios-dynamic | ios-swift | osx-swift | watchos | cocoapods | swiftlint | tvos | osx-encryption | osx-object-server | ios-device-objc-ios8 | ios-device-swift-ios8 | ios-device-objc-ios10 | ios-device-swift-ios10 | tvos-device |
-# | -------------------- | --- | ---- | ---------- | ----------- | --------- | --------- | ------- | --------- | --------- | ---- | -------------- | ----------------- | -------------------- | --------------------- | --------------------- | ---------------------- | ----------- |
-# | 9.2   | Debug        | X   |      | X          |             |           |           |         |           |           |      |                |                   |                      |                       |                       |                        |             |
-# | 9.2   | Release      | X   |      | X          | X           | X         | X         | X       | X         |           | X    | X              | X                 | X                    |                       | X                     |                        |             |
-# | -------------------- | --- | ---- | ---------- | ----------- | --------- | --------- | ------- | --------- | --------- | ---- | -------------- | ----------------- | -------------------- | --------------------- | --------------------- | ---------------------- | ----------- |
-# | 9.3   | Debug        | X   |      |            |             |           |           |         |           |           |      |                |                   |                      |                       |                       |                        |             |
-# | 9.3   | Release      | X   |      | X          | X           | X         | X         | X       | X         |           | X    |                |                   |                      |                       |                       |                        |             |
-# | -------------------- | --- | ---- | ---------- | ----------- | --------- | --------- | ------- | --------- | --------- | ---- | -------------- | ----------------- | -------------------- | --------------------- | --------------------- | ---------------------- | ----------- |
-# | 9.4   | Debug        | X   |      |            |             |           |           |         |           |           |      |                |                   |                      |                       |                       |                        |             |
-# | 9.4   | Release      | X   |      | X          | X           | X         | X         | X       | X         |           | X    |                |                   |                      |                       |                       |                        |             |
-# | -------------------- | --- | ---- | ---------- | ----------- | --------- | --------- | ------- | --------- | --------- | ---- | -------------- | ----------------- | -------------------- | --------------------- | --------------------- | ---------------------- | ----------- |
-# | 10.0  | Debug        | X   |      |            |             |           |           |         |           |           |      |                |                   |                      |                       |                       |                        |             |
-# | 10.0  | Release      | X   |      | X          | X           | X         | X         | X       | X         |           | X    |                |                   |                      |                       |                       |                        |             |
-# | -------------------- | --- | ---- | ---------- | ----------- | --------- | --------- | ------- | --------- | --------- | ---- | -------------- | ----------------- | -------------------- | --------------------- | --------------------- | ---------------------- | ----------- |
-# | 10.1  | Debug        | X   |      |            | X           | X         | X         | X       |           |           | X    |                |                   |                      |                       |                       |                        |             |
-# | 10.1  | Release      | X   | X    | X          | X           | X         | X         | X       | X         | X         | X    | X              | X                 |                      |                       | X                     |                        | X           |
-# +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+# +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+# | Configuration Matrix | osx | docs | ios-static | ios-dynamic | ios-swift | osx-swift | watchos | cocoapods-ios | cocoapods-osx | cocoapods-watchos | swiftlint | tvos | osx-encryption | osx-object-server | ios-device-objc-ios8 | ios-device-swift-ios8 | ios-device-objc-ios10 | ios-device-swift-ios10 | tvos-device |
+# | -------------------- | --- | ---- | ---------- | ----------- | --------- | --------- | ------- | ------------- | ------------- | ----------------- | --------- | ---- | -------------- | ----------------- | -------------------- | --------------------- | --------------------- | ---------------------- | ----------- |
+# | 9.2   | Debug        | X   |      | X          |             |           |           |         |               |               |                   |           |      |                |                   |                      |                       |                       |                        |             |
+# | 9.2   | Release      | X   |      | X          | X           | X         | X         | X       | X             | X             | X                 |           | X    | X              | X                 | X                    |                       | X                     |                        |             |
+# | -------------------- | --- | ---- | ---------- | ----------- | --------- | --------- | ------- | ------------- | ------------- | ----------------- | --------- | ---- | -------------- | ----------------- | -------------------- | --------------------- | --------------------- | ---------------------- | ----------- |
+# | 9.3   | Debug        | X   |      |            |             |           |           |         |               |               |                   |           |      |                |                   |                      |                       |                       |                        |             |
+# | 9.3   | Release      | X   |      | X          | X           | X         | X         | X       | X             | X             | X                 |           | X    |                |                   |                      |                       |                       |                        |             |
+# | -------------------- | --- | ---- | ---------- | ----------- | --------- | --------- | ------- | ------------- | ------------- | ----------------- | --------- | ---- | -------------- | ----------------- | -------------------- | --------------------- | --------------------- | ---------------------- | ----------- |
+# | 9.4   | Debug        | X   |      |            |             |           |           |         |               |               |                   |           |      |                |                   |                      |                       |                       |                        |             |
+# | 9.4   | Release      | X   |      | X          | X           | X         | X         | X       | X             | X             | X                 |           | X    |                |                   |                      |                       |                       |                        |             |
+# | -------------------- | --- | ---- | ---------- | ----------- | --------- | --------- | ------- | ------------- | ------------- | ----------------- | --------- | ---- | -------------- | ----------------- | -------------------- | --------------------- | --------------------- | ---------------------- | ----------- |
+# | 10.0  | Debug        | X   |      |            |             |           |           |         |               |               |                   |           |      |                |                   |                      |                       |                       |                        |             |
+# | 10.0  | Release      | X   |      | X          | X           | X         | X         | X       | X             | X             | X                 |           | X    |                |                   |                      |                       |                       |                        |             |
+# | -------------------- | --- | ---- | ---------- | ----------- | --------- | --------- | ------- | ------------- | ------------- | ----------------- | --------- | ---- | -------------- | ----------------- | -------------------- | --------------------- | --------------------- | ---------------------- | ----------- |
+# | 10.1  | Debug        | X   |      |            |             |           |           |         |               |               |                   |           |      |                |                   |                      |                       |                       |                        |             |
+# | 10.1  | Release      | X   |      | X          | X           | X         | X         | X       | X             | X             | X                 |           | X    |                |                   |                      |                       |                       |                        |             |
+# | -------------------- | --- | ---- | ---------- | ----------- | --------- | --------- | ------- | ------------- | ------------- | ----------------- | --------- | ---- | -------------- | ----------------- | -------------------- | --------------------- | --------------------- | ---------------------- | ----------- |
+# | 10.2  | Debug        | X   |      |            | X           | X         | X         | X       |               |               |                   |           | X    |                |                   |                      |                       |                       |                        |             |
+# | 10.2  | Release      | X   | X    | X          | X           | X         | X         | X       | X             | X             | X                 | X         | X    | X              | X                 |                      |                       | X                     |                        | X           |
+# +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 
 exclude:
   ################
   # docs
   ################
-  # Just run on 10.0 Release
+  # Just run on 10.2 Release
   - xcode_version: 9.2
     target: docs
   - xcode_version: 9.3
@@ -65,13 +73,15 @@ exclude:
     target: docs
   - xcode_version: 10.0
     target: docs
+  - xcode_version: 10.1
+    target: docs
   - target: docs
     configuration: Debug
 
   ################
   # ios-static
   ################
-  # Skip on 9.3/9.4/10.0 Debug
+  # Skip Debug on everything but 9.2
   - xcode_version: 9.3
     target: ios-static
     configuration: Debug
@@ -84,11 +94,14 @@ exclude:
   - xcode_version: 10.1
     target: ios-static
     configuration: Debug
+  - xcode_version: 10.2
+    target: ios-static
+    configuration: Debug
 
   ################
   # ios-dynamic
   ################
-  # Skip on 9.2/9.3/0.2 Debug
+  # Skip Debug on everything but 10.2
   - xcode_version: 9.2
     target: ios-dynamic
     configuration: Debug
@@ -101,11 +114,14 @@ exclude:
   - xcode_version: 10.0
     target: ios-dynamic
     configuration: Debug
+  - xcode_version: 10.1
+    target: ios-dynamic
+    configuration: Debug
 
   ################
   # ios-swift
   ################
-  # Skip 9.2/9.3/9.4/10.0 Debug
+  # Skip Debug on everything but 10.2
   - xcode_version: 9.2
     target: ios-swift
     configuration: Debug
@@ -118,11 +134,14 @@ exclude:
   - xcode_version: 10.0
     target: ios-swift
     configuration: Debug
+  - xcode_version: 10.1
+    target: ios-swift
+    configuration: Debug
 
   ################
   # osx-swift
   ################
-  # Skip 9.2/9.3/9.4/10.0 Debug
+  # Skip Debug on everything but 10.2
   - xcode_version: 9.2
     target: osx-swift
     configuration: Debug
@@ -135,11 +154,14 @@ exclude:
   - xcode_version: 10.0
     target: osx-swift
     configuration: Debug
+  - xcode_version: 10.1
+    target: osx-swift
+    configuration: Debug
 
   ################
   # watchos
   ################
-  # Skip 9.2/9.3/9.4/10.0 Debug
+  # Skip Debug on everything but 10.2
   - xcode_version: 9.2
     target: watchos
     configuration: Debug
@@ -152,18 +174,25 @@ exclude:
   - xcode_version: 10.0
     target: watchos
     configuration: Debug
+  - xcode_version: 10.1
+    target: watchos
+    configuration: Debug
 
   ################
   # cocoapods
   ################
   # Skip Debug
-  - target: cocoapods
+  - target: cocoapods-ios
+    configuration: Debug
+  - target: cocoapods-osx
+    configuration: Debug
+  - target: cocoapods-watchos
     configuration: Debug
 
   ################
   # swiftlint
   ################
-  # Just run on 10.1 Release
+  # Just run on 10.2 Release
   - xcode_version: 9.2
     target: swiftlint
   - xcode_version: 9.3
@@ -172,13 +201,15 @@ exclude:
     target: swiftlint
   - xcode_version: 10.0
     target: swiftlint
+  - xcode_version: 10.1
+    target: swiftlint
   - target: swiftlint
     configuration: Debug
 
   ################
   # tvos
   ################
-  # Skip 9.2/9.3/9.4/10.0 Debug
+  # Skip Debug on everything but 10.2
   - xcode_version: 9.2
     target: tvos
     configuration: Debug
@@ -191,29 +222,36 @@ exclude:
   - xcode_version: 10.0
     target: tvos
     configuration: Debug
+  - xcode_version: 10.1
+    target: tvos
+    configuration: Debug
 
   ################
   # osx-encryption
   ################
-  # Just run on 9.2/10.1 Release
+  # Just run on 9.2/10.2 Release
   - xcode_version: 9.3
     target: osx-encryption
   - xcode_version: 9.4
     target: osx-encryption
   - xcode_version: 10.0
     target: osx-encryption
+  - xcode_version: 10.1
+    target: osx-encryption
   - target: osx-encryption
     configuration: Debug
 
   ################
   # osx-object-server
   ################
-  # Just run on 9.2/10.1 Release
+  # Just run on 9.2/10.2 Release
   - xcode_version: 9.3
     target: osx-object-server
   - xcode_version: 9.4
     target: osx-object-server
-  - xcode_version: 10.01
+  - xcode_version: 10.0
+    target: osx-object-server
+  - xcode_version: 10.1
     target: osx-object-server
   - target: osx-object-server
     configuration: Debug
@@ -221,22 +259,26 @@ exclude:
   ################
   # ios-device-objc-ios8
   ################
-  # Just run on 9.2/10.1 Release
+  # Just run on 9.2/10.2 Release
   - xcode_version: 9.3
     target: ios-device-objc-ios8
   - xcode_version: 10.0
     target: ios-device-objc-ios8
+  - xcode_version: 10.1
+    target: ios-device-objc-ios8
   - target: ios-device-objc-ios8
     configuration: Debug
 
   ################
   # ios-device-swift-ios8
   ################
-  # Just run on 9.2/10.1 Release
+  # Just run on 9.2/10.2 Release
   - xcode_version: 9.3
     target: ios-device-swift-ios8
   - xcode_version: 9.4
     target: ios-device-swift-ios8
+  - xcode_version: 10.0
+    target: ios-device-swift-ios8
   - xcode_version: 10.1
     target: ios-device-swift-ios8
   - target: ios-device-swift-ios8
@@ -245,24 +287,28 @@ exclude:
   ################
   # ios-device-objc-ios10
   ################
-  # Just run on 9.2/10.1 Release
+  # Just run on 9.2/10.2 Release
   - xcode_version: 9.3
     target: ios-device-objc-ios10
   - xcode_version: 9.4
     target: ios-device-objc-ios10
   - xcode_version: 10.0
     target: ios-device-objc-ios10
+  - xcode_version: 10.1
+    target: ios-device-objc-ios10
   - target: ios-device-objc-ios10
     configuration: Debug
 
   ################
   # ios-device-swift-ios10
   ################
-  # Just run on 9.2/10.1 Release
+  # Just run on 9.2/10.2 Release
   - xcode_version: 9.3
     target: ios-device-swift-ios10
   - xcode_version: 9.4
     target: ios-device-swift-ios10
+  - xcode_version: 10.0
+    target: ios-device-swift-ios10
   - xcode_version: 10.1
     target: ios-device-swift-ios10
   - target: ios-device-swift-ios10
@@ -271,7 +317,7 @@ exclude:
   ################
   # tvos-device
   ################
-  # Just run on 10.1 Release
+  # Just run on 10.2 Release
   - xcode_version: 9.2
     target: tvos-device
   - xcode_version: 9.3
@@ -280,5 +326,7 @@ exclude:
     target: tvos-device
   - xcode_version: 10.0
     target: tvos-device
+  - xcode_version: 10.1
+    target: tvos-device
   - target: tvos-device
     configuration: Debug

+ 4 - 0
Carthage/Checkouts/realm-cocoa/.swiftlint.yml

@@ -19,6 +19,10 @@ identifier_name:
     - to
 disabled_rules:
   - block_based_kvo
+  # SwiftLint considers 'Realm' and 'Realm.Private' to be duplicate imports
+  # because we're using submodules in an unsual way, and normally the parent
+  # module re-exports all of its children.
+  - duplicate_imports
   - file_length
   - force_cast
   - force_try

+ 49 - 0
Carthage/Checkouts/realm-cocoa/CHANGELOG.md

@@ -1,3 +1,52 @@
+3.14.1 Release notes (2019-04-04)
+=============================================================
+
+### Fixed
+
+* Fix "Cannot find interface declaration for 'RealmSwiftObject', superclass of
+  'MyRealmObjectClass'" errors when building for a simulator with Xcode 10.2
+  with "Install Objective-C Compatibility Header" enabled.
+
+### Compatibility
+
+* File format: Generates Realms with format v9 (Reads and upgrades all previous formats)
+* Realm Object Server: 3.11.0 or later.
+
+3.14.0 Release notes (2019-03-27)
+=============================================================
+
+### Enhancements
+
+* Reduce memory usage when committing write transactions.
+* Improve performance of compacting encrypted Realm files.
+  ([PR #3221](https://github.com/realm/realm-core/pull/3221)).
+* Add a Xcode 10.2 build to the release package.
+
+### Fixed
+
+* Fix a memory leak whenever Realm makes a HTTP(s) request to the Realm Object
+  Server (Issue [#6058](https://github.com/realm/realm-cocoa/issues/6058), since 3.8.0).
+* Fix an assertion failure when creating an object in a synchronized Realm
+  after creating an object with a null int primary key in the same write
+  transaction.
+  ([PR #3227](https://github.com/realm/realm-core/pull/3227)).
+* Fix some new warnings when building with Xcode 10.2 beta.
+* Properly clean up sync sessions when the last Realm object using the session
+  is deallocated while the session is explicitly suspended (since 3.9.0).
+
+### Compatibility
+
+* File format: Generates Realms with format v9 (Reads and upgrades all previous formats)
+* Realm Object Server: 3.11.0 or later.
+* Carthage release for Swift is built with Xcode 10.2.
+
+### Internal
+
+* Throw an exception rather than crashing with an assertion failure in more
+  cases when opening invalid Realm files.
+* Upgrade to REALM_CORE_VERSION=5.14.0
+* Upgrade to REALM_SYNC_VERSION=3.15.1
+
 3.13.1 Release notes (2019-01-03)
 =============================================================
 

+ 1 - 1
Carthage/Checkouts/realm-cocoa/Configuration/Base.xcconfig

@@ -58,4 +58,4 @@ IPHONEOS_DEPLOYMENT_TARGET = 8.0;
 WATCHOS_DEPLOYMENT_TARGET = 2.0;
 TVOS_DEPLOYMENT_TARGET = 9.0;
 
-SWIFT_VERSION = 3.0;
+SWIFT_VERSION = 4.0;

+ 12 - 14
Carthage/Checkouts/realm-cocoa/Jenkinsfile.releasability

@@ -1,8 +1,8 @@
-swiftVersions = ['3.2.3', '3.3', '3.3.2', '3.4', '3.4.1', '4.0.3', '4.1', '4.1.2', '4.2', '4.2.1']
+xcodeVersions = ['9.2', '9.3', '9.4', '10.0', '10.1', '10.2']
 platforms = ['osx', 'ios', 'watchos', 'tvos']
 platformNames = ['osx': 'macOS', 'ios': 'iOS', 'watchos': 'watchOS', 'tvos': 'tvOS']
-carthageXcodeVersion = '10.1'
-carthageSwiftVersion = '3.4.1'
+carthageXcodeVersion = '10.2'
+docsSwiftVersion = '5.0'
 
 def installationTest(platform, test, language) {
   return {
@@ -24,8 +24,6 @@ def installationTest(platform, test, language) {
         find . -name 'realm-${language}-*' -print0 | xargs -J% mv % realm-${language}-latest
       fi
 
-      sed -i '' 's/swift-3.[0-9.]*/swift-${carthageSwiftVersion}/g' osx/swift/DynamicExample/DynamicExample.xcodeproj/project.pbxproj
-      sed -i '' 's/swift-3.[0-9.]*/swift-${carthageSwiftVersion}/g' ios/swift/DynamicExample/DynamicExample.xcodeproj/project.pbxproj
       export REALM_XCODE_VERSION=${carthageXcodeVersion}
       ./build.sh test-${platform}-${language}-${test}
       """
@@ -74,7 +72,7 @@ def doBuild() {
           deleteDir()
           unstash 'source'
           sh """
-          export REALM_SWIFT_VERSION=${swiftVersions.last()}
+          export REALM_SWIFT_VERSION=${docsSwiftVersion}
           ./scripts/reset-simulators.sh
           ./build.sh docs
           cd docs
@@ -127,16 +125,16 @@ def doBuild() {
     for (def p in platforms) {
       def platform = p
       def platformName = platformNames[platform]
-      for (def v in swiftVersions) {
-        def swiftVersion = v
-        parallelBuilds["${platformName} Swift ${swiftVersion}"] = {
+      for (def v in xcodeVersions) {
+        def xcodeVersion = v
+        parallelBuilds["${platformName} Swift ${xcodeVersion}"] = {
           node('osx') {
             deleteDir()
             unstash 'source'
-            sh "XCMODE=xcpretty ./build.sh package-${platform}-swift-${swiftVersion}"
+            sh "XCMODE=xcpretty ./build.sh package-${platform}-swift-${xcodeVersion}"
             dir("build/${platform}") {
-              stash includes: "realm-swift-framework-${platform}-swift-${swiftVersion}.zip",
-                    name: "${platform}-swift-${swiftVersion}"
+              stash includes: "realm-swift-framework-${platform}-swift-${xcodeVersion}.zip",
+                    name: "${platform}-swift-${xcodeVersion}"
             }
           }
         }
@@ -170,8 +168,8 @@ def doBuild() {
           deleteDir()
 
           for (def platform in platforms) {
-            for (def swiftVersion in swiftVersions) {
-              unstash "${platform}-swift-${swiftVersion}"
+            for (def xcodeVersion in xcodeVersions) {
+              unstash "${platform}-swift-${xcodeVersion}"
             }
           }
 

+ 1 - 46
Carthage/Checkouts/realm-cocoa/Realm/ObjectServerTests/RLMObjectServerTests.mm

@@ -1518,15 +1518,9 @@
 
             return 0;
         };
-        NSUInteger sizeBefore = fileSize(c.pathOnDisk);
-        @autoreleasepool {
-            // We have partial transaction logs but no data
-            XCTAssertGreaterThan(sizeBefore, 0U);
-            XCTAssertTrue([[RLMRealm realmWithConfiguration:c error:nil] isEmpty]);
-        }
         XCTAssertNil(RLMGetAnyCachedRealmForPath(c.pathOnDisk.UTF8String));
         [self waitForExpectationsWithTimeout:10.0 handler:nil];
-        XCTAssertGreaterThan(fileSize(c.pathOnDisk), sizeBefore);
+        XCTAssertGreaterThan(fileSize(c.pathOnDisk), 0U);
         XCTAssertNil(RLMGetAnyCachedRealmForPath(c.pathOnDisk.UTF8String));
     } else {
         RLMRealm *realm = [self openRealmForURL:url user:user];
@@ -1590,45 +1584,6 @@
     CHECK_COUNT(NUMBER_OF_BIG_OBJECTS, HugeSyncObject, realm);
 }
 
-- (void)testDownloadWhileOpeningRealm {
-    const NSInteger NUMBER_OF_BIG_OBJECTS = 2;
-    NSURL *url = REALM_URL();
-    // Log in the user.
-    RLMSyncUser *user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd)
-                                                                                            register:self.isParent]
-                                               server:[RLMObjectServerTests authServerURL]];
-    if (self.isParent) {
-        // Wait for the child process to upload everything.
-        RLMRunChildAndWait();
-        XCTestExpectation *ex = [self expectationWithDescription:@"download-realm"];
-        RLMRealmConfiguration *c = [user configurationWithURL:url fullSynchronization:true];
-        XCTAssertFalse([[NSFileManager defaultManager] fileExistsAtPath:c.pathOnDisk isDirectory:nil]);
-        [RLMRealm asyncOpenWithConfiguration:c
-                               callbackQueue:dispatch_get_main_queue()
-                                    callback:^(RLMRealm * _Nullable realm, NSError * _Nullable error) {
-            XCTAssertNil(error);
-            CHECK_COUNT(NUMBER_OF_BIG_OBJECTS, HugeSyncObject, realm);
-            [ex fulfill];
-        }];
-        RLMRealm *realm = [RLMRealm realmWithConfiguration:c error:nil];
-        CHECK_COUNT(0, HugeSyncObject, realm);
-        XCTAssertNotNil(RLMGetAnyCachedRealmForPath(c.pathOnDisk.UTF8String));
-        [self waitForExpectationsWithTimeout:10.0 handler:nil];
-        CHECK_COUNT(NUMBER_OF_BIG_OBJECTS, HugeSyncObject, realm);
-        XCTAssertNotNil(RLMGetAnyCachedRealmForPath(c.pathOnDisk.UTF8String));
-    } else {
-        RLMRealm *realm = [self openRealmForURL:url user:user];
-        // Write lots of data to the Realm, then wait for it to be uploaded.
-        [realm beginWriteTransaction];
-        for (NSInteger i=0; i<NUMBER_OF_BIG_OBJECTS; i++) {
-            [realm addObject:[HugeSyncObject object]];
-        }
-        [realm commitWriteTransaction];
-        [self waitForUploadsForRealm:realm];
-        CHECK_COUNT(NUMBER_OF_BIG_OBJECTS, HugeSyncObject, realm);
-    }
-}
-
 - (void)testDownloadCancelsOnAuthError {
     RLMSyncUser *user = [self logInUserForCredentials:[RLMObjectServerTests basicCredentialsWithName:NSStringFromSelector(_cmd)
                                                                                             register:self.isParent]

+ 1 - 1
Carthage/Checkouts/realm-cocoa/Realm/ObjectServerTests/RLMSyncTestCase.mm

@@ -82,7 +82,7 @@ static NSString *nodePath() {
     const NSInteger fakeDataSize = 1000000;
     HugeSyncObject *object = [[self alloc] init];
     char fakeData[fakeDataSize];
-    memset(fakeData, sizeof(fakeData), 16);
+    memset(fakeData, 16, sizeof(fakeData));
     object.dataProp = [NSData dataWithBytes:fakeData length:sizeof(fakeData)];
     return object;
 }

+ 5 - 14
Carthage/Checkouts/realm-cocoa/Realm/ObjectServerTests/SwiftObjectServerTests.swift

@@ -235,26 +235,24 @@ class SwiftObjectServerTests: SwiftSyncTestCase {
     func testStreamingUploadNotifier() {
         let bigObjectCount = 2
         do {
-            var callCount = 0
             var transferred = 0
             var transferrable = 0
             let user = try synchronouslyLogInUser(for: basicCredentials(register: isParent), server: authURL)
             let realm = try synchronouslyOpenRealm(url: realmURL, user: user)
             let session = realm.syncSession
             XCTAssertNotNil(session)
-            let ex = expectation(description: "streaming-uploads-expectation")
-            var hasBeenFulfilled = false
+            var ex = expectation(description: "initial upload")
             let token = session!.addProgressNotification(for: .upload, mode: .reportIndefinitely) { p in
-                callCount += 1
                 XCTAssert(p.transferredBytes >= transferred)
                 XCTAssert(p.transferrableBytes >= transferrable)
                 transferred = p.transferredBytes
                 transferrable = p.transferrableBytes
-                if p.transferredBytes > 0 && p.isTransferComplete && !hasBeenFulfilled {
+                if p.transferredBytes > 0 && p.isTransferComplete {
                     ex.fulfill()
-                    hasBeenFulfilled = true
                 }
             }
+            waitForExpectations(timeout: 10.0, handler: nil)
+            ex = expectation(description: "write transaction upload")
             try realm.write {
                 for _ in 0..<bigObjectCount {
                     realm.add(SwiftHugeSyncObject())
@@ -262,7 +260,6 @@ class SwiftObjectServerTests: SwiftSyncTestCase {
             }
             waitForExpectations(timeout: 10.0, handler: nil)
             token!.invalidate()
-            XCTAssert(callCount > 1)
             XCTAssert(transferred >= transferrable)
         } catch {
             XCTFail("Got an error: \(error) (process: \(isParent ? "parent" : "child"))")
@@ -293,15 +290,9 @@ class SwiftObjectServerTests: SwiftSyncTestCase {
                     }
                     return 0
                 }
-                let sizeBefore = fileSize(path: pathOnDisk)
-                autoreleasepool {
-                    // We have partial transaction logs but no data
-                    XCTAssertGreaterThan(sizeBefore, 0)
-                    XCTAssert(try! Realm(configuration: config).isEmpty)
-                }
                 XCTAssertFalse(RLMHasCachedRealmForPath(pathOnDisk))
                 waitForExpectations(timeout: 10.0, handler: nil)
-                XCTAssertGreaterThan(fileSize(path: pathOnDisk), sizeBefore)
+                XCTAssertGreaterThan(fileSize(path: pathOnDisk), 0)
                 XCTAssertFalse(RLMHasCachedRealmForPath(pathOnDisk))
             } else {
                 let realm = try synchronouslyOpenRealm(url: realmURL, user: user)

+ 2 - 2
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/CMake/RealmCore.cmake

@@ -260,8 +260,8 @@ macro(build_realm_core)
     set(core_release_binary_dir "${SOURCE_DIR}/build.release")
     set(core_library_debug "${core_debug_binary_dir}/src/realm/${CMAKE_STATIC_LIBRARY_PREFIX}realm-dbg${CMAKE_STATIC_LIBRARY_SUFFIX}")
     set(core_library_release "${core_release_binary_dir}/src/realm/${CMAKE_STATIC_LIBRARY_PREFIX}realm${CMAKE_STATIC_LIBRARY_SUFFIX}")
-    set(core_parser_library_debug "${core_debug_binary_dir}/src/realm/${CMAKE_STATIC_LIBRARY_PREFIX}realm-parser-dbg${CMAKE_STATIC_LIBRARY_SUFFIX}")
-    set(core_parser_library_release "${core_release_binary_dir}/src/realm/${CMAKE_STATIC_LIBRARY_PREFIX}realm-parser${CMAKE_STATIC_LIBRARY_SUFFIX}")
+    set(core_parser_library_debug "${core_debug_binary_dir}/src/realm/parser/${CMAKE_STATIC_LIBRARY_PREFIX}realm-parser-dbg${CMAKE_STATIC_LIBRARY_SUFFIX}")
+    set(core_parser_library_release "${core_release_binary_dir}/src/realm/parser/${CMAKE_STATIC_LIBRARY_PREFIX}realm-parser${CMAKE_STATIC_LIBRARY_SUFFIX}")
 
     ExternalProject_Add_Step(realm-core ensure-libraries
         DEPENDEES build

+ 5 - 0
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/CMakeLists.txt

@@ -30,6 +30,11 @@ if(REALM_CORE_PREFIX AND REALM_ENABLE_SYNC AND NOT REALM_SYNC_PREFIX)
     message(FATAL_ERROR "REALM_SYNC_PREFIX must be set when specifying REALM_CORE_PREFIX when REALM_ENABLE_SYNC is set.")
 endif()
 
+set(REALM_ENABLE_SERVER OFF CACHE BOOL "Enable the server-only functionality.")
+if(REALM_ENABLE_SERVER AND NOT REALM_ENABLE_SYNC)
+    message(FATAL_ERROR "REALM_ENABLE_SERVER requires REALM_ENABLE_SYNC.")
+endif()
+
 include(RealmCore)
 use_realm_core("${REALM_ENABLE_SYNC}" "${REALM_CORE_PREFIX}" "${REALM_SYNC_PREFIX}")
 

+ 2 - 2
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/dependencies.list

@@ -1,4 +1,4 @@
-REALM_CORE_VERSION=5.12.0
-REALM_SYNC_VERSION=3.12.10
+REALM_CORE_VERSION=5.12.7
+REALM_SYNC_VERSION=3.14.12
 ANDROID_OPENSSL_VERSION=1.0.2k
 REALM_CORE_PACKAGING=2

+ 16 - 2
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/CMakeLists.txt

@@ -64,14 +64,16 @@ set(HEADERS
 
     util/aligned_union.hpp
     util/atomic_shared_ptr.hpp
+    util/event_loop_dispatcher.hpp
     util/event_loop_signal.hpp
+    util/fifo.hpp
     util/tagged_bool.hpp
     util/uuid.hpp)
 
 if(APPLE)
-    list(APPEND SOURCES impl/apple/external_commit_helper.cpp impl/apple/keychain_helper.cpp)
+    list(APPEND SOURCES impl/apple/external_commit_helper.cpp impl/apple/keychain_helper.cpp util/fifo.cpp)
 elseif(REALM_HAVE_EPOLL)
-    list(APPEND SOURCES impl/epoll/external_commit_helper.cpp)
+    list(APPEND SOURCES impl/epoll/external_commit_helper.cpp util/fifo.cpp)
 elseif(CMAKE_SYSTEM_NAME MATCHES "^Windows")
     list(APPEND SOURCES impl/windows/external_commit_helper.cpp)
 else()
@@ -119,6 +121,18 @@ if(REALM_ENABLE_SYNC)
     list(APPEND INCLUDE_DIRS ${ZLIB_INCLUDE_DIRS})
 endif()
 
+if(REALM_ENABLE_SERVER)
+    list(APPEND HEADERS
+        server/adapter.hpp
+        server/admin_realm.hpp
+        server/global_notifier.hpp)
+    list(APPEND SOURCES
+        server/adapter.cpp
+        server/admin_realm.cpp
+        server/global_notifier.cpp)
+    list(APPEND INCLUDE_DIRS ../external/json)
+endif()
+
 add_library(realm-object-store STATIC ${SOURCES} ${HEADERS})
 set_target_properties(realm-object-store PROPERTIES POSITION_INDEPENDENT_CODE 1)
 target_compile_definitions(realm-object-store PRIVATE ${PLATFORM_DEFINES})

+ 38 - 24
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/apple/external_commit_helper.cpp

@@ -17,8 +17,10 @@
 ////////////////////////////////////////////////////////////////////////////
 
 #include "impl/external_commit_helper.hpp"
-
 #include "impl/realm_coordinator.hpp"
+#include "util/fifo.hpp"
+
+#include <realm/group_shared_options.hpp>
 
 #include <asl.h>
 #include <assert.h>
@@ -53,6 +55,7 @@ void notify_fd(int fd, int read_fd)
         read(read_fd, buff, sizeof buff);
     }
 }
+
 } // anonymous namespace
 
 void ExternalCommitHelper::FdHolder::close()
@@ -95,27 +98,38 @@ ExternalCommitHelper::ExternalCommitHelper(RealmCoordinator& parent)
     }
 
 #if !TARGET_OS_TV
-    auto path = parent.get_path() + ".note";
 
-    // Create and open the named pipe
-    int ret = mkfifo(path.c_str(), 0600);
-    if (ret == -1) {
-        int err = errno;
-        if (err == ENOTSUP) {
-            // Filesystem doesn't support named pipes, so try putting it in tmp instead
-            // Hash collisions are okay here because they just result in doing
-            // extra work, as opposed to correctness problems
-            std::ostringstream ss;
-            ss << getenv("TMPDIR");
-            ss << "realm_" << std::hash<std::string>()(path) << ".note";
-            path = ss.str();
-            ret = mkfifo(path.c_str(), 0600);
-            err = errno;
-        }
-        // the fifo already existing isn't an error
-        if (ret == -1 && err != EEXIST) {
-            throw std::system_error(err, std::system_category());
-        }
+
+    // Object Store needs to create a named pipe in order to coordinate notifications.
+    // This can be a problem on some file systems (e.g. FAT32) or due to security policies in SELinux. Most commonly
+    // it is a problem when saving Realms on external storage: https://stackoverflow.com/questions/2740321/how-to-create-named-pipe-mkfifo-in-android
+    //
+    // For this reason we attempt to create this file in a temporary location known to be safe to write these files.
+    //
+    // In order of priority we attempt to write the file in the following locations:
+    //  1) Next to the Realm file itself
+    //  2) A location defined by `Realm::Config::fifo_files_fallback_path`
+    //  3) A location defined by `SharedGroupOptions::set_sys_tmp_dir()`
+    //
+    // Core has a similar policy for its named pipes.
+    //
+    // Also see https://github.com/realm/realm-java/issues/3140
+    // Note that hash collisions are okay here because they just result in doing extra work instead of resulting
+    // in correctness problems.
+
+    std::string path;
+    std::string temp_dir = util::normalize_dir(parent.get_config().fifo_files_fallback_path);
+    std::string sys_temp_dir = util::normalize_dir(SharedGroupOptions::get_sys_tmp_dir());
+
+    path = parent.get_path() + ".note";
+    bool fifo_created = util::try_create_fifo(path);
+    if (!fifo_created && !temp_dir.empty()) {
+        path = util::format("%1realm_%2.note", temp_dir, std::hash<std::string>()(parent.get_path()));
+        fifo_created = util::try_create_fifo(path);
+    }
+    if (!fifo_created && !sys_temp_dir.empty()) {
+        path = util::format("%1realm_%2.note", sys_temp_dir, std::hash<std::string>()(parent.get_path()));
+        util::create_fifo(path);
     }
 
     m_notify_fd = open(path.c_str(), O_RDWR);
@@ -125,7 +139,7 @@ ExternalCommitHelper::ExternalCommitHelper(RealmCoordinator& parent)
 
     // Make writing to the pipe return -1 when the pipe's buffer is full
     // rather than blocking until there's space available
-    ret = fcntl(m_notify_fd, F_SETFL, O_NONBLOCK);
+    int ret = fcntl(m_notify_fd, F_SETFL, O_NONBLOCK);
     if (ret == -1) {
         throw std::system_error(errno, std::system_category());
     }
@@ -154,7 +168,7 @@ ExternalCommitHelper::ExternalCommitHelper(RealmCoordinator& parent)
     m_shutdown_read_fd = shutdown_pipe[0];
     m_shutdown_write_fd = shutdown_pipe[1];
 
-    m_thread = std::async(std::launch::async, [=] {
+    m_thread = std::thread([=] {
         try {
             listen();
         }
@@ -177,7 +191,7 @@ ExternalCommitHelper::ExternalCommitHelper(RealmCoordinator& parent)
 ExternalCommitHelper::~ExternalCommitHelper()
 {
     notify_fd(m_shutdown_write_fd, m_shutdown_read_fd);
-    m_thread.wait(); // Wait for the thread to exit
+    m_thread.join(); // Wait for the thread to exit
 }
 
 void ExternalCommitHelper::listen()

+ 2 - 2
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/apple/external_commit_helper.hpp

@@ -16,7 +16,7 @@
 //
 ////////////////////////////////////////////////////////////////////////////
 
-#include <future>
+#include <thread>
 
 namespace realm {
 class Realm;
@@ -59,7 +59,7 @@ private:
     RealmCoordinator& m_parent;
 
     // The listener thread
-    std::future<void> m_thread;
+    std::thread m_thread;
 
     // Pipe which is waited on for changes and written to when there is a new
     // commit to notify others of. When using a named pipe m_notify_fd is

+ 30 - 32
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/epoll/external_commit_helper.cpp

@@ -18,6 +18,7 @@
 
 #include "impl/external_commit_helper.hpp"
 #include "impl/realm_coordinator.hpp"
+#include "util/fifo.hpp"
 
 #include <realm/util/assert.hpp>
 #include <realm/group_shared_options.hpp>
@@ -29,8 +30,6 @@
 #include <stdlib.h>
 #include <sys/epoll.h>
 #include <sys/time.h>
-#include <sys/stat.h>
-#include <system_error>
 #include <unistd.h>
 
 #ifdef __ANDROID__
@@ -115,36 +114,35 @@ ExternalCommitHelper::ExternalCommitHelper(RealmCoordinator& parent)
 : m_parent(parent)
 {
     std::string path;
-    std::string temporary_dir = SharedGroupOptions::get_sys_tmp_dir();
-    if (temporary_dir.empty()) {
-        path = parent.get_path() + ".note";
-    } else {
-        // The fifo is always created in the temporary directory if it is provided.
-        // See https://github.com/realm/realm-java/issues/3140
-        // We create .note file on the temp directory always for simplicity no matter where the Realm file is.
-        // Hash collisions are okay here because they just result in doing extra work.
-        path = util::format("%1%2_realm.note", temporary_dir, std::hash<std::string>()(parent.get_path()));
+    std::string temp_dir = util::normalize_dir(parent.get_config().fifo_files_fallback_path);
+    std::string sys_temp_dir = util::normalize_dir(SharedGroupOptions::get_sys_tmp_dir());
+
+    // Object Store needs to create a named pipe in order to coordinate notifications.
+    // This can be a problem on some file systems (e.g. FAT32) or due to security policies in SELinux. Most commonly
+    // it is a problem when saving Realms on external storage: https://stackoverflow.com/questions/2740321/how-to-create-named-pipe-mkfifo-in-android
+    //
+    // For this reason we attempt to create this file in a temporary location known to be safe to write these files.
+    //
+    // In order of priority we attempt to write the file in the following locations:
+    //  1) Next to the Realm file itself
+    //  2) A location defined by `Realm::Config::fifo_files_fallback_path`
+    //  3) A location defined by `SharedGroupOptions::set_sys_tmp_dir()`
+    //
+    // Core has a similar policy for its named pipes.
+    //
+    // Also see https://github.com/realm/realm-java/issues/3140
+    // Note that hash collisions are okay here because they just result in doing extra work instead of resulting
+    // in correctness problems.
+
+    path = parent.get_path() + ".note";
+    bool fifo_created = util::try_create_fifo(path);
+    if (!fifo_created && !temp_dir.empty()) {
+        path = util::format("%1realm_%2.note", temp_dir, std::hash<std::string>()(parent.get_path()));
+        fifo_created = util::try_create_fifo(path);
     }
-
-    // Create and open the named pipe
-    int ret = mkfifo(path.c_str(), 0600);
-    if (ret == -1) {
-        int err = errno;
-        // the fifo already existing isn't an error
-        if (err != EEXIST) {
-            // Workaround for a mkfifo bug on Blackberry devices:
-            // When the fifo already exists, mkfifo fails with error ENOSYS which is not correct.
-            // In this case, we use stat to check if the path exists and it is a fifo.
-            struct stat stat_buf;
-            if (err == ENOSYS && stat(path.c_str(), &stat_buf) == 0) {
-                if ((stat_buf.st_mode & S_IFMT) != S_IFIFO) {
-                    throw std::runtime_error(path + " exists and it is not a fifo.");
-                }
-            }
-            else {
-                throw std::system_error(err, std::system_category());
-            }
-        }
+    if (!fifo_created && !sys_temp_dir.empty()) {
+        path = util::format("%1realm_%2.note", sys_temp_dir, std::hash<std::string>()(parent.get_path()));
+        util::create_fifo(path);
     }
 
     m_notify_fd = open(path.c_str(), O_RDWR);
@@ -154,7 +152,7 @@ ExternalCommitHelper::ExternalCommitHelper(RealmCoordinator& parent)
 
     // Make writing to the pipe return -1 when the pipe's buffer is full
     // rather than blocking until there's space available
-    ret = fcntl(m_notify_fd, F_SETFL, O_NONBLOCK);
+    int ret = fcntl(m_notify_fd, F_SETFL, O_NONBLOCK);
     if (ret == -1) {
         throw std::system_error(errno, std::system_category());
     }

+ 27 - 9
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/realm_coordinator.cpp

@@ -196,6 +196,7 @@ std::shared_ptr<Realm> RealmCoordinator::get_realm(Realm::Config config)
     auto schema = std::move(config.schema);
     auto migration_function = std::move(config.migration_function);
     auto initialization_function = std::move(config.initialization_function);
+    auto audit_factory = std::move(config.audit_factory);
     config.schema = {};
 
     if (config.cache) {
@@ -239,6 +240,9 @@ std::shared_ptr<Realm> RealmCoordinator::get_realm(Realm::Config config)
     if (realm->config().sync_config)
         create_sync_session();
 
+    if (!m_audit_context && audit_factory)
+        m_audit_context = audit_factory();
+
     if (schema) {
         lock.unlock();
         realm->update_schema(std::move(*schema), config.schema_version, std::move(migration_function),
@@ -321,10 +325,19 @@ RealmCoordinator::~RealmCoordinator()
 
 void RealmCoordinator::unregister_realm(Realm* realm)
 {
-    std::lock_guard<std::mutex> lock(m_realm_mutex);
-    auto new_end = remove_if(begin(m_weak_realm_notifiers), end(m_weak_realm_notifiers),
-                             [=](auto& notifier) { return notifier.expired() || notifier.is_for_realm(realm); });
-    m_weak_realm_notifiers.erase(new_end, end(m_weak_realm_notifiers));
+    // Normally results notifiers are cleaned up by the background worker thread
+    // but if that's disabled we need to ensure that any notifiers from this
+    // Realm get cleaned up
+    if (!m_config.automatic_change_notifications) {
+        std::unique_lock<std::mutex> lock(m_notifier_mutex);
+        clean_up_dead_notifiers();
+    }
+    {
+        std::lock_guard<std::mutex> lock(m_realm_mutex);
+        auto new_end = remove_if(begin(m_weak_realm_notifiers), end(m_weak_realm_notifiers),
+                                 [=](auto& notifier) { return notifier.expired() || notifier.is_for_realm(realm); });
+        m_weak_realm_notifiers.erase(new_end, end(m_weak_realm_notifiers));
+    }
 }
 
 void RealmCoordinator::clear_cache()
@@ -864,11 +877,10 @@ void RealmCoordinator::process_available_async(Realm& realm)
     if (notifiers.empty())
         return;
 
-    if (realm.m_binding_context)
-        realm.m_binding_context->will_send_notifications();
-
     if (auto error = m_async_error) {
         lock.unlock();
+        if (realm.m_binding_context)
+            realm.m_binding_context->will_send_notifications();
         for (auto& notifier : notifiers)
             notifier->deliver_error(m_async_error);
         if (realm.m_binding_context)
@@ -878,19 +890,25 @@ void RealmCoordinator::process_available_async(Realm& realm)
 
     bool in_read = realm.is_in_read_transaction();
     auto& sg = Realm::Internal::get_shared_group(realm);
-    if (!sg) // i.e. the Realm was closed in a callback above
-        return;
     auto version = sg->get_version_of_current_transaction();
     auto package = [&](auto& notifier) {
         return !(notifier->has_run() && (!in_read || notifier->version() == version) && notifier->package_for_delivery());
     };
     notifiers.erase(std::remove_if(begin(notifiers), end(notifiers), package), end(notifiers));
+    if (notifiers.empty())
+        return;
     lock.unlock();
 
     // no before advance because the Realm is already at the given version,
     // because we're either sending initial notifications or the write was
     // done on this Realm instance
 
+    if (realm.m_binding_context) {
+        realm.m_binding_context->will_send_notifications();
+        if (!sg) // i.e. the Realm was closed in the callback above
+            return;
+    }
+
     // Skip delivering if the Realm isn't in a read transaction
     if (in_read) {
         for (auto& notifier : notifiers)

+ 4 - 0
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/impl/realm_coordinator.hpp

@@ -146,6 +146,8 @@ public:
     partial_sync::WorkQueue& partial_sync_work_queue();
 #endif
 
+    AuditInterface* audit_context() const noexcept { return m_audit_context.get(); }
+
 private:
     Realm::Config m_config;
 
@@ -184,6 +186,8 @@ private:
     std::unique_ptr<partial_sync::WorkQueue> m_partial_sync_work_queue;
 #endif
 
+    std::shared_ptr<AuditInterface> m_audit_context;
+
     // must be called with m_notifier_mutex locked
     void pin_version(VersionID version);
 

+ 3 - 0
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/results.cpp

@@ -20,6 +20,7 @@
 
 #include "impl/realm_coordinator.hpp"
 #include "impl/results_notifier.hpp"
+#include "audit.hpp"
 #include "object_schema.hpp"
 #include "object_store.hpp"
 #include "schema.hpp"
@@ -267,6 +268,8 @@ void Results::evaluate_query_if_needed(bool wants_notifications)
                 prepare_async(ForCallback{false});
             m_has_used_table_view = true;
             m_table_view.sync_if_needed();
+            if (auto audit = m_realm->audit_context())
+                audit->record_query(m_realm->read_transaction_version(), m_table_view);
             break;
     }
 }

+ 31 - 11
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/shared_realm.cpp

@@ -21,7 +21,9 @@
 #include "impl/collection_notifier.hpp"
 #include "impl/realm_coordinator.hpp"
 #include "impl/transact_log_handler.hpp"
+#include "util/fifo.hpp"
 
+#include "audit.hpp"
 #include "binding_context.hpp"
 #include "list.hpp"
 #include "object.hpp"
@@ -144,7 +146,7 @@ REALM_NOINLINE static void translate_file_exception(StringData path, bool immuta
 static bool is_nonupgradable_history(IncompatibleHistories const& ex)
 {
     // FIXME: Replace this with a proper specific exception type once Core adds support for it.
-    return ex.what() == std::string("Incompatible histories. Nonupgradable history schema");
+    return std::string(ex.what()).find(std::string("Incompatible histories. Nonupgradable history schema")) != npos;
 }
 #endif
 
@@ -180,6 +182,8 @@ void Realm::open_with_config(const Config& config,
             SharedGroupOptions options;
             options.durability = config.in_memory ? SharedGroupOptions::Durability::MemOnly :
                                                     SharedGroupOptions::Durability::Full;
+
+            options.temp_dir = util::normalize_dir(config.fifo_files_fallback_path);
             options.encryption_key = config.encryption_key.data();
             options.allow_file_format_upgrade = !config.disable_format_upgrade &&
                                                 config.schema_mode != SchemaMode::ResetFile;
@@ -205,7 +209,7 @@ void Realm::open_with_config(const Config& config,
             translate_file_exception(config.path, config.immutable()); // Throws
 
         // Move the Realm file into the recovery directory.
-        std::string recovery_directory = SyncManager::shared().recovery_directory_path();
+        std::string recovery_directory = SyncManager::shared().recovery_directory_path(config.sync_config ? config.sync_config->recovery_directory : none);
         std::string new_realm_path = util::reserve_unique_file_name(recovery_directory, "synced-realm-XXXXXXX");
         util::File::move(config.path, new_realm_path);
 
@@ -585,14 +589,14 @@ void Realm::notify_schema_changed()
     }
 }
 
-static void check_read_write(Realm *realm)
+static void check_read_write(const Realm* realm)
 {
     if (realm->config().immutable()) {
         throw InvalidTransactionException("Can't perform transactions on read-only Realms.");
     }
 }
 
-static void check_write(Realm* realm)
+static void check_write(const Realm* realm)
 {
     if (realm->config().immutable() || realm->config().read_only_alternative()) {
         throw InvalidTransactionException("Can't perform transactions on read-only Realms.");
@@ -623,6 +627,14 @@ void Realm::verify_open() const
     }
 }
 
+VersionID Realm::read_transaction_version() const
+{
+    verify_thread();
+    verify_open();
+    check_read_write(this);
+    return m_shared_group->get_version_of_current_transaction();
+}
+
 bool Realm::is_in_transaction() const noexcept
 {
     if (!m_shared_group) {
@@ -678,7 +690,15 @@ void Realm::commit_transaction()
         throw InvalidTransactionException("Can't commit a non-existing write transaction");
     }
 
-    m_coordinator->commit_write(*this);
+    if (auto audit = audit_context()) {
+        auto prev_version = m_shared_group->pin_version();
+        m_coordinator->commit_write(*this);
+        audit->record_write(prev_version, m_shared_group->get_version_of_current_transaction());
+        m_shared_group->unpin_version(prev_version);
+    }
+    else {
+        m_coordinator->commit_write(*this);
+    }
     cache_new_schema();
     invalidate_permission_cache();
 }
@@ -864,7 +884,7 @@ bool Realm::refresh()
 
 bool Realm::can_deliver_notifications() const noexcept
 {
-    if (m_config.immutable()) {
+    if (m_config.immutable() || !m_config.automatic_change_notifications) {
         return false;
     }
 
@@ -987,6 +1007,11 @@ template Object Realm::resolve_thread_safe_reference(ThreadSafeReference<Object>
 template List Realm::resolve_thread_safe_reference(ThreadSafeReference<List> reference);
 template Results Realm::resolve_thread_safe_reference(ThreadSafeReference<Results> reference);
 
+AuditInterface* Realm::audit_context() const noexcept
+{
+    return m_coordinator ? m_coordinator->audit_context() : nullptr;
+}
+
 #if REALM_ENABLE_SYNC
 static_assert(static_cast<int>(ComputedPrivileges::Read) == static_cast<int>(sync::Privilege::Read), "");
 static_assert(static_cast<int>(ComputedPrivileges::Update) == static_cast<int>(sync::Privilege::Update), "");
@@ -1107,8 +1132,3 @@ Group& RealmFriend::read_group_to(Realm& realm, VersionID version)
     realm.begin_read(version);
     return *realm.m_group;
 }
-
-std::size_t Realm::compute_size() {
-    Group& group = read_group();
-    return group.compute_aggregated_byte_size();
-}

+ 18 - 8
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/src/shared_realm.hpp

@@ -32,6 +32,7 @@
 #include <memory>
 
 namespace realm {
+class AuditInterface;
 class BindingContext;
 class Group;
 class Realm;
@@ -188,6 +189,11 @@ public:
         // User-supplied encryption key. Must be either empty or 64 bytes.
         std::vector<char> encryption_key;
 
+        // Core and Object Store will in some cases need to create named pipes alongside the Realm file.
+        // But on some filesystems this can be a problem (e.g. external storage on Android that uses FAT32).
+        // In order to work around this, a separate path can be specified for these files.
+        std::string fifo_files_fallback_path;
+
         bool in_memory = false;
         SchemaMode schema_mode = SchemaMode::Automatic;
 
@@ -242,9 +248,12 @@ public:
         /// A data structure storing data used to configure the Realm for sync support.
         std::shared_ptr<SyncConfig> sync_config;
 
-        // FIXME: Realm Java manages sync at the Java level, so it needs to create Realms using the sync history
-        //        format.
+        // Open the Realm using the sync history mode even if a sync
+        // configuration is not supplied.
         bool force_sync_history = false;
+
+        // A factory function which produces an audit implementation.
+        std::function<std::shared_ptr<AuditInterface>()> audit_factory;
     };
 
     // Get a cached Realm or create a new one if no cached copies exists
@@ -279,7 +288,10 @@ public:
     void commit_transaction();
     void cancel_transaction();
     bool is_in_transaction() const noexcept;
+
     bool is_in_read_transaction() const { return !!m_group; }
+    VersionID read_transaction_version() const;
+    Group& read_group();
 
     bool is_in_migration() const noexcept { return m_in_migration; }
 
@@ -329,6 +341,8 @@ public:
     ComputedPrivileges get_privileges(StringData object_type);
     ComputedPrivileges get_privileges(RowExpr row);
 
+    AuditInterface* audit_context() const noexcept;
+
     static SharedRealm make_shared_realm(Config config, std::shared_ptr<_impl::RealmCoordinator> coordinator = nullptr) {
         struct make_shared_enabler : public Realm {
             make_shared_enabler(Config config, std::shared_ptr<_impl::RealmCoordinator> coordinator)
@@ -426,12 +440,8 @@ private:
 public:
     std::unique_ptr<BindingContext> m_binding_context;
 
-    // FIXME private
-    Group& read_group();
-
-    std::size_t compute_size();
-    
-    Replication *history() { return m_history.get(); }
+    // FIXME: This is currently needed by the adapter to get access to its changeset cooker
+    Replication* history() { return m_history.get(); }
 
     friend class _impl::RealmFriend;
 };

+ 2 - 0
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/CMakeLists.txt

@@ -5,6 +5,7 @@ set(HEADERS
     util/index_helpers.hpp
     util/templated_test_case.hpp
     util/test_file.hpp
+    util/test_utils.hpp
 )
 
 set(SOURCES
@@ -25,6 +26,7 @@ set(SOURCES
 
     util/event_loop.cpp
     util/test_file.cpp
+    util/test_utils.cpp
 )
 
 

+ 52 - 1
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/realm.cpp

@@ -21,6 +21,7 @@
 #include "util/event_loop.hpp"
 #include "util/test_file.hpp"
 #include "util/templated_test_case.hpp"
+#include "util/test_utils.hpp"
 
 #include "binding_context.hpp"
 #include "object_schema.hpp"
@@ -152,6 +153,53 @@ TEST_CASE("SharedRealm: get_shared_realm()") {
         }
     }
 
+
+// Windows doesn't use fifos
+#ifndef _WIN32
+    SECTION("should be able to set a FIFO fallback path") {
+        std::string fallback_dir = tmp_dir() + "/fallback/";
+        realm::util::try_make_dir(fallback_dir);
+        TestFile config;
+        config.fifo_files_fallback_path = fallback_dir;
+        config.schema_version = 1;
+        config.schema = Schema{
+            {"object", {
+                {"value", PropertyType::Int}
+            }},
+        };
+
+        realm::util::make_dir(config.path + ".note");
+        auto realm = Realm::get_shared_realm(config);
+        auto fallback_file = util::format("%1realm_%2.note", fallback_dir, std::hash<std::string>()(config.path)); // Mirror internal implementation
+        REQUIRE(File::exists(fallback_file));
+        realm::util::remove_dir(config.path + ".note");
+        realm::util::remove_dir_recursive(fallback_dir);
+    }
+#endif
+
+// Windows doesn't use fifos
+#ifndef _WIN32
+    SECTION("automatically append dir separator to end of fallback path") {
+        std::string fallback_dir = tmp_dir() + "/fallback";
+        realm::util::try_make_dir(fallback_dir);
+        TestFile config;
+        config.fifo_files_fallback_path = fallback_dir;
+        config.schema_version = 1;
+        config.schema = Schema{
+            {"object", {
+                {"value", PropertyType::Int}
+            }},
+        };
+
+        realm::util::make_dir(config.path + ".note");
+        auto realm = Realm::get_shared_realm(config);
+        auto fallback_file = util::format("%1/realm_%2.note", fallback_dir, std::hash<std::string>()(config.path)); // Mirror internal implementation
+        REQUIRE(File::exists(fallback_file));
+        realm::util::remove_dir(config.path + ".note");
+        realm::util::remove_dir_recursive(fallback_dir);
+    }
+#endif
+
     SECTION("should verify that the schema is valid") {
         config.schema = Schema{
             {"object",
@@ -337,8 +385,11 @@ TEST_CASE("SharedRealm: get_shared_realm()") {
 #ifndef _WIN32
     SECTION("should throw when creating the notification pipe fails") {
         util::try_make_dir(config.path + ".note");
+        auto sys_fallback_file = util::format("%1realm_%2.note", SharedGroupOptions::get_sys_tmp_dir(), std::hash<std::string>()(config.path)); // Mirror internal implementation
+        util::try_make_dir(sys_fallback_file);
         REQUIRE_THROWS(Realm::get_shared_realm(config));
         util::remove_dir(config.path + ".note");
+        util::remove_dir(sys_fallback_file);
     }
 #endif
 
@@ -1580,7 +1631,7 @@ TEST_CASE("Statistics on Realms") {
     });
 
     SECTION("compute_size") {
-        auto s = r->compute_size();
+        auto s = r->read_group().compute_aggregated_byte_size();
         REQUIRE(s > 0);
     }
 }

+ 40 - 1
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/tests/results.cpp

@@ -41,6 +41,15 @@
 #include "sync/sync_session.hpp"
 #endif
 
+namespace realm {
+class TestHelper {
+public:
+    static SharedGroup& get_shared_group(SharedRealm const& shared_realm)
+    {
+        return *Realm::Internal::get_shared_group(*shared_realm);
+    }
+};
+}
 
 using namespace realm;
 using namespace std::string_literals;
@@ -1897,7 +1906,7 @@ TEST_CASE("results: notifications after move") {
     }
 }
 
-TEST_CASE("results: implicit background notifier") {
+TEST_CASE("results: notifier with no callbacks") {
     _impl::RealmCoordinator::assert_no_open_realms();
 
     InMemoryTestFile config;
@@ -1917,6 +1926,11 @@ TEST_CASE("results: implicit background notifier") {
     results.last(); // force evaluation and creation of TableView
 
     SECTION("refresh() does not block due to implicit notifier") {
+        // Create and then immediately remove a callback because
+        // `automatic_change_notifications = false` makes Results not implicitly
+        // create a notifier
+        results.add_notification_callback([](CollectionChangeSet const&, std::exception_ptr) {});
+
         auto r2 = coordinator->get_realm();
         r2->begin_transaction();
         r2->read_group().get_table("class_object")->add_empty_row();
@@ -1926,6 +1940,8 @@ TEST_CASE("results: implicit background notifier") {
     }
 
     SECTION("refresh() does not attempt to deliver stale results") {
+        results.add_notification_callback([](CollectionChangeSet const&, std::exception_ptr) {});
+
         // Create version 1
         r->begin_transaction();
         table->add_empty_row();
@@ -1942,6 +1958,29 @@ TEST_CASE("results: implicit background notifier") {
         // they're for version 1 and the realm is at 2)
         r->refresh();
     }
+
+    SECTION("should not pin the source version even after the Realm has been closed") {
+        auto r2 = coordinator->get_realm();
+        REQUIRE(r != r2);
+        r->close();
+
+        auto& shared_group = TestHelper::get_shared_group(r2);
+        // There's always at least 2 live versions because the previous version
+        // isn't clean up until the *next* commit
+        REQUIRE(shared_group.get_number_of_versions() == 2);
+
+        auto table = r2->read_group().get_table("class_object");
+
+        r2->begin_transaction();
+        table->add_empty_row();
+        r2->commit_transaction();
+        r2->begin_transaction();
+        table->add_empty_row();
+        r2->commit_transaction();
+
+        // Would now be 3 if the closed Realm is still pinning the version it was at
+        REQUIRE(shared_group.get_number_of_versions() == 2);
+    }
 }
 
 TEST_CASE("results: error messages") {

+ 1 - 1
Carthage/Checkouts/realm-cocoa/Realm/ObjectStore/workflow/build.sh

@@ -27,7 +27,7 @@ if [ "${flavor}" = "android" ]; then
 fi
 
 if [ "${sync}" = "sync" ]; then
-    cmake_flags="${cmake_flags} -DREALM_ENABLE_SYNC=1"
+    cmake_flags="${cmake_flags} -DREALM_ENABLE_SYNC=1 -DREALM_ENABLE_SERVER=1"
 fi
 
 cmake ${cmake_flags} ..

+ 2 - 1
Carthage/Checkouts/realm-cocoa/Realm/RLMCollection.h

@@ -18,12 +18,13 @@
 
 #import <Foundation/Foundation.h>
 
+#import <Realm/RLMConstants.h>
 #import <Realm/RLMThreadSafeReference.h>
 
 NS_ASSUME_NONNULL_BEGIN
 
 @class RLMRealm, RLMResults, RLMSortDescriptor, RLMNotificationToken, RLMCollectionChange;
-typedef NS_ENUM(int32_t, RLMPropertyType);
+typedef RLM_CLOSED_ENUM(int32_t, RLMPropertyType);
 
 /**
  A homogenous collection of Realm-managed objects. Examples of conforming types

+ 10 - 1
Carthage/Checkouts/realm-cocoa/Realm/RLMConstants.h

@@ -29,6 +29,15 @@ NS_ASSUME_NONNULL_BEGIN
 #define RLM_EXTENSIBLE_STRING_ENUM_CASE_SWIFT_NAME(fully_qualified, _) NS_SWIFT_NAME(fully_qualified)
 #endif
 
+// Swift 5 considers NS_ENUM to be "open", meaning there could be values present
+// other than the defined cases (which allows adding more cases later without
+// it being a breaking change), while older versions consider it "closed".
+#ifdef NS_CLOSED_ENUM
+#define RLM_CLOSED_ENUM NS_CLOSED_ENUM
+#else
+#define RLM_CLOSED_ENUM NS_ENUM
+#endif
+
 #if __has_attribute(ns_error_domain) && (!defined(__cplusplus) || !__cplusplus || __cplusplus >= 201103L)
 #define RLM_ERROR_ENUM(type, name, domain) \
     _Pragma("clang diagnostic push") \
@@ -47,7 +56,7 @@ NS_ASSUME_NONNULL_BEGIN
 
  For more information, see [Realm Models](https://realm.io/docs/objc/latest/#models).
  */
-typedef NS_ENUM(int32_t, RLMPropertyType) {
+typedef RLM_CLOSED_ENUM(int32_t, RLMPropertyType) {
 
 #pragma mark - Primitive types
 

+ 10 - 15
Carthage/Checkouts/realm-cocoa/Realm/RLMNetworkClient.mm

@@ -310,7 +310,7 @@ didCompleteWithError:(NSError *)error
         return;
     }
 
-    if (![self validateResponse:task.response data:_data error:&error]) {
+    if (NSError *error = [self validateResponse:task.response data:_data]) {
         _completionBlock(error, nil);
         return;
     }
@@ -330,11 +330,10 @@ didCompleteWithError:(NSError *)error
     _completionBlock(nil, (NSDictionary *)json);
 }
 
-- (BOOL)validateResponse:(NSURLResponse *)response data:(NSData *)data error:(NSError * __autoreleasing *)error {
+- (NSError *)validateResponse:(NSURLResponse *)response data:(NSData *)data {
     if (![response isKindOfClass:[NSHTTPURLResponse class]]) {
         // FIXME: Provide error message
-        *error = make_auth_error_bad_response();
-        return NO;
+        return make_auth_error_bad_response();
     }
 
     NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
@@ -353,28 +352,22 @@ didCompleteWithError:(NSError *)error
                 case RLMSyncAuthErrorExpiredPermissionOffer:
                 case RLMSyncAuthErrorAmbiguousPermissionOffer:
                 case RLMSyncAuthErrorFileCannotBeShared:
-                    *error = make_auth_error(responseModel);
-                    break;
+                    return make_auth_error(responseModel);
                 default:
                     // Right now we assume that any codes not described
                     // above are generic HTTP error codes.
-                    *error = make_auth_error_http_status(responseModel.status);
-                    break;
+                    return make_auth_error_http_status(responseModel.status);
             }
-        } else {
-            *error = make_auth_error_http_status(httpResponse.statusCode);
         }
-
-        return NO;
+        return make_auth_error_http_status(httpResponse.statusCode);
     }
 
     if (!data) {
         // FIXME: provide error message
-        *error = make_auth_error_bad_response();
-        return NO;
+        return make_auth_error_bad_response();
     }
 
-    return YES;
+    return nil;
 }
 
 - (RLMSyncErrorResponseModel *)responseModelFromData:(NSData *)data {
@@ -425,6 +418,8 @@ didCompleteWithError:(NSError *)error
 
     // Add the request to a task and start it
     [[session dataTaskWithRequest:request] resume];
+    // Tell the session to destroy itself once it's done with the request
+    [session finishTasksAndInvalidate];
 }
 @end
 

+ 1 - 1
Carthage/Checkouts/realm-cocoa/Realm/RLMRealm.mm

@@ -389,7 +389,7 @@ REALM_NOINLINE static void translateSharedGroupOpenException(RLMRealmConfigurati
     configuration = [configuration copy];
     Realm::Config& config = configuration.config;
 
-    RLMRealm *realm = [[RLMRealm alloc] initPrivate];
+    RLMRealm *realm = [[self alloc] initPrivate];
     realm->_dynamic = dynamic;
 
     // protects the realm cache and accessors cache

+ 3 - 1
Carthage/Checkouts/realm-cocoa/Realm/RLMSyncConfiguration_Private.h

@@ -18,9 +18,11 @@
 
 #import <Realm/RLMSyncConfiguration.h>
 
+#import <Realm/RLMConstants.h>
+
 NS_ASSUME_NONNULL_BEGIN
 
-typedef NS_ENUM(NSUInteger, RLMSyncStopPolicy) {
+typedef RLM_CLOSED_ENUM(NSUInteger, RLMSyncStopPolicy) {
     RLMSyncStopPolicyImmediately,
     RLMSyncStopPolicyLiveIndefinitely,
     RLMSyncStopPolicyAfterChangesUploaded,

+ 1 - 1
Carthage/Checkouts/realm-cocoa/Realm/RLMSyncManager.h

@@ -23,7 +23,7 @@
 @class RLMSyncSession;
 
 /// An enum representing different levels of sync-related logging that can be configured.
-typedef NS_ENUM(NSUInteger, RLMSyncLogLevel) {
+typedef RLM_CLOSED_ENUM(NSUInteger, RLMSyncLogLevel) {
     /// Nothing will ever be logged.
     RLMSyncLogLevelOff,
     /// Only fatal errors will be logged.

+ 2 - 1
Carthage/Checkouts/realm-cocoa/Realm/RLMSyncPermission.h

@@ -16,6 +16,7 @@
 //
 ////////////////////////////////////////////////////////////////////////////
 
+#import <Realm/RLMConstants.h>
 #import <Realm/RLMObject.h>
 
 @protocol RLMPermission, RLMPermissionUser;
@@ -362,7 +363,7 @@ FOUNDATION_EXTERN id RLMPermissionForRole(RLMArray *array, id role);
  access to a Realm can always read from that Realm, and users with
  administrative access can always read or write from the Realm.
  */
-typedef NS_ENUM(NSUInteger, RLMSyncAccessLevel) {
+typedef RLM_CLOSED_ENUM(NSUInteger, RLMSyncAccessLevel) {
     /// No access whatsoever.
     RLMSyncAccessLevelNone          = 0,
     /**

+ 1 - 1
Carthage/Checkouts/realm-cocoa/Realm/RLMSyncSession.h

@@ -57,7 +57,7 @@ typedef NS_ENUM(NSUInteger, RLMSyncConnectionState) {
  Progress notification blocks can be registered on sessions if your app wishes to be informed
  how many bytes have been uploaded or downloaded, for example to show progress indicator UIs.
  */
-typedef NS_ENUM(NSUInteger, RLMSyncProgressDirection) {
+typedef RLM_CLOSED_ENUM(NSUInteger, RLMSyncProgressDirection) {
     /// For monitoring upload progress.
     RLMSyncProgressDirectionUpload,
     /// For monitoring download progress.

+ 1 - 1
Carthage/Checkouts/realm-cocoa/Realm/RLMSyncSubscription.h

@@ -24,7 +24,7 @@ NS_ASSUME_NONNULL_BEGIN
 /**
  `RLMSyncSubscriptionState` is an enumeration representing the possible state of a sync subscription.
  */
-typedef NS_ENUM(NSInteger, RLMSyncSubscriptionState) {
+typedef RLM_CLOSED_ENUM(NSInteger, RLMSyncSubscriptionState) {
     /**
      An error occurred while creating the subscription or while the server was processing it.
      */

+ 2 - 2
Carthage/Checkouts/realm-cocoa/Realm/Realm-Info.plist

@@ -17,11 +17,11 @@
 	<key>CFBundlePackageType</key>
 	<string>FMWK</string>
 	<key>CFBundleShortVersionString</key>
-	<string>3.13.1</string>
+	<string>3.14.1</string>
 	<key>CFBundleSignature</key>
 	<string>????</string>
 	<key>CFBundleVersion</key>
-	<string>3.13.1</string>
+	<string>3.14.1</string>
 	<key>NSHumanReadableCopyright</key>
 	<string>Copyright © 2014 Realm. All rights reserved.</string>
 	<key>NSPrincipalClass</key>

+ 9 - 1
Carthage/Checkouts/realm-cocoa/Realm/Tests/AsyncTests.mm

@@ -30,6 +30,14 @@
 // A whole bunch of blocks don't use their RLMResults parameter
 #pragma clang diagnostic ignored "-Wunused-parameter"
 
+@interface ManualRefreshRealm : RLMRealm
+@end
+@implementation ManualRefreshRealm
+- (void)verifyNotificationsAreSupported:(__unused bool)isCollection {
+    // The normal implementation of this will reject realms with automatic change notifications disabled
+}
+@end
+
 @interface AsyncTests : RLMTestCase
 @end
 
@@ -583,7 +591,7 @@
     // Create ten RLMRealm instances, each with a different read version
     RLMRealm *realms[10];
     for (int i = 0; i < 10; ++i) {
-        RLMRealm *realm = realms[i] = [RLMRealm realmWithConfiguration:config error:nil];
+        RLMRealm *realm = realms[i] = [ManualRefreshRealm realmWithConfiguration:config error:nil];
         [realm transactionWithBlock:^{
             [IntObject createInRealm:realm withValue:@[@(i)]];
         }];

+ 2 - 2
Carthage/Checkouts/realm-cocoa/Realm/Tests/InterprocessTests.m

@@ -378,7 +378,7 @@
     else {
         RLMRealm *realm = RLMRealm.defaultRealm;
         [realm beginWriteTransaction];
-        abort();
+        _Exit(1);
     }
 }
 
@@ -394,7 +394,7 @@
     else {
         RLMRealm *realm = RLMRealm.defaultRealm;
         [realm beginWriteTransaction];
-        abort();
+        _Exit(1);
     }
 }
 

+ 6 - 0
Carthage/Checkouts/realm-cocoa/Realm/Tests/RealmTests.mm

@@ -1779,10 +1779,16 @@
     assert(![manager fileExistsAtPath:fifoURL.path]);
     [manager createDirectoryAtPath:fifoURL.path withIntermediateDirectories:YES attributes:nil error:nil];
 
+    // Ensure that it doesn't try to fall back to putting it in the temp directory
+    auto oldTempDir = realm::SharedGroupOptions::get_sys_tmp_dir();
+    realm::SharedGroupOptions::set_sys_tmp_dir("");
+
     NSError *error;
     XCTAssertNil([RLMRealm realmWithConfiguration:configuration error:&error], @"Should not have been able to open FIFO");
     XCTAssertNotNil(error);
     RLMValidateRealmError(error, RLMErrorFileAccess, @"Is a directory", nil);
+
+    realm::SharedGroupOptions::set_sys_tmp_dir(std::move(oldTempDir));
 }
 #endif
 

+ 1 - 1
Carthage/Checkouts/realm-cocoa/RealmSwift/Object.swift

@@ -269,7 +269,7 @@ open class Object: RLMObjectBase, ThreadConfined, RealmCollectionValue {
 
      Objects are considered the same if and only if they are both managed by the same
      Realm and point to the same underlying object in the database.
-     
+
      - note: Equality comparison is implemented by `isEqual(_:)`. If the object type
              is defined with a primary key, `isEqual(_:)` behaves identically to this
              method. If the object type is not defined with a primary key,

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio