Ambiguous use of 'gl_id' - swift4

I am getting this error in below code.
In Xcode10. How to fix it
Reference to var 'gl_id' of 'Taskdetail' depends on '#objc' inference deprecated in Swift 4
if let Tasks = user?.tasks {
for task in tasks {
print("To fetch task ((task as AnyObject).gl_id)")
if let taskId = (task as AnyObject).gl_id {
if let id = taskId {
fetchtaskValues(id, limit: limit, delegate: delegate)
}
}
}
}

you need to set Swift 3 #objc inference -> Default
go to project Setting
click Build Settings
Search Swift 3 #objc Inference
set Default

Related

Error "Trailing closure passed to parameter of type 'NSManagedObjectContext' that does not accept a closure" in Swift

I try to add a live activity to my app, in Swift. But when I try to run the app, the error message "Trailing closure passed to parameter of type 'NSManagedObjectContext' that does not accept a closure" appear. My app uses Core Data to save the data of my app.
class HabitManager: ObservableObject {
private var activity: Activity<HabitsWidgetAttributes>? = nil
func startHabit(name: String, symbol: String, currentTask: String) {
let attributes = HabitsWidgetAttributes(name: name, symbol: symbol)
let state = HabitsWidgetAttributes.ContentState(currentTask: currentTask)
activity = try? Activity<HabitsWidgetAttributes>.request(attributes: attributes, contentState: state)
}
func updateActivity(nextTask: String) {
let state = HabitsWidgetAttributes.ContentState(currentTask: nextTask)
Task { // Line where the error is generated
await activity?.update(using: state)
}
}
func stopActivity() {
let state = HabitsWidgetAttributes.ContentState(currentTask: "Finished")
Task { // Line where the error is generated
await activity?.end(using: state, dismissalPolicy: .immediate)
}
}
}
If you create a CoreData entity called Task, then the compiler will try to use that instead of the Swift Task struct.
You can either rename your CoreData entity to something else (which I'd recommend), or you can call an async task by prefixing it with the module, in this case it would look like this:
Swift.Task {
// do stuff
}
Since you'd have to do that everywhere, I would strongly recommend renaming your entity instead.

Need keypath syntax for use in assign(to:_) in SwiftUI

I'm new to SwiftUI and have been following along with #peter-friese's example SwiftUI/Firebase app.
My example app works perfectly, but am now trying to modify slightly but am unable to get the correct keypath syntax of in the assign/map in order to set a property.
Relevantly (and slightly simplified), there is a struct for the data model:
struct Task: Codable, Identifiable {
var title: String
var status: Bool
var flag: Bool
}
and a class for a view model:
class TaskCellViewModel {
#Published var task: Task
var iconName:String = ""
}
In this tutorial a map/assign is used within the TaskCellViewModel to set the value of the iconName property in the instance of the TaskCellViewModel as follows:
private var cancellables = Set<AnyCancellable>()
init(task: Task) {
self.task = task
$task
.map { task in
task.status ? "checkmark.circle.fill" : "circle"
}
.assign(to: \.iconName, on: self)
.store(in: &cancellables)
}
This works for setting the iconName. What is the correct syntax to set the flag property on the Task itself?
I have tried various combinations but none work, including:
.assign(to .\Task.task.flag, on: self)
.assign(to .\task.flag, on: self)
.assign(to .\Task.task.flag, on: TaskCellViewModel)
Using Task.task.flag it fails at runtime with EXC_BAD_ACCESS error or a type conversion compile error:
Cannot convert value of type AnswerRowViewModel.Type to expected argument type AnswerRowViewModel.
PS given I'm learning and trying to follow along with the tutorials, I'm hoping for a answer to the assign/map question - as opposed to a workaround/alternative.
Use sink instead
.sink { [weak self] flag in
self?.task.flag = flag
}
This is probably the assign arguments you were looking for:
.assign(to: \Task.flag, on: self.task)
BUT this won't work here since Task is a struct. The first argument is a ReferenceWritableKeyPath (docs) which doesn't work with a struct's value semantics. Your TaskCellViewModel is a class, so that's why it worked with self.
As Asperi already answered, you can use sink for this case and manually assign the value in the closure.

How to use inout variables with closures defined by other sources?

I'm relatively new to Swift and was wondering how I could achieve this exact thing.
I have a Swift process, and I want to toggle a flag on completion, and I have the following code:
task.terminationHandler = { process in
isTaskComplete.toggle()
}
I have this exact code duplicated in various views and was trying to convert it to a function, with my first attempt of referencing the isTaskComplete flag by using inout.
However, because terminationHandler itself defines the parameters of the closure it takes, there is no way for me to attach a secondary inout parameter. I was wondering if there was any way for me to reference the flag inside the closure and have the value be referenced?
For what it's worth in using Swift 5 and Xcode 11.5.
Any help will be greatly appreciated! Thanks :)
You can use protocols and protocol extensions for that.
protocol NameYourProtocol {
var task: TypeOfTask { get } // { get set } If you need
var isTaskComplete: Bool { get }
}
extension NameYourProtocol {
func handleTermination() {
task.terminationHandler = { process in
isTaskComplete.toggle()
}
}
}
And this is what you will do in every class you need to call it:
class Worker: NameYourProtocol {
// This will be required by protocol.
var task = TypeOfTask()
var isTaskComplete = false
init() {
// Call `handleTermination` where you need to.
handleTermination()
}
}

KVO for dependent key paths does not work properly for Swift class

I'm trying to write a wrapper around URLSessionTask in Swift. According to the documentation
All task properties support key-value observing.
So I want to keep this behavior and make all the properties on my wrapper also KVO-compliant (usually delegating to the wrapped task) and fully accessible to Objective-C. I'll describe what I'm doing with one property, but I basically want to do the same thing for all properties.
Let's take the property state of URLSessionTask. I create my wrapper like this:
#objc(MyURLSessionTask)
public class TaskWrapper: NSObject {
#objc public internal(set) var underlyingTask: URLSessionTask?
#objc dynamic public var state: URLSessionTask.State {
return underlyingTask?.state ?? backupState
}
// the state to be used when we don't have an underlyingTask
#objc dynamic private var backupState: URLSessionTask.State = .suspended
#objc public func resume() {
if let task = underlyingTask {
task.resume()
return
}
dispatchOnBackgroundQueue {
let task:URLSessionTask = constructTask()
task.resume()
self.underlyingTask = task
}
}
}
I added #objc to the properties so they are available to be called from Objective-C. And I added dynamic to the properties so they will be called via message-passing/the runtime even from Swift, to make sure the correct KVO-Notifications can be generated by NSObject. This is supposed to be enough according to Apple's KVO chapter in the "Using Swift with Cocoa and Objective-C" book.
I then implemented the static class methods necessary to tell KVO about dependent key paths:
// MARK: KVO Support
extension TaskWrapper {
#objc static var keyPathsForValuesAffectingState:Set<String> {
let keypaths:Set<String> = [
#keyPath(TaskWrapper.backupState),
#keyPath(TaskWrapper.underlyingTask.state)
]
return keypaths
}
}
Then I wrote a unit test to check whether the notifications are called correctly:
var swiftKVOObserver:NSKeyValueObservation?
func testStateObservation() {
let taskWrapper = TaskWrapper()
let objcKVOExpectation = keyValueObservingExpectation(for: taskWrapper, keyPath: #keyPath(TaskWrapper.state), handler: nil)
let swiftKVOExpectation = expectation(description: "Expect Swift KVO call for `state`-change")
swiftKVOObserver = taskWrapper.observe(\.state) { (_, _) in
swiftKVOExpectation.fulfill()
}
// this should trigger both KVO versions
taskWrapper.underlyingTask = URLSession(configuration: .default).dataTask(with: url)
self.wait(for: [swiftKVOExpectation, objcKVOExpectation], timeout: 0.1)
}
When I run it, the test crashes with an NSInternalInconsistencyException:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Cannot remove an observer <_XCKVOExpectationImplementation 0x60000009d6a0> for the key path "underlyingTask.state" from < MyURLSessionTask 0x6000002a1440>, most likely because the value for the key "underlyingTask" has changed without an appropriate KVO notification being sent. Check the KVO-compliance of the MyURLSessionTask class.'
But by making the underlyingTask-property #objc and dynamic, the Objective-C runtime should ensure that this notification is sent, even when the task is changed from Swift, right?
I can make the test work correctly by sending the KVO-notifications for the underlyingTask manually like this:
#objc public internal(set) var underlyingTask: URLSessionTask? {
willSet {
willChangeValue(for: \.underlyingTask)
}
didSet {
didChangeValue(for: \.underlyingTask)
}
}
But I'd much rather avoid having to implement this for every property and would prefer to use the existing keyPathsForValuesAffecting<Key> methods. Am I missing something to make this work? Or should it work and this is a bug?
Property underlyingTask isn't dynamic.

Modifying struct instance variables within a Dispatch closure in Swift

I'm using the DEVELOPMENT-SNAPSHOT-2016-06-06-a version of Swift. I cannot seem to get around this issue, I've tried using #noescape in various places, but I still have the following error:
Closure cannot implicitly capture a mutating self parameter
To better explain, here is a simple example:
public struct ExampleStruct {
let connectQueue = dispatch_queue_create("connectQueue", nil)
var test = 10
mutating func example() {
if let connectQueue = self.connectQueue {
dispatch_sync(connectQueue) {
self.test = 20 // error happens here
}
}
}
}
Something must have changed in these Swift binaries that is now causing my previously working code to break. A workaround I want to avoid is making my struct a class, which does help in fixing the issue. Let me know if there is another way.
I cannot test it, because I'm not using a build with that error, but I'm pretty sure by capturing self explicitly you can fix it:
dispatch_sync(connectQueue) { [self] in
self.test = 20
}
EDIT: Apparently it doesn't work, maybe you can try this (not very nice tbh):
var copy = self
dispatch_sync(connectQueue) {
copy.test = 20
}
self = copy
If you want to read more on why, here is the responsible Swift proposal.
The new dispatch API makes the sync method #noreturn so you wouldn't need the explicit capture:
connectQueue.sync {
test = 20
}
You are using Swift3 since you mentioned a recent dev snapshot of Swift. Try below and let me know if it works:
public struct ExampleStruct {
let connectQueue = DispatchQueue(label: "connectQueue", attributes: .concurrent)//This creates a concurrent Queue
var test = 10
mutating func example() {
connectQueue.sync {
self.test = 20
}
}
}
If you are interested in other types of queues, check these:
let serialQueue = DispatchQueue(label: "YOUR_QUEUE", attributes: .serial)
serialQueue.sync {
//
}
Get the mainQueue asynchronously and synchronously:
DispatchQueue.main.async {
//async operations
}
DispatchQueue.main.sync {
//sync operations
}
And if you are interested in Background:
DispatchQueue.global(attributes: .qosDefault).async {
//async operations
}
You could refer this for new features in Swift3 and for changes to existing version: Migrating to Swift 2.3 or Swift 3 from Swift 2.2