Browse Source

add ThreadSafeDictionary

Signed-off-by: marinofaggiana <ios@nextcloud.com>
marinofaggiana 2 years ago
parent
commit
462cad06f1

+ 10 - 0
Nextcloud.xcodeproj/project.pbxproj

@@ -149,6 +149,10 @@
 		F7239871253D86B600257F49 /* NCEmptyDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7239870253D86B600257F49 /* NCEmptyDataSet.swift */; };
 		F7239877253D86D300257F49 /* NCEmptyView.xib in Resources */ = {isa = PBXBuildFile; fileRef = F7239876253D86D300257F49 /* NCEmptyView.xib */; };
 		F723B3DD22FC6D1D00301EFE /* NCShareCommentsCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F723B3DC22FC6D1C00301EFE /* NCShareCommentsCell.xib */; };
+		F7245924289BB50C00474787 /* ThreadSafeDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7245923289BB50B00474787 /* ThreadSafeDictionary.swift */; };
+		F7245925289BB59100474787 /* ThreadSafeDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7245923289BB50B00474787 /* ThreadSafeDictionary.swift */; };
+		F7245926289BB59300474787 /* ThreadSafeDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7245923289BB50B00474787 /* ThreadSafeDictionary.swift */; };
+		F7245927289BB59300474787 /* ThreadSafeDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7245923289BB50B00474787 /* ThreadSafeDictionary.swift */; };
 		F72685E727C78E490019EF5E /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = F72685E927C78E490019EF5E /* InfoPlist.strings */; };
 		F726EEEC1FED1C820030B9C8 /* NCEndToEndInitialize.swift in Sources */ = {isa = PBXBuildFile; fileRef = F726EEEB1FED1C820030B9C8 /* NCEndToEndInitialize.swift */; };
 		F72928A0253B0937009CA4FD /* NCMainNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F729289F253B0937009CA4FD /* NCMainNavigationController.swift */; };
@@ -642,6 +646,7 @@
 		F7239870253D86B600257F49 /* NCEmptyDataSet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCEmptyDataSet.swift; sourceTree = "<group>"; };
 		F7239876253D86D300257F49 /* NCEmptyView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NCEmptyView.xib; sourceTree = "<group>"; };
 		F723B3DC22FC6D1C00301EFE /* NCShareCommentsCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NCShareCommentsCell.xib; sourceTree = "<group>"; };
+		F7245923289BB50B00474787 /* ThreadSafeDictionary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThreadSafeDictionary.swift; sourceTree = "<group>"; };
 		F7267A81225DFCE100D6DB7D /* AFNetworking.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AFNetworking.framework; path = Carthage/Build/iOS/AFNetworking.framework; sourceTree = "<group>"; };
 		F72685E827C78E490019EF5E /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
 		F726EEEB1FED1C820030B9C8 /* NCEndToEndInitialize.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCEndToEndInitialize.swift; sourceTree = "<group>"; };
@@ -1563,6 +1568,7 @@
 				AF817EF0274BC781009ED85B /* NCUserBaseUrl.swift */,
 				F74AF3A3247FB6AE00AC767B /* NCUtilityFileSystem.swift */,
 				AF36077027BFA4E8001A243D /* ParallelWorker.swift */,
+				F7245923289BB50B00474787 /* ThreadSafeDictionary.swift */,
 				F702F2FC25EE5D2C008F8E80 /* NYMnemonic */,
 			);
 			path = Utility;
@@ -2390,6 +2396,7 @@
 				2C1D5D7523E2DE3300334ABB /* NCDatabase.swift in Sources */,
 				F7E98C1927E0D0FC001F9F19 /* NCManageDatabase+Video.swift in Sources */,
 				2C1D5D7623E2DE3300334ABB /* NCManageDatabase.swift in Sources */,
+				F7245927289BB59300474787 /* ThreadSafeDictionary.swift in Sources */,
 				2C33C48223E2C475005F963B /* NotificationService.swift in Sources */,
 				AF4BF617275629E20081CEEF /* NCManageDatabase+Account.swift in Sources */,
 				D575039F27146F93008DC9DC /* String+Extensions.swift in Sources */,
@@ -2420,6 +2427,7 @@
 			buildActionMask = 2147483647;
 			files = (
 				F746EC4E273906B80052598D /* NCViewCertificateDetails.swift in Sources */,
+				F7245925289BB59100474787 /* ThreadSafeDictionary.swift in Sources */,
 				F73D5E48246DE09200DF6467 /* NCElementsJSON.swift in Sources */,
 				F7EDE4E5262D7BBE00414FE6 /* NCSectionHeaderFooter.swift in Sources */,
 				F79EC78926316AC4004E59D6 /* NCPopupViewController.swift in Sources */,
@@ -2471,6 +2479,7 @@
 			buildActionMask = 2147483647;
 			files = (
 				F771E3F720E239B500AFB62D /* FileProviderExtension+Actions.swift in Sources */,
+				F7245926289BB59300474787 /* ThreadSafeDictionary.swift in Sources */,
 				F76673F022C90434007ED366 /* FileProviderUtility.swift in Sources */,
 				F7434B3420E23FD700417916 /* NCDatabase.swift in Sources */,
 				F702F2D125EE5B5C008F8E80 /* NCGlobal.swift in Sources */,
@@ -2523,6 +2532,7 @@
 				F769454022E9F077000A798A /* NCSharePaging.swift in Sources */,
 				F78ACD4221903CE00088454D /* NCListCell.swift in Sources */,
 				F76D3CF12428B40E005DFA87 /* NCViewerPDFSearch.swift in Sources */,
+				F7245924289BB50C00474787 /* ThreadSafeDictionary.swift in Sources */,
 				F73F537F1E929C8500F8678D /* NCMore.swift in Sources */,
 				F702F2CF25EE5B5C008F8E80 /* NCGlobal.swift in Sources */,
 				F72CD63A25C19EBF00F46F9A /* NCAutoUpload.swift in Sources */,

+ 3 - 3
iOSClient/AppDelegate.swift

@@ -49,9 +49,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
     var mainTabBar: NCMainTabBar?
     var activeMetadata: tableMetadata?
 
-    var listFilesVC: [String: NCFiles] = [:]
-    var listFavoriteVC: [String: NCFavorite] = [:]
-    var listOfflineVC: [String: NCOffline] = [:]
+    let listFilesVC = ThreadSafeDictionary<String,NCFiles>()
+    let listFavoriteVC = ThreadSafeDictionary<String,NCFavorite>()
+    let listOfflineVC = ThreadSafeDictionary<String,NCOffline>()
 
     var disableSharesView: Bool = false
     var documentPickerViewController: NCDocumentPickerViewController?

+ 2 - 2
iOSClient/Data/NCDataSource.swift

@@ -125,7 +125,7 @@ class NCDataSource: NSObject {
 
         // Unified search
         if let providers = self.providers, !providers.isEmpty {
-            var sectionsDictionary: [String:Int] = [:]
+            let sectionsDictionary = ThreadSafeDictionary<String,Int>()
             for section in self.sectionsValue {
                 if let provider = providers.filter({ $0.name.lowercased() == section.lowercased()}).first {
                     sectionsDictionary[section] = provider.order
@@ -434,7 +434,7 @@ class NCMetadataForSection: NSObject {
     public var numDirectory: Int = 0
     public var numFile: Int = 0
     public var totalSize: Int64 = 0
-    public var metadataShare: [String: tableShare] = [:]
+    public let metadataShare  = ThreadSafeDictionary<String,tableShare>()
     public var metadataOffLine: [String] = []
     public var directories: [tableDirectory]?
 

+ 1 - 1
iOSClient/Data/NCManageDatabase+Metadata.swift

@@ -132,7 +132,7 @@ extension NCManageDatabase {
 
         var counter: Int = 0
         var isEncrypted: Bool = false
-        var listServerUrl: [String: Bool] = [:]
+        let listServerUrl = ThreadSafeDictionary<String,Bool>()
 
         var metadataFolder = tableMetadata()
         var metadataFolders: [tableMetadata] = []

+ 1 - 1
iOSClient/Main/Create cloud/NCCreateFormUploadConflict.swift

@@ -60,7 +60,7 @@ extension NCCreateFormUploadConflictDelegate {
 
     var metadatasConflictNewFiles: [String] = []
     var metadatasConflictAlreadyExistingFiles: [String] = []
-    var fileNamesPath: [String: String] = [:]
+    let fileNamesPath = ThreadSafeDictionary<String,String>()
     var blurView: UIVisualEffectView!
 
     // MARK: - View Life Cycle

+ 6 - 5
iOSClient/Networking/NCNetworking.swift

@@ -45,9 +45,9 @@ import Photos
 
     var lastReachability: Bool = true
     var networkReachability: NCCommunicationCommon.typeReachability?
-    var downloadRequest: [String: DownloadRequest] = [:]
-    var uploadRequest: [String: UploadRequest] = [:]
-    var uploadMetadataInBackground: [String: tableMetadata] = [:]
+    let downloadRequest = ThreadSafeDictionary<String,DownloadRequest>()
+    let uploadRequest = ThreadSafeDictionary<String,UploadRequest>()
+    let uploadMetadataInBackground = ThreadSafeDictionary<String,tableMetadata>()
     
     @objc public let sessionMaximumConnectionsPerHost = 5
     @objc public let sessionIdentifierBackground: String = "com.nextcloud.session.upload.background"
@@ -327,6 +327,7 @@ import Photos
         NCCommunication.shared.download(serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameLocalPath, queue: NCCommunicationCommon.shared.backgroundQueue, requestHandler: { request in
 
             self.downloadRequest[fileNameLocalPath] = request
+            self.downloadRequest.removeValue(forKey: fileNameLocalPath)
 
             NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId, status: NCGlobal.shared.metadataStatusDownloading)
             NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDownloadStartFile, userInfo: ["ocId":metadata.ocId, "serverUrl": metadata.serverUrl, "account": metadata.account])
@@ -448,7 +449,7 @@ import Photos
 
         }) { _, ocId, etag, date, size, _, _, errorCode, errorDescription in
 
-            self.uploadRequest[fileNameLocalPath] = nil
+            self.uploadRequest.removeValue(forKey: fileNameLocalPath)
             if let uploadTask = uploadTask {
                 self.uploadComplete(fileName: metadata.fileName, serverUrl: metadata.serverUrl, ocId: ocId, etag: etag, date: date, size: size, description: description, task: uploadTask, errorCode: errorCode, errorDescription: errorDescription)
             }
@@ -556,7 +557,7 @@ import Photos
                 }
             }
 
-            self.uploadMetadataInBackground[fileName + serverUrl] = nil
+            self.uploadMetadataInBackground.removeValue(forKey: fileName + serverUrl)
             self.delegate?.uploadComplete?(fileName: fileName, serverUrl: serverUrl, ocId: ocId, etag: etag, date: date, size: size, description: description, task: task, errorCode: errorCode, errorDescription: errorDescription)
         }
     }

+ 1 - 1
iOSClient/Networking/NCNetworkingChunkedUpload.swift

@@ -112,7 +112,7 @@ extension NCNetworking {
 
                 }) { _, _, _, _, _, _, _, errorCode, errorDescription in
 
-                    self.uploadRequest[fileNameLocalPath] = nil
+                    self.uploadRequest.removeValue(forKey: fileNameLocalPath)
                     uploadErrorCode = errorCode
                     uploadErrorDescription = errorDescription
                     semaphore.continue()

+ 1 - 1
iOSClient/Networking/NCNetworkingE2EE.swift

@@ -287,7 +287,7 @@ import Alamofire
 
                 }) { account, ocId, etag, date, _, _, error, errorCode, errorDescription in
 
-                    NCNetworking.shared.uploadRequest[fileNameLocalPath] = nil
+                    NCNetworking.shared.uploadRequest.removeValue(forKey: fileNameLocalPath)
                     if let metadata = NCManageDatabase.shared.getMetadataFromOcId(metadata.ocId) {
                         if error?.isExplicitlyCancelledError ?? false {
 

+ 65 - 0
iOSClient/Utility/ThreadSafeDictionary.swift

@@ -0,0 +1,65 @@
+//
+//  ThreadSafeDictionary.swift
+//
+//  Created by Shashank on 29/10/20.
+//
+
+class ThreadSafeDictionary<V: Hashable, T>: Collection {
+
+    private var dictionary: [V: T]
+    private let concurrentQueue = DispatchQueue(label: "Dictionary Barrier Queue", attributes: .concurrent)
+
+    var startIndex: Dictionary<V, T>.Index {
+        self.concurrentQueue.sync {
+            return self.dictionary.startIndex
+        }
+    }
+
+    var endIndex: Dictionary<V, T>.Index {
+        self.concurrentQueue.sync {
+            return self.dictionary.endIndex
+        }
+    }
+
+    init(dict: [V: T] = [V: T]()) {
+        self.dictionary = dict
+    }
+
+    func index(after i: Dictionary<V, T>.Index) -> Dictionary<V, T>.Index {
+        self.concurrentQueue.sync {
+            return self.dictionary.index(after: i)
+        }
+    }
+
+    subscript(key: V) -> T? {
+        get {
+            self.concurrentQueue.sync {
+                return self.dictionary[key]
+            }
+        }
+        set(newValue) {
+            self.concurrentQueue.async(flags: .barrier) {[weak self] in
+                self?.dictionary[key] = newValue
+            }
+        }
+    }
+
+    subscript(index: Dictionary<V, T>.Index) -> Dictionary<V, T>.Element {
+        self.concurrentQueue.sync {
+            return self.dictionary[index]
+        }
+    }
+
+    func removeValue(forKey key: V) {
+        self.concurrentQueue.async(flags: .barrier) {[weak self] in
+            self?.dictionary.removeValue(forKey: key)
+        }
+    }
+
+    func removeAll() {
+        self.concurrentQueue.async(flags: .barrier) {[weak self] in
+            self?.dictionary.removeAll()
+        }
+    }
+
+}