159 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Swift
		
	
	
			
		
		
	
	
			159 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Swift
		
	
	
| //
 | |
| //  Utilities.swift
 | |
| //  GuruAnalytics_iOS
 | |
| //
 | |
| //  Created by mayue on 2022/11/4.
 | |
| //
 | |
| 
 | |
| import Foundation
 | |
| import RxSwift
 | |
| 
 | |
| internal extension TimeInterval {
 | |
|     
 | |
|     var int64Ms: Int64 {
 | |
|         return Int64(self * 1000)
 | |
|     }
 | |
|     
 | |
| }
 | |
| 
 | |
| internal extension Date {
 | |
|     
 | |
|     var msSince1970: Int64 {
 | |
|         timeIntervalSince1970.int64Ms
 | |
|     }
 | |
|     
 | |
|     static var absoluteTimeMs: Int64 {
 | |
|         return CACurrentMediaTime().int64Ms
 | |
|     }
 | |
|     
 | |
| }
 | |
| 
 | |
| internal extension Dictionary {
 | |
|     
 | |
|     func jsonString(prettify: Bool = false) -> String? {
 | |
|         guard JSONSerialization.isValidJSONObject(self) else { return nil }
 | |
|         let options = (prettify == true) ? JSONSerialization.WritingOptions.prettyPrinted : JSONSerialization.WritingOptions()
 | |
|         guard let jsonData = try? JSONSerialization.data(withJSONObject: self, options: options) else { return nil }
 | |
|         return String(data: jsonData, encoding: .utf8)
 | |
|     }
 | |
|     
 | |
| }
 | |
| 
 | |
| internal extension String {
 | |
|     func convertToDictionary() -> [String: Any]? {
 | |
|         if let data = data(using: .utf8) {
 | |
|             return (try? JSONSerialization.jsonObject(with: data, options: [])) as? [String: Any]
 | |
|         }
 | |
|         return nil
 | |
|     }
 | |
|     
 | |
|     mutating func deletePrefix(_ prefix: String) {
 | |
|         guard hasPrefix(prefix) else { return }
 | |
|         if #available(iOS 16.0, *) {
 | |
|             trimPrefix(prefix)
 | |
|         } else {
 | |
|             removeFirst(prefix.count)
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     mutating func trimmed(in set: CharacterSet) {
 | |
|         self = trimmingCharacters(in: set)
 | |
|     }
 | |
| }
 | |
| 
 | |
| internal extension Array {
 | |
|     func chunked(into size: Int) -> [[Element]] {
 | |
|         return stride(from: 0, to: count, by: size).map {
 | |
|             Array(self[$0 ..< Swift.min($0 + size, count)])
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| internal class SafeValue<T> {
 | |
|     
 | |
|     private var _value: T
 | |
|     
 | |
|     private let queue = DispatchQueue(label: "com.guru.analytics.safe.value.reader.writer.queue", attributes: .concurrent)
 | |
|     private let group = DispatchGroup()
 | |
|     
 | |
|     internal init(_ value: T) {
 | |
|         _value = value
 | |
|     }
 | |
|     
 | |
|     internal func setValue(_ value: T) {
 | |
|         queue.async(group: group, execute: .init(flags: .barrier, block: { [weak self] in
 | |
|             self?._value = value
 | |
|         }))
 | |
|     }
 | |
|     
 | |
|     internal func getValue(_ valueBlock: @escaping ((T) -> Void)) {
 | |
|         queue.async(group: group, execute: .init(block: { [weak self] in
 | |
|             guard let `self` = self else { return }
 | |
|             valueBlock(self._value)
 | |
|         }))
 | |
|     }
 | |
|     
 | |
|     internal var singleValue: Single<T> {
 | |
|         return Single.create { [weak self] subscriber in
 | |
|             
 | |
|             self?.getValue { value in
 | |
|                 subscriber(.success(value))
 | |
|             }
 | |
|             
 | |
|             return Disposables.create()
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| internal extension SafeValue where T == Dictionary<String, String> {
 | |
|     
 | |
|     func mergeValue(_ value: T) -> Single<Void> {
 | |
|         return .create { [weak self] subscriber in
 | |
|             guard let `self` = self else {
 | |
|                 subscriber(.failure(
 | |
|                     NSError(domain: "safevalue", code: 0, userInfo: [NSLocalizedDescriptionKey : "safevalue object is released"])
 | |
|                 ))
 | |
|                 return Disposables.create()
 | |
|             }
 | |
|             self.getValue { currentValue in
 | |
|                 let newValue = currentValue.merging(value) { _, new in new }
 | |
|                 self.setValue(newValue)
 | |
|                 subscriber(.success(()))
 | |
|             }
 | |
|             
 | |
|             return Disposables.create()
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| internal extension SafeValue where T == Array<String> {
 | |
|     
 | |
|     func appendValue(_ value: T) {
 | |
|         getValue { [weak self] v in
 | |
|             var currentValue = v
 | |
|             currentValue.append(contentsOf: value)
 | |
|             self?.setValue(currentValue)
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     func removeAll(where shouldBeRemoved: @escaping (Array<String>.Element) -> Bool) {
 | |
|         getValue { [weak self] v in
 | |
|             var currentValue = v
 | |
|             currentValue.removeAll(where: shouldBeRemoved)
 | |
|             self?.setValue(currentValue)
 | |
|         }
 | |
|     }
 | |
|     
 | |
| }
 | |
| 
 | |
| internal extension Character {
 | |
|     
 | |
|     var isAlphabetic: Bool {
 | |
|         return (self >= "a" && self <= "z") || (self >= "A" && self <= "Z")
 | |
|     }
 | |
|     
 | |
|     var isDigit: Bool {
 | |
|         return self >= "0" && self <= "9"
 | |
|     }
 | |
| }
 |