Skip to content

Commit 319bae2

Browse files
committed
Merge branch 'deploy/1.6.0' into productive
2 parents 47a8055 + 4bb72b5 commit 319bae2

File tree

4 files changed

+52
-20
lines changed

4 files changed

+52
-20
lines changed

CSVImporter.podspec

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Pod::Spec.new do |s|
22

33
s.name = "CSVImporter"
4-
s.version = "1.5.0"
4+
s.version = "1.6.0"
55
s.summary = "Import CSV files line by line with ease."
66

77
s.description = <<-DESC
@@ -24,6 +24,6 @@ Pod::Spec.new do |s|
2424
s.source = { :git => "https://github.com/Flinesoft/CSVImporter.git", :tag => "#{s.version}" }
2525
s.source_files = "Sources", "Sources/**/*.swift"
2626
s.framework = "Foundation"
27-
s.dependency "HandySwift", "~> 1.3"
27+
s.dependency "HandySwift", "~> 2.0"
2828

2929
end

README.md

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
alt="codebeat badge">
1313
</a>
1414
<a href="https://github.com/Flinesoft/CSVImporter/releases">
15-
<img src="https://img.shields.io/badge/Version-1.5.0-blue.svg"
16-
alt="Version: 1.5.0">
15+
<img src="https://img.shields.io/badge/Version-1.6.0-blue.svg"
16+
alt="Version: 1.6.0">
1717
</a>
1818
<img src="https://img.shields.io/badge/Swift-3-FFAC45.svg"
1919
alt="Swift: 3">
@@ -56,7 +56,7 @@ You can of course also just include this framework manually into your project by
5656
Simply add this line to your Cartfile:
5757

5858
```
59-
github "Flinesoft/CSVImporter" ~> 1.4
59+
github "Flinesoft/CSVImporter" ~> 1.6
6060
```
6161

6262
And run `carthage update`. Then drag & drop the HandySwift.framework in the Carthage/build folder to your project. Also do the same with the dependent framework `HandySwift`. Now you can `import CSVImporter` in each class you want to use its features. Refer to the [Carthage README](https://github.com/Carthage/Carthage#adding-frameworks-to-an-application) for detailed / updated instructions.
@@ -71,7 +71,7 @@ platform :ios, '8.0'
7171
use_frameworks!
7272

7373
target 'MyAppTarget' do
74-
pod 'CSVImporter', '~> 1.4'
74+
pod 'CSVImporter', '~> 1.6'
7575
end
7676
```
7777

@@ -103,7 +103,7 @@ Note that you can specify an **alternative delimiter** when creating a `CSVImpor
103103

104104
### Asynchronous with Callbacks
105105

106-
CSVImporter works completely asynchronous and therefore doesn't block the main thread. As you can see the `onFinish` method is called once it finishes for using the results. There is also `onFail` for failure cases (for example when the given path doesn't contain a CSV file), `onProgress` which is regularly called and provides the number of lines already processed (e.g. for progress indicators). You can chain them as follows:
106+
CSVImporter works asynchronously by default and therefore doesn't block the main thread. As you can see the `onFinish` method is called once it finishes for using the results. There is also `onFail` for failure cases (for example when the given path doesn't contain a CSV file), `onProgress` which is regularly called and provides the number of lines already processed (e.g. for progress indicators). You can chain them as follows:
107107

108108
``` Swift
109109
importer.startImportingRecords { $0 }.onFail {
@@ -121,6 +121,13 @@ importer.startImportingRecords { $0 }.onFail {
121121
}
122122
```
123123

124+
By default the real importing work is done in the `.utility` global background queue and callbacks are called on the `main` queue. This way the hard work is done asynchronously but the callbacks allow you to update your UI. If you need a different behavior, you can customize the queues when creating a CSVImporter object like so:
125+
126+
``` Swift
127+
let path = "path/to/your/CSV/file"
128+
let importer = CSVImporter<[String]>(path: path, workQosClass: .background, callbacksQosClass: .utility)
129+
```
130+
124131
### Easy data mapping
125132

126133
As stated above the default type is a `[String]` but you can provide whatever type you like. For example, let's say you have a class like this

Sources/Code/CSVImporter.swift

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,20 +32,36 @@ public class CSVImporter<T> {
3232
var finishClosure: ((_ importedRecords: [T]) -> Void)?
3333
var failClosure: (() -> Void)?
3434

35+
let workQosClass: DispatchQoS.QoSClass
36+
let callbacksQosClass: DispatchQoS.QoSClass?
37+
3538

3639
// MARK: - Computed Instance Properties
3740

3841
var shouldReportProgress: Bool {
3942
return self.progressClosure != nil && (self.lastProgressReport == nil || Date().timeIntervalSince(self.lastProgressReport!) > 0.1)
4043
}
4144

45+
var workDispatchQueue: DispatchQueue {
46+
return DispatchQueue.global(qos: workQosClass)
47+
}
48+
49+
var callbacksDispatchQueue: DispatchQueue {
50+
guard let callbacksQosClass = callbacksQosClass else {
51+
return DispatchQueue.main
52+
}
53+
return DispatchQueue.global(qos: callbacksQosClass)
54+
}
55+
4256

4357
// MARK: - Initializers
4458

4559
/// Internal initializer to prevent duplicate code.
46-
private init(source: Source, delimiter: String) {
60+
private init(source: Source, delimiter: String, workQosClass: DispatchQoS.QoSClass, callbacksQosClass: DispatchQoS.QoSClass?) {
4761
self.source = source
4862
self.delimiter = delimiter
63+
self.workQosClass = workQosClass
64+
self.callbacksQosClass = callbacksQosClass
4965

5066
delimiterQuoteDelimiter = "\(delimiter)\"\"\(delimiter)"
5167
delimiterDelimiter = delimiter+delimiter
@@ -61,10 +77,13 @@ public class CSVImporter<T> {
6177
/// - delimiter: The delimiter used within the CSV file for separating fields. Defaults to ",".
6278
/// - lineEnding: The lineEnding used in the file. If not specified will be determined automatically.
6379
/// - encoding: The encoding the file is read with. Defaults to `.utf8`.
64-
public convenience init(path: String, delimiter: String = ",", lineEnding: LineEnding = .unknown, encoding: String.Encoding = .utf8) {
80+
/// - workQosClass: The QOS class of the background queue to run the heavy work in. Defaults to `.utility`.
81+
/// - callbacksQosClass: The QOS class of the background queue to run the callbacks in or `nil` for the main queue. Defaults to `nil`.
82+
public convenience init(path: String, delimiter: String = ",", lineEnding: LineEnding = .unknown, encoding: String.Encoding = .utf8,
83+
workQosClass: DispatchQoS.QoSClass = .utility, callbacksQosClass: DispatchQoS.QoSClass? = nil) {
6584
let textFile = TextFile(path: path, encoding: encoding)
6685
let fileSource = FileSource(textFile: textFile, encoding: encoding, lineEnding: lineEnding)
67-
self.init(source: fileSource, delimiter: delimiter)
86+
self.init(source: fileSource, delimiter: delimiter, workQosClass: workQosClass, callbacksQosClass: callbacksQosClass)
6887
}
6988

7089
/// Creates a `CSVImporter` object with required configuration options.
@@ -74,9 +93,12 @@ public class CSVImporter<T> {
7493
/// - delimiter: The delimiter used within the CSV file for separating fields. Defaults to ",".
7594
/// - lineEnding: The lineEnding used in the file. If not specified will be determined automatically.
7695
/// - encoding: The encoding the file is read with. Defaults to `.utf8`.
77-
public convenience init?(url: URL, delimiter: String = ",", lineEnding: LineEnding = .unknown, encoding: String.Encoding = .utf8) {
96+
/// - workQosClass: The QOS class of the background queue to run the heavy work in. Defaults to `.utility`.
97+
/// - callbacksQosClass: The QOS class of the background queue to run the callbacks in or `nil` for the main queue. Defaults to `nil`.
98+
public convenience init?(url: URL, delimiter: String = ",", lineEnding: LineEnding = .unknown, encoding: String.Encoding = .utf8,
99+
workQosClass: DispatchQoS.QoSClass = .utility, callbacksQosClass: DispatchQoS.QoSClass? = nil) {
78100
guard url.isFileURL else { return nil }
79-
self.init(path: url.path, delimiter: delimiter, lineEnding: lineEnding, encoding: encoding)
101+
self.init(path: url.path, delimiter: delimiter, lineEnding: lineEnding, encoding: encoding, workQosClass: workQosClass, callbacksQosClass: callbacksQosClass)
80102
}
81103

82104
/// Creates a `CSVImporter` object with required configuration options.
@@ -88,9 +110,12 @@ public class CSVImporter<T> {
88110
/// - contentString: The string which contains the content of a CSV file.
89111
/// - delimiter: The delimiter used within the CSV file for separating fields. Defaults to ",".
90112
/// - lineEnding: The lineEnding used in the file. If not specified will be determined automatically.
91-
public convenience init(contentString: String, delimiter: String = ",", lineEnding: LineEnding = .unknown) {
113+
/// - workQosClass: The QOS class of the background queue to run the heavy work in. Defaults to `.utility`.
114+
/// - callbacksQosClass: The QOS class of the background queue to run the callbacks in or `nil` for the main queue. Defaults to `nil`.
115+
public convenience init(contentString: String, delimiter: String = ",", lineEnding: LineEnding = .unknown,
116+
workQosClass: DispatchQoS.QoSClass = .utility, callbacksQosClass: DispatchQoS.QoSClass? = nil) {
92117
let stringSource = StringSource(contentString: contentString, lineEnding: lineEnding)
93-
self.init(source: stringSource, delimiter: delimiter)
118+
self.init(source: stringSource, delimiter: delimiter, workQosClass: workQosClass, callbacksQosClass: callbacksQosClass)
94119
}
95120

96121
// MARK: - Instance Methods
@@ -101,7 +126,7 @@ public class CSVImporter<T> {
101126
/// - mapper: A closure to map the data received in a line to your data structure.
102127
/// - Returns: `self` to enable consecutive method calls (e.g. `importer.startImportingRecords {...}.onProgress {...}`).
103128
public func startImportingRecords(mapper closure: @escaping (_ recordValues: [String]) -> T) -> Self {
104-
DispatchQueue.global(qos: DispatchQoS.QoSClass.userInitiated).async {
129+
workDispatchQueue.async {
105130
var importedRecords: [T] = []
106131

107132
let importedLinesWithSuccess = self.importLines { valuesInLine in
@@ -129,7 +154,7 @@ public class CSVImporter<T> {
129154
/// - Returns: `self` to enable consecutive method calls (e.g. `importer.startImportingRecords {...}.onProgress {...}`).
130155
public func startImportingRecords(structure structureClosure: @escaping (_ headerValues: [String]) -> Void,
131156
recordMapper closure: @escaping (_ recordValues: [String: String]) -> T) -> Self {
132-
DispatchQueue.global(qos: DispatchQoS.QoSClass.userInitiated).async {
157+
workDispatchQueue.async {
133158
var recordStructure: [String]?
134159
var importedRecords: [T] = []
135160

@@ -271,7 +296,7 @@ public class CSVImporter<T> {
271296

272297
func reportFail() {
273298
if let failClosure = self.failClosure {
274-
DispatchQueue.main.async {
299+
callbacksDispatchQueue.async {
275300
failClosure()
276301
}
277302
}
@@ -282,7 +307,7 @@ public class CSVImporter<T> {
282307
self.lastProgressReport = Date()
283308

284309
if let progressClosure = self.progressClosure {
285-
DispatchQueue.main.async {
310+
callbacksDispatchQueue.async {
286311
progressClosure(importedRecords.count)
287312
}
288313
}
@@ -291,7 +316,7 @@ public class CSVImporter<T> {
291316

292317
func reportFinish(_ importedRecords: [T]) {
293318
if let finishClosure = self.finishClosure {
294-
DispatchQueue.main.async {
319+
callbacksDispatchQueue.async {
295320
finishClosure(importedRecords)
296321
}
297322
}

Sources/Supporting Files/Info.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
<key>CFBundlePackageType</key>
1616
<string>FMWK</string>
1717
<key>CFBundleShortVersionString</key>
18-
<string>1.5.0</string>
18+
<string>1.6.0</string>
1919
<key>CFBundleSignature</key>
2020
<string>????</string>
2121
<key>CFBundleVersion</key>

0 commit comments

Comments
 (0)