Skip to content

Commit

Permalink
Add objective-c interoperability (#19)
Browse files Browse the repository at this point in the history
* Add objective-c interoperability

* Add parameter to delegates method.

* Fix comment
  • Loading branch information
morzv authored and krzysztofzablocki committed Dec 20, 2018
1 parent 7b0ecf6 commit 8545c9b
Show file tree
Hide file tree
Showing 7 changed files with 247 additions and 1 deletion.
24 changes: 24 additions & 0 deletions Example/Pods/Pods.xcodeproj/project.pbxproj

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion KZFileWatchers.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

Pod::Spec.new do |s|
s.name = 'KZFileWatchers'
s.version = '1.0.5'
s.version = '1.0.6'
s.summary = 'A micro-framework for observing file changes, both local and remote. Helpful in building developer tools.'

s.description = <<-DESC
Expand Down
45 changes: 45 additions & 0 deletions ObjcWrappers/FileWatcherProtocols.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//
// FileWatcherProtocols.swift
// KZFileWatchers
//
// Created by Andrey Morozov on 18/12/2018.
//

import Foundation

/**
Protocol for essence, that responsible for file refresh processing.
*/
@objc(FileWatcherDelegate)
public protocol FileWatcherOutput: NSObjectProtocol {

/// Fires, when monitoring file is updated.
///
/// - Parameters:
/// - fileWatcher: The file watcher, which handles file refreshing.
/// - type: Status of refresh result.
/// - data: Content from file.
func refreshDidOccur(from fileWatcher: FileWatcherInput, type: RefreshResultType, data: Data?)
}

/**
Protocol for File Watchers.
*/
@objc(FileWatcherProtocol)
public protocol FileWatcherInput: NSObjectProtocol {

/// Responsible for file refresh processing.
var delegate: FileWatcherOutput? { get set }

/**
Starts observing file changes, a file watcher can only have one callback.
*/
@objc(startWithError:)
func start() throws

/**
Stops observing file changes.
*/
@objc(stopWithError:)
func stop() throws
}
67 changes: 67 additions & 0 deletions ObjcWrappers/LocalFileWatcher.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//
// LocalFileWatcher.swift
// KZFileWatchers
//
// Created by Andrey Morozov on 18/12/2018.
//

import Foundation

/**
Watcher for local files, it uses content diffing.
*/
@objc
public final class LocalFileWatcher: NSObject {

/// Original local FileWatcher, that does all work.
private let localWatcher: FileWatcher.Local

public weak var delegate: FileWatcherOutput?

/**
Initializes watcher to specified path.
- parameter path: Path of file to observe.
- note: By default it throttles to 60 FPS, some editors can generate stupid multiple saves that mess with file system e.g. Sublime with AutoSave plugin is a mess and generates different file sizes, this will limit wasted time trying to load faster than 60 FPS, and no one should even notice it's throttled.
*/
@objc
public convenience init(path: String) {
self.init(path: path, refreshInterval: 1/60, queue: DispatchQueue.main)
}

/**
Initializes watcher to specified path.
- parameter path: Path of file to observe.
- parameter refreshInterval: Refresh interval to use for updates.
- parameter queue: Queue to use for firing `onChange` callback.
*/
@objc
public init(path: String, refreshInterval: TimeInterval, queue: DispatchQueue) {
localWatcher = FileWatcher.Local(path: path, refreshInterval: refreshInterval, queue: queue)
}

@objc
public func refresh() {
localWatcher.refresh()
}
}

extension LocalFileWatcher: FileWatcherInput {

public func start() throws {
try localWatcher.start { (result) in
switch result {
case .noChanges:
self.delegate?.refreshDidOccur(from: self, type: .noChanges, data: nil)
case .updated(let data):
self.delegate?.refreshDidOccur(from: self, type: .updated, data: data)
}
}
}

public func stop() throws {
try localWatcher.stop()
}
}
24 changes: 24 additions & 0 deletions ObjcWrappers/RefreshResultType.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// RefreshResultType.swift
// KZFileWatchers
//
// Created by Andrey Morozov on 18/12/2018.
//

import Foundation

/**
Enum that contains status of refresh result.
*/
@objc(RefreshResult)
public enum RefreshResultType: Int {
/**
Watched file didn't change since last update.
*/
case noChanges

/**
Watched file did change.
*/
case updated
}
66 changes: 66 additions & 0 deletions ObjcWrappers/RemoteFileWatcher.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//
// RemoteFileWatcher.swift
// KZFileWatchers
//
// Created by Andrey Morozov on 18/12/2018.
//

import Foundation

/**
Watcher for remote files, it supports both ETag and Last-Modified HTTP header tags.
*/
@objc
public final class RemoteFileWatcher: NSObject {

/// Original remote FileWatcher, that does all work.
private let remoteWatcher: FileWatcher.Remote

public weak var delegate: FileWatcherOutput?

/**
Creates a new watcher using given URL and refreshInterval.
- parameter url: URL to observe.
- note: By default, it uses refreshInterval equal to 1.
*/
@objc
public convenience init(url: URL) {
self.init(url: url, refreshInterval: 1)
}

/**
Creates a new watcher using given URL and refreshInterval.
- parameter url: URL to observe.
- parameter refreshInterval: Minimal refresh interval between queries.
*/
@objc
public init(url: URL, refreshInterval: TimeInterval) {
remoteWatcher = FileWatcher.Remote(url: url, refreshInterval: refreshInterval)
}

@objc
public func refresh() throws {
try remoteWatcher.refresh()
}
}

extension RemoteFileWatcher: FileWatcherInput {

public func start() throws {
try remoteWatcher.start { (result) in
switch result {
case .noChanges:
self.delegate?.refreshDidOccur(from: self, type: .noChanges, data: nil)
case .updated(let data):
self.delegate?.refreshDidOccur(from: self, type: .updated, data: data)
}
}
}

public func stop() throws {
try remoteWatcher.stop()
}
}
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,26 @@ This framework provides:

- `FileWatcher.Remote` can be used to observe files on the web, it supports both `Etag` headers and `Last-Modified-Date` so you can just put file on Dropbox or real ftp server.

It also supports usage from Objective-C projects. For this, you should consider these following steps:

1. Add `$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)` into your projects **Library Search Paths** in **Build Setting** section.

2. Import swift-header by adding `@import KZFileWatchers;` into any `.m` file, where you want to use FileWatchers.

3. Use provided classes for set up file observing like this:
```objectivec
self.fileWatcher = [[LocalFileWatcher alloc] initWithPath:path];
self.fileWatcher.delegate = self;
[self.fileWatcher startWithError:nil];
```
4. Implement `FileWatcherDelegate` in your class for handling file refreshing events. For example:
```objectivec
- (void)refreshDidOccurFrom:(id<FileWatcherProtocol>)fileWatcher type:(enum RefreshResult)type data:(NSData *)data
{
self.textLabel.text = [[NSString alloc] initWithData:data encoding:kCFStringEncodingUTF8];
}
```

## Installation

KZFileWatchers is available through [CocoaPods](http://cocoapods.org) and [Swift Package Manager](http://github.com/apple/swift-package-manager).
Expand Down

0 comments on commit 8545c9b

Please sign in to comment.