Skip to content

Commit

Permalink
Merge branch 'deploy/1.6.0' into productive
Browse files Browse the repository at this point in the history
  • Loading branch information
Jeehut committed Feb 13, 2017
2 parents 47a8055 + 4bb72b5 commit 319bae2
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 20 deletions.
4 changes: 2 additions & 2 deletions CSVImporter.podspec
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Pod::Spec.new do |s|

s.name = "CSVImporter"
s.version = "1.5.0"
s.version = "1.6.0"
s.summary = "Import CSV files line by line with ease."

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

end
17 changes: 12 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
alt="codebeat badge">
</a>
<a href="https://github.com/Flinesoft/CSVImporter/releases">
<img src="https://img.shields.io/badge/Version-1.5.0-blue.svg"
alt="Version: 1.5.0">
<img src="https://img.shields.io/badge/Version-1.6.0-blue.svg"
alt="Version: 1.6.0">
</a>
<img src="https://img.shields.io/badge/Swift-3-FFAC45.svg"
alt="Swift: 3">
Expand Down Expand Up @@ -56,7 +56,7 @@ You can of course also just include this framework manually into your project by
Simply add this line to your Cartfile:

```
github "Flinesoft/CSVImporter" ~> 1.4
github "Flinesoft/CSVImporter" ~> 1.6
```

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.
Expand All @@ -71,7 +71,7 @@ platform :ios, '8.0'
use_frameworks!

target 'MyAppTarget' do
pod 'CSVImporter', '~> 1.4'
pod 'CSVImporter', '~> 1.6'
end
```

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

### Asynchronous with Callbacks

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:
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:

``` Swift
importer.startImportingRecords { $0 }.onFail {
Expand All @@ -121,6 +121,13 @@ importer.startImportingRecords { $0 }.onFail {
}
```

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:

``` Swift
let path = "path/to/your/CSV/file"
let importer = CSVImporter<[String]>(path: path, workQosClass: .background, callbacksQosClass: .utility)
```

### Easy data mapping

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
Expand Down
49 changes: 37 additions & 12 deletions Sources/Code/CSVImporter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,20 +32,36 @@ public class CSVImporter<T> {
var finishClosure: ((_ importedRecords: [T]) -> Void)?
var failClosure: (() -> Void)?

let workQosClass: DispatchQoS.QoSClass
let callbacksQosClass: DispatchQoS.QoSClass?


// MARK: - Computed Instance Properties

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

var workDispatchQueue: DispatchQueue {
return DispatchQueue.global(qos: workQosClass)
}

var callbacksDispatchQueue: DispatchQueue {
guard let callbacksQosClass = callbacksQosClass else {
return DispatchQueue.main
}
return DispatchQueue.global(qos: callbacksQosClass)
}


// MARK: - Initializers

/// Internal initializer to prevent duplicate code.
private init(source: Source, delimiter: String) {
private init(source: Source, delimiter: String, workQosClass: DispatchQoS.QoSClass, callbacksQosClass: DispatchQoS.QoSClass?) {
self.source = source
self.delimiter = delimiter
self.workQosClass = workQosClass
self.callbacksQosClass = callbacksQosClass

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

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

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

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

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

Expand Down Expand Up @@ -271,7 +296,7 @@ public class CSVImporter<T> {

func reportFail() {
if let failClosure = self.failClosure {
DispatchQueue.main.async {
callbacksDispatchQueue.async {
failClosure()
}
}
Expand All @@ -282,7 +307,7 @@ public class CSVImporter<T> {
self.lastProgressReport = Date()

if let progressClosure = self.progressClosure {
DispatchQueue.main.async {
callbacksDispatchQueue.async {
progressClosure(importedRecords.count)
}
}
Expand All @@ -291,7 +316,7 @@ public class CSVImporter<T> {

func reportFinish(_ importedRecords: [T]) {
if let finishClosure = self.finishClosure {
DispatchQueue.main.async {
callbacksDispatchQueue.async {
finishClosure(importedRecords)
}
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/Supporting Files/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.5.0</string>
<string>1.6.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
Expand Down

0 comments on commit 319bae2

Please sign in to comment.