Cocoa Binding (Enabled) broken after updating to Swift4 - swift3

I am trying to update my codes from Swift3.3 to Swift4.1 but encountering KVC error.
Swift4CocoaBindings[4639:2311856] [General] [<Swift4CocoaBindings.AppDelegate 0x604000000270> addObserver:<NSKeyValueObservance 0x60c000045e50> forKeyPath:#"dbCom.dbFileExists" options:256 context:0x0] was sent to an object that is not KVC-compliant for the "dbCom" property.
What I'm doing is disabling menu items depending on properties' value in my singleton class (DBCom.swift), which is inherited from NSObject.
So I created blank projects, one with Swift3.3 and the other with Swift4.1, both with same DBCom.swift, to see if this problem reproduced. And found it reproduced.
In AppDelegate.swift, I included the singleton as follows.
let dbCom = DBCom.shared
Then,
Bindings of menu items are made to Enabled with self.dbCom.dbFileExists in the InterfaceBuilder.
This was working with Swift3.3 but once it is switched to Swift4.1, the app got the error at the startup.
dbFileExists' implementation in the DBCom.swift is as follows. Just checking the file is existed or not.
var dbFileExists: Bool {
get {
if let dbfp = dbFullPath {
if FileManager.default.fileExists(atPath: dbfp.path) {
return true
} else {
return false
}
} else {
return false
}
}
}
If anyone can suggest the solution to this problem, it'd be very much appreciated.
Regards,

Cocoa Binding depends on the dynamic features of Objective-C, such as KVC/KVO.
So, all the properties included in the Cocoa Binding reference needs to be Objective-C compatible.
Try adding #obc explicitly:
#objc let dbCom = DBCom.shared
and:
#objc dynamic var dbFileExists: Bool {
get {
if let dbfp = dbFullPath {
if FileManager.default.fileExists(atPath: dbfp.path) {
return true
} else {
return false
}
} else {
return false
}
}
}
Since Swift 4, automatic annotation of #objc happens in very limited conditions and you may need to explicitly annotate each properties or methods.

Related

set variable in SFSpeechRecognizer.requestAuthorization

I'm trying to check whether the user has accepted the speech recognition or not. But for some reason the status is .authorized but the according variable won't be changed. What am I missing here? It's not about to display the message to the user, but just for some error handling use cases.
class ViewModel: ObservableObject {
#Published var requestAuth: Bool = false
init() {
SFSpeechRecognizer.requestAuthorization { (authState) in
DispatchQueue.main.async {
if authState == .authorized {
print("is authorized") // <---- is printed!
self.requestAuth = true
} else {
self.requestAuth = false
}
}
}
if self.requestAuth { // <--- will not be executed - why?
// do something...
}
}
The code inside the requestAuthorization braces ({}) is what's called a callback function. Often times, callback functions don't get executed immediately. In fact, the documentation for that function states:
This method executes asynchronously, returning shortly after you call it
That means that the code that follows will not happen immediately. Similarly, you're using DispatchQueue.main.async inside that callback function, which also acts the same way. The code in the braces will not be called right away, so you can't base anything later in your structure on it having happened.
The solution to this is to call any functions that you need that are based on the authorization status from inside those closures -- like where you have print("is authorized"):
init() {
SFSpeechRecognizer.requestAuthorization { (authState) in
DispatchQueue.main.async {
if authState == .authorized {
print("is authorized") // <---- is printed!
self.requestAuth = true
// do other things based on authorization status
} else {
self.requestAuth = false
}
}
}
//can't rely on having an updated value for self.requestAuth here
}

How can I change the filename in a SwiftUI Document-based app?

I've been using the new template for a document-based SwiftUI app. While you get a lot of file-management "for free" in the new template, as it stands in the iOS version users have to back out of the file to the file browser to change the filename. I want to create an opportunity for the user to rename the file while it is open.
Here's a sample project focused on the issue: https://github.com/stevepvc/DocumentRenamer
In the code, I've added to the template code a simple UI with a textfield for the user to enter a new name. When the user hits the "rename" button, the app checks to see if the URL with that name component is available, appending a suffix if necessary to create a target url.
func getTargetURL() -> URL {
let baseURL = self.fileurl.deletingLastPathComponent()
print("filename: \(self.filename)")
print("fileURL: \(self.fileurl)")
print("BaseURL: \(baseURL)")
var target = URL(fileURLWithPath: baseURL.path + "/\(filename).exampletext")
var nameSuffix = 1
while (target as NSURL).checkPromisedItemIsReachableAndReturnError(nil) {
target = URL(fileURLWithPath: baseURL.path + "/\(filename)-\(nameSuffix).sermon")
print("Checking: \(target)")
nameSuffix += 1
}
print("Available Target: \(target)")
return target
}
It then attempts to rename the file, and this is when I am stuck. I have tried several methods, most recently the following:
func changeFilename(){
let target = getTargetURL()
var rv = URLResourceValues()
let newFileName = target.deletingPathExtension().lastPathComponent
rv.name = newFileName
do {
if fileurl.startAccessingSecurityScopedResource(){
try fileurl.setResourceValues(rv)
fileurl.stopAccessingSecurityScopedResource()
}
} catch {
print("Error:\(error)")
}
}
But I keep getting the following error:
Domain=NSCocoaErrorDomain Code=513 "You don’t have permission to save the file “Untitled” in the folder “DocumentRenamer”."
I have also tried this without the startAccessingSecurityScopedResource() check, and alternatively have tried creating a helper class as follows:
class FileMover: NSObject {
func moveFile(originalURL: URL, updatedURL:URL) -> Bool {
let coordinator = NSFileCoordinator(filePresenter: nil)
var writingError: NSError? = nil
var success : Bool = true
print("moving file")
coordinator.coordinate(writingItemAt: originalURL, options: NSFileCoordinator.WritingOptions.forMoving, error: &writingError, byAccessor: { (coordinatedURL) in
do {
try FileManager.default.moveItem(at: coordinatedURL, to: updatedURL)
success = true
print("file moved")
} catch {
print(error)
success = false
}
})
return success
}
}
But using this method locks up the app entirely. It's possible that there is something about iCloud permissions going on there, but I think I've have those set up appropriately.
It appears to work fine in the simulator, but not when run on a device.
What is the correct method for renaming a file in the app's container?

Can't create object with existing primary key value

I'm in my first steps of using Realm Mobile Database, and I would like to know if there is a way of handling the error caused by trying to add an object with the same primaryKey as one previously inserted, causing the following Can't create object with existing primary key value.
Here are my snippets:
class CategoryRLM: Object {
dynamic var name: String = ""
dynamic var desc: String = ""
override static func primaryKey() -> String? {
return "name"
}
}
static func addCategory(category: CategoryRLM) -> Bool {
let realm = try! Realm()
do {
try realm.write {
realm.add(category)
}
return true
}
catch let error {
print(error)
return false
}
}
Using the previous function:
if !CategoryRLM.addCategory(category: newCategory) {
// There was an error while adding the object
}
The thing is that the error doesn't get handled by the do-catch.
Attempting to add an object with a primary key that already exists is classed as programmer error (that is, misuse of the API), and as such it is not possible to handle this error at runtime.
In your case you should instead check if an object exists with that primary key prior to attempting to add the category to the Realm:
static func addCategory(category: CategoryRLM) -> Bool {
let realm = try! Realm()
if let existingCategory = realm.object(ofType: CategoryRLM.self, forPrimaryKey: category.name) {
return false
}
try realm.write! {
realm.add(category)
}
return true
}

Problems with migration to Swift3, compilation error with URLSession.GET

I'm trying to migrate from Swift2 to Swift3 and I'm having an issue with URLSession.GET
I went through the migration tool provided by XCode, and changed my "NSURLSession" calls into "URLSession" but I keep having this error message:
"Use of Instance member 'GET' on type 'URLSession'; did you mean to use a value of type 'URLSession' instead?"
Here is my code:
open static func getData() -> Promise<[Station]> {
return URLSession.GET("http://api.xxx.gov/api/").asDataAndResponse().then { (data: NSData, _) -> [Station] in
var stations = [Station]()
// rest of the code to retrieve the data
...
...
return stations
}
}
Update:
After some digging a found a solution, see answer below for more details and helpful links
After some more digging I found a solution :
First I have to init URLSession with a configuration:
let URLSession1 = URLSession(configuration: .default)
Then I can call the 'GET' method and I had to use (data,_ ) instead of (data:NSData,_ ):
open static func getData() -> Promise<[Station]> {
return URLSession1.GET("http://api.xxx.com/api/").asDataAndResponse().then { (data, _) -> [Station] in
var stations = [Station]()
// rest of the code to retrieve the data
...
...
return stations
}
}
Some helpful StackOverflow links that helped me find the solution:
NSURLSession dataTaskForRequest:completion: unrecognized selector sent to instance

What is the Swift equivalent to Objective-C's "#synchronized"?

I've searched the Swift book, but can't find the Swift version of #synchronized. How do I do mutual exclusion in Swift?
You can use GCD. It is a little more verbose than #synchronized, but works as a replacement:
let serialQueue = DispatchQueue(label: "com.test.mySerialQueue")
serialQueue.sync {
// code
}
I was looking for this myself and came to the conclusion there's no native construct inside of swift for this yet.
I did make up this small helper function based on some of the code I've seen from Matt Bridges and others.
func synced(_ lock: Any, closure: () -> ()) {
objc_sync_enter(lock)
closure()
objc_sync_exit(lock)
}
Usage is pretty straight forward
synced(self) {
println("This is a synchronized closure")
}
There is one problem I've found with this. Passing in an array as the lock argument seems to cause a very obtuse compiler error at this point. Otherwise though it seems to work as desired.
Bitcast requires both operands to be pointer or neither
%26 = bitcast i64 %25 to %objc_object*, !dbg !378
LLVM ERROR: Broken function found, compilation aborted!
I like and use many of the answers here, so I'd choose whichever works best for you. That said, the method I prefer when I need something like objective-c's #synchronized uses the defer statement introduced in swift 2.
{
objc_sync_enter(lock)
defer { objc_sync_exit(lock) }
//
// code of critical section goes here
//
} // <-- lock released when this block is exited
The nice thing about this method, is that your critical section can exit the containing block in any fashion desired (e.g., return, break, continue, throw), and "the statements within the defer statement are executed no matter how program control is transferred."1
You can sandwich statements between objc_sync_enter(obj: AnyObject?) and objc_sync_exit(obj: AnyObject?). The #synchronized keyword is using those methods under the covers. i.e.
objc_sync_enter(self)
... synchronized code ...
objc_sync_exit(self)
Analog of the #synchronized directive from Objective-C can have an arbitrary return type and nice rethrows behaviour in Swift.
// Swift 3
func synchronized<T>(_ lock: AnyObject, _ body: () throws -> T) rethrows -> T {
objc_sync_enter(lock)
defer { objc_sync_exit(lock) }
return try body()
}
The use of the defer statement lets directly return a value without introducing a temporary variable.
In Swift 2 add the #noescape attribute to the closure to allow more optimisations:
// Swift 2
func synchronized<T>(lock: AnyObject, #noescape _ body: () throws -> T) rethrows -> T {
objc_sync_enter(lock)
defer { objc_sync_exit(lock) }
return try body()
}
Based on the answers from GNewc [1] (where I like arbitrary return type) and Tod Cunningham [2] (where I like defer).
SWIFT 4
In Swift 4 you can use GCDs dispatch queues to lock resources.
class MyObject {
private var internalState: Int = 0
private let internalQueue: DispatchQueue = DispatchQueue(label:"LockingQueue") // Serial by default
var state: Int {
get {
return internalQueue.sync { internalState }
}
set (newState) {
internalQueue.sync { internalState = newState }
}
}
}
In modern Swift 5, with return capability:
/**
Makes sure no other thread reenters the closure before the one running has not returned
*/
#discardableResult
public func synchronized<T>(_ lock: AnyObject, closure:() -> T) -> T {
objc_sync_enter(lock)
defer { objc_sync_exit(lock) }
return closure()
}
Use it like this, to take advantage the return value capability:
let returnedValue = synchronized(self) {
// Your code here
return yourCode()
}
Or like that otherwise:
synchronized(self) {
// Your code here
yourCode()
}
To add return functionalty, you could do this:
func synchronize<T>(lockObj: AnyObject!, closure: ()->T) -> T
{
objc_sync_enter(lockObj)
var retVal: T = closure()
objc_sync_exit(lockObj)
return retVal
}
Subsequently, you can call it using:
func importantMethod(...) -> Bool {
return synchronize(self) {
if(feelLikeReturningTrue) { return true }
// do other things
if(feelLikeReturningTrueNow) { return true }
// more things
return whatIFeelLike ? true : false
}
}
Using Bryan McLemore answer, I extended it to support objects that throw in a safe manor with the Swift 2.0 defer ability.
func synchronized( lock:AnyObject, block:() throws -> Void ) rethrows
{
objc_sync_enter(lock)
defer {
objc_sync_exit(lock)
}
try block()
}
In the "Understanding Crashes and Crash Logs" session 414 of the 2018 WWDC they show the following way using DispatchQueues with sync.
In swift 4 should be something like the following:
class ImageCache {
private let queue = DispatchQueue(label: "sync queue")
private var storage: [String: UIImage] = [:]
public subscript(key: String) -> UIImage? {
get {
return queue.sync {
return storage[key]
}
}
set {
queue.sync {
storage[key] = newValue
}
}
}
}
Anyway you can also make reads faster using concurrent queues with barriers. Sync and async reads are performed concurrently and writing a new value waits for previous operations to finish.
class ImageCache {
private let queue = DispatchQueue(label: "with barriers", attributes: .concurrent)
private var storage: [String: UIImage] = [:]
func get(_ key: String) -> UIImage? {
return queue.sync { [weak self] in
guard let self = self else { return nil }
return self.storage[key]
}
}
func set(_ image: UIImage, for key: String) {
queue.async(flags: .barrier) { [weak self] in
guard let self = self else { return }
self.storage[key] = image
}
}
}
Try: NSRecursiveLock
A lock that may be acquired multiple times by the same thread without
causing a deadlock.
let lock = NSRecursiveLock()
func f() {
lock.lock()
//Your Code
lock.unlock()
}
func f2() {
lock.lock()
defer {
lock.unlock()
}
//Your Code
}
The Objective-C synchronization feature supports recursive and
reentrant code. A thread can use a single semaphore several times in a
recursive manner; other threads are blocked from using it until the
thread releases all the locks obtained with it; that is, every
#synchronized() block is exited normally or through an exception.
Source
Swift 3
This code has the re-entry ability and can work with Asynchronous function calls. In this code, after someAsyncFunc() is called, another function closure on the serial queue will process but be blocked by semaphore.wait() until signal() is called. internalQueue.sync shouldn't be used as it will block the main thread if I'm not mistaken.
let internalQueue = DispatchQueue(label: "serialQueue")
let semaphore = DispatchSemaphore(value: 1)
internalQueue.async {
self.semaphore.wait()
// Critical section
someAsyncFunc() {
// Do some work here
self.semaphore.signal()
}
}
objc_sync_enter/objc_sync_exit isn't a good idea without error handling.
Use NSLock in Swift4:
let lock = NSLock()
lock.lock()
if isRunning == true {
print("Service IS running ==> please wait")
return
} else {
print("Service not running")
}
isRunning = true
lock.unlock()
Warning
The NSLock class uses POSIX threads to implement its locking behavior. When sending an unlock message to an NSLock object, you must be sure that message is sent from the same thread that sent the initial lock message. Unlocking a lock from a different thread can result in undefined behavior.
With Swift's property wrappers, this is what I'm using now:
#propertyWrapper public struct NCCSerialized<Wrapped> {
private let queue = DispatchQueue(label: "com.nuclearcyborg.NCCSerialized_\(UUID().uuidString)")
private var _wrappedValue: Wrapped
public var wrappedValue: Wrapped {
get { queue.sync { _wrappedValue } }
set { queue.sync { _wrappedValue = newValue } }
}
public init(wrappedValue: Wrapped) {
self._wrappedValue = wrappedValue
}
}
Then you can just do:
#NCCSerialized var foo: Int = 10
or
#NCCSerialized var myData: [SomeStruct] = []
Then access the variable as you normally would.
With the advent of Swift concurrency, we would use actors.
You can use tasks to break up your program into isolated, concurrent
pieces. Tasks are isolated from each other, which is what makes it
safe for them to run at the same time, but sometimes you need to share
some information between tasks. Actors let you safely share
information between concurrent code.
Like classes, actors are reference types, so the comparison of value
types and reference types in Classes Are Reference Types applies to
actors as well as classes. Unlike classes, actors allow only one task
to access their mutable state at a time, which makes it safe for code
in multiple tasks to interact with the same instance of an actor. For
example, here’s an actor that records temperatures:
actor TemperatureLogger {
let label: String
var measurements: [Int]
private(set) var max: Int
init(label: String, measurement: Int) {
self.label = label
self.measurements = [measurement]
self.max = measurement
}
}
You introduce an actor with the actor keyword, followed by its definition in a pair of braces. The TemperatureLogger actor has properties that other code outside the actor can access, and restricts the max property so only code inside the actor can update the maximum value.
For more information, see WWDC video Protect mutable state with Swift actors.
For the sake of completeness, the historical alternatives include:
GCD serial queue: This is a simple pre-concurrency approach to ensure that one one thread at a time will interact with the shared resource.
Reader-writer pattern with concurrent GCD queue: In reader-writer patterns, one uses a concurrent dispatch queue to perform synchronous, but concurrent, reads (but concurrent with other reads only, not writes) but perform writes asynchronously with a barrier (forcing writes to not be performed concurrently with anything else on that queue). This can offer a performance improvement over a simple GCD serial solution, but in practice, the advantage is modest and comes at the cost of additional complexity (e.g., you have to be careful about thread-explosion scenarios). IMHO, I tend to avoid this pattern, either sticking with the simplicity of the serial queue pattern, or, when the performance difference is critical, using a completely different pattern.
Locks: In my Swift tests, lock-based synchronization tends to be substantially faster than either of the GCD approaches. Locks come in a few flavors:
NSLock is a nice, relatively efficient lock mechanism.
In those cases where performance is of paramount concern, I use “unfair locks”, but you must be careful when using them from Swift (see https://stackoverflow.com/a/66525671/1271826).
For the sake of completeness, there is also the recursive lock. IMHO, I would favor simple NSLock over NSRecursiveLock. Recursive locks are subject to abuse and often indicate code smell.
You might see references to “spin locks”. Many years ago, they used to be employed where performance was of paramount concern, but they are now deprecated in favor of unfair locks.
Technically, one can use semaphores for synchronization, but it tends to be the slowest of all the alternatives.
I outline a few my benchmark results here.
In short, nowadays I use actors for contemporary codebases, GCD serial queues for simple scenarios non-async-await code, and locks in those rare cases where performance is essential.
And, needless to say, we often try to reduce the number of synchronizations altogether. If we can, we often use value types, where each thread gets its own copy. And where synchronization cannot be avoided, we try to minimize the number of those synchronizations where possible.
Figure I'll post my Swift 5 implementation, built off of the prior answers. Thanks guys! I found it helpful to have one that returns a value too, so I have two methods.
Here is a simple class to make first:
import Foundation
class Sync {
public class func synced(_ lock: Any, closure: () -> ()) {
objc_sync_enter(lock)
defer { objc_sync_exit(lock) }
closure()
}
public class func syncedReturn(_ lock: Any, closure: () -> (Any?)) -> Any? {
objc_sync_enter(lock)
defer { objc_sync_exit(lock) }
return closure()
}
}
Then use it like so if needing a return value:
return Sync.syncedReturn(self, closure: {
// some code here
return "hello world"
})
Or:
Sync.synced(self, closure: {
// do some work synchronously
})
You can create propertyWrapper Synchronised
Here example with NSLock underhood. You can use for synchronisation whatever you want GCD, posix_locks e.t.c
#propertyWrapper public struct Synchronised<T> {
private let lock = NSLock()
private var _wrappedValue: T
public var wrappedValue: T {
get {
lock.lock()
defer {
lock.unlock()
}
return _wrappedValue
}
set {
lock.lock()
defer {
lock.unlock()
}
_wrappedValue = newValue
}
}
public init(wrappedValue: T) {
self._wrappedValue = wrappedValue
}
}
#Synchronised var example: String = "testing"
based on #drewster answer
In conclusion, Here give more common way that include return value or void, and throw
import Foundation
extension NSObject {
func synchronized<T>(lockObj: AnyObject!, closure: () throws -> T) rethrows -> T
{
objc_sync_enter(lockObj)
defer {
objc_sync_exit(lockObj)
}
return try closure()
}
}
Details
Xcode 8.3.1, Swift 3.1
Task
Read write value from different threads (async).
Code
class AsyncObject<T>:CustomStringConvertible {
private var _value: T
public private(set) var dispatchQueueName: String
let dispatchQueue: DispatchQueue
init (value: T, dispatchQueueName: String) {
_value = value
self.dispatchQueueName = dispatchQueueName
dispatchQueue = DispatchQueue(label: dispatchQueueName)
}
func setValue(with closure: #escaping (_ currentValue: T)->(T) ) {
dispatchQueue.sync { [weak self] in
if let _self = self {
_self._value = closure(_self._value)
}
}
}
func getValue(with closure: #escaping (_ currentValue: T)->() ) {
dispatchQueue.sync { [weak self] in
if let _self = self {
closure(_self._value)
}
}
}
var value: T {
get {
return dispatchQueue.sync { _value }
}
set (newValue) {
dispatchQueue.sync { _value = newValue }
}
}
var description: String {
return "\(_value)"
}
}
Usage
print("Single read/write action")
// Use it when when you need to make single action
let obj = AsyncObject<Int>(value: 0, dispatchQueueName: "Dispatch0")
obj.value = 100
let x = obj.value
print(x)
print("Write action in block")
// Use it when when you need to make many action
obj.setValue{ (current) -> (Int) in
let newValue = current*2
print("previous: \(current), new: \(newValue)")
return newValue
}
Full Sample
extension DispatchGroup
extension DispatchGroup {
class func loop(repeatNumber: Int, action: #escaping (_ index: Int)->(), completion: #escaping ()->()) {
let group = DispatchGroup()
for index in 0...repeatNumber {
group.enter()
DispatchQueue.global(qos: .utility).async {
action(index)
group.leave()
}
}
group.notify(queue: DispatchQueue.global(qos: .userInitiated)) {
completion()
}
}
}
class ViewController
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//sample1()
sample2()
}
func sample1() {
print("=================================================\nsample with variable")
let obj = AsyncObject<Int>(value: 0, dispatchQueueName: "Dispatch1")
DispatchGroup.loop(repeatNumber: 5, action: { index in
obj.value = index
}) {
print("\(obj.value)")
}
}
func sample2() {
print("\n=================================================\nsample with array")
let arr = AsyncObject<[Int]>(value: [], dispatchQueueName: "Dispatch2")
DispatchGroup.loop(repeatNumber: 15, action: { index in
arr.setValue{ (current) -> ([Int]) in
var array = current
array.append(index*index)
print("index: \(index), value \(array[array.count-1])")
return array
}
}) {
print("\(arr.value)")
}
}
}
What about
final class SpinLock {
private let lock = NSRecursiveLock()
func sync<T>(action: () -> T) -> T {
lock.lock()
defer { lock.unlock() }
return action()
}
}
Why make it difficult and hassle with locks?
Use Dispatch Barriers.
A dispatch barrier creates a synchronization point within a concurrent queue.
While it’s running, no other block on the queue is allowed to run, even if it’s concurrent and other cores are available.
If that sounds like an exclusive (write) lock, it is.
Non-barrier blocks can be thought of as shared (read) locks.
As long as all access to the resource is performed through the queue, barriers provide very cheap synchronization.
dispatch_barrier_async is the better way, while not blocking current thread.
dispatch_barrier_async(accessQueue, {
dictionary[object.ID] = object
})
Based on ɲeuroburɳ, test an sub-class case
class Foo: NSObject {
func test() {
print("1")
objc_sync_enter(self)
defer {
objc_sync_exit(self)
print("3")
}
print("2")
}
}
class Foo2: Foo {
override func test() {
super.test()
print("11")
objc_sync_enter(self)
defer {
print("33")
objc_sync_exit(self)
}
print("22")
}
}
let test = Foo2()
test.test()
Output:
1
2
3
11
22
33
Another method is to create a superclass and then inherit it. This way you can use GCD more directly
class Lockable {
let lockableQ:dispatch_queue_t
init() {
lockableQ = dispatch_queue_create("com.blah.blah.\(self.dynamicType)", DISPATCH_QUEUE_SERIAL)
}
func lock(closure: () -> ()) {
dispatch_sync(lockableQ, closure)
}
}
class Foo: Lockable {
func boo() {
lock {
....... do something
}
}