Generic understanding issue - swift

I was reading Alamofire example, below is the function declaration is not clear to me what does this mean: Response<T, NSError> -> Void
public func responseObject<T: ResponseJSONObjectSerializable>
(completionHandler: Response<T, NSError> -> Void) -> Self {
////
}

Related

save escaping method reference in swift

I am a Java/Kotlin programmer and new to swift. I want to pass a method reference in a constructor to save it for later use. The method I want to pass looks like this:
func refresh(completion: #escaping (Error?) -> ()) {
...
}
What I want to do is instantiate an object and pass this method as a parameter like this:
refreshControl = Refresher() {
compl -> Void in
self.refresh(completion: compl)
}
The class I want to pass this function to looks like this:
class Refresher {
let refresh: (#escaping (Error?) -> ()) -> Void
init(refresh: (#escaping (Error?) -> ()) -> Void) {
self.refresh = refresh
}
// call refresh somewhere later
}
This does not compile with error "Assigning non-escaping parameter 'refresh' to an #escaping closure. Not entirely sure what escaping does but I know I need it in the actual refresh function. I am not sure how to syntax this right. Any help would be appreciated.
But Xcode tells you what to do. It offers you a Fix-It:
init(refresh: #escaping (#escaping (Error?) -> ()) -> Void) {
Personally I would then get rid of the other #escaping stuff you've put in, as it is not needed. So:
class Refresher {
let refresh: ((Error?) -> ()) -> Void
init(refresh: #escaping ((Error?) -> ()) -> Void) {
self.refresh = refresh
}
}
And elsewhere:
func refresh(completion: (Error?) -> ()) {
// ...
}
func f() {
let refreshControl = Refresher() {
compl -> Void in
self.refresh(completion: compl)
}
// ...
}

Class Initializer with #escaping parameter

I'm setting up a class that can ideally store an async method for later use. I would like to pass a function inside of class initializer but I'm running into a weird compiler issue.
Cannot convert value of type '(#escaping (Int) -> Void) -> ()' to expected argument type '((Int) -> Void) -> Void'
If the method is not escaping/sync this works fine. The compiler also suggest to force cast the parameter as! (((Int) -> Void) -> Void). Gave that a shot but it crashes.
Here's an example I've been messing with in a playground:
class NumberTwo {
let numberTwoMethod: ((Int) -> Void) -> Void
init(numberTwoMethod: #escaping ((Int) -> Void) -> Void) {
self.numberTwoMethod = numberTwoMethod
}
func callNumberTwoMethod() {
numberTwoMethod { myNum in
print(myNum)
}
}
}
func getNumberTwoMethod(completion: #escaping (Int) -> Void) {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
completion(2)
}
}
func getNumberTwoMethodSync(completion: (Int) -> Void) {
completion(2)
}
NumberTwo(numberTwoMethod: getNumberTwoMethod) // error: cannot convert value of type '(#escaping (Int) -> Void) -> ()' to expected argument type '((Int) -> Void) -> Void'
NumberTwo(numberTwoMethod: getNumberTwoMethodSync) // Works
Any suggestions on what's going on here or alternative ways of storing an async function as a variable in a class?
You are missing #escaping on the inner closure:
class NumberTwo {
let numberTwoMethod: (#escaping (Int) -> Void) -> Void
init(numberTwoMethod: #escaping (#escaping (Int) -> Void) -> Void) {
self.numberTwoMethod = numberTwoMethod
}
func callNumberTwoMethod() {
numberTwoMethod { myNum in
print(myNum)
}
}
}
or slightly simplified:
class NumberTwo {
typealias CompletionHandler = (Int) -> Void
let numberTwoMethod: (#escaping CompletionHandler) -> Void
init(numberTwoMethod: #escaping (#escaping CompletionHandler) -> Void) {
self.numberTwoMethod = numberTwoMethod
}
func callNumberTwoMethod() {
numberTwoMethod { myNum in
print(myNum)
}
}
}
Also note this will probably create a memory leak since there is no weak anywhere.

Weird crash when calling closure with generic parameters in Swift 3

here I have a Protocol:
protocol CrashProtocol {
associatedtype T
static func tryCrash(_ dummyInt: Int,
with closure: ((T) -> Void))
}
A Base class that implements it:
class Crash<M>: CrashProtocol {
typealias T = M
class func tryCrash(_ dummyInt: Int,
with closure: ((M) -> Void)) {
print("Crash tryCrash")
}
}
And a derived class inherit the base class:
class DerivedCrash: Crash<DummyObject> {
override class func tryCrash(_ dummyInt: Int, with closure: ((DummyObject) -> Void)) {
super.tryCrash(dummyInt, with: closure)
print("Derived tryCrash")
let obj = DummyObject.init()
closure(obj)
}
}
Now whenever I try
DerivedCrash.tryCrash(1) { _ in
print("Never reach here")
}
I get a "EXC_BAD_ACCESS" crash. You can find my testing code here.
I've done my share of debugging, but only find out that the memory address causing the crash points to a Swift.Int instance, which I do not use..
And if I change the calling code a little bit, the code would crash after the closure being executed..
DerivedCrash.tryCrash(1) { (obj: DummyObject) in
//print("Never reach here")
print("print as expected and then crash")
}
If anyone could shred in some light, I would be highly appreciated..
I have added NSObject to associatedtype and now it doesn't crash.
It doesn't answer your question, but maybe this temp solution will help you
protocol CrashProtocol {
associatedtype T: NSObject
static func tryCrash(_ dummyInt: Int,
with closure: ((T) -> Void))
}
class Crash<M:NSObject>: CrashProtocol {
typealias T = M
class func tryCrash(_ dummyInt: Int,
with closure: ((M) -> Void)) {
print("Crash tryCrash")
}
}

Cannot convert value of type '(NSURLRequest, HTTPURLResponse?, AnyObject?, NSError?) -> Void' to expected argument type '(DataResponse<Any>) -> Void'

I study how to make iOS app by codingforentrepreneurs.com
nowadays I study Alamofire. Xcode is 8.3.3
this is error command. I don't understand error command.
Cannot convert value of type '(NSURLRequest, HTTPURLResponse?,
AnyObject?, NSError?) -> Void' to expected argument type
'(DataResponse) -> Void'
this is ViewController.swift
import UIKit
import Alamofire
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
var rTest = Alamofire.request("http://ec2-52-78-193-10.ap-northeast-2.compute.amazonaws.com", method: .get)
.responseJSON(completionHandler: isComplete)
}
func isComplete(request:NSURLRequest, response: HTTPURLResponse?, data: AnyObject?, error:NSError?) -> Void {
print(response!.statusCode)
print(data)
print(error)
print(request)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
i don't know what is problem.
could you help me?
Signature of the completion handler method should be like this.
func isComplete(response: DataResponse<Any>) {
let statusCode = response?.response?.statusCode
let result = response?.result
let request = response?.request
}
The error, in this case, correctly describes the problem.
The completion handler you passed in was of type (NSURLRequest, HTTPURLResponse?, AnyObject?, NSError?) -> Void but that is not the correct type for an Alamofire completion handler. The correct type is (DataResponse) -> Void
This means you need to change your isComplete method to something like:
func isComplete(dataResponse: DataResponse<Any>) -> Void {
print(dataResponse)
}

How to return `[Self]` from a Swift Protocol?

I am having a Protocol implementation as follows.
protocol DatabaseInjectable {
static func deriveObjectFromDBRow(row: [String]) -> Self? // Method - 1
static func collectAllObjectsForDatabaseAction(action: (Database) -> Void) -> [Self]? // Method - 2
}
Where I am successful with the correspondent implementation of Method - 1 like this:
static func deriveObjectFromDBRow(row: [String]) -> Self? {
...
}
But I could not implement the Method - 2 like this:
static func collectAllObjectsForDatabaseAction(action: (WWDatabase) -> Void) -> [Self]? {
...
}
There I am getting an error like this:
'Self' is only available in a protocol or as the result of a method in a class;
Any help to return the array form of Self (the class it self) would be nice.
If you can set your class final you can replace Self by the class name
final class SampleClass: DatabaseInjectable {
init() {
}
static func deriveObjectFromDBRow(row: [String]) -> SampleClass? {
return SampleClass()
}
static func collectAllObjectsForDatabaseAction(action: (Database) -> Void) -> [SampleClass]? {
let array = [SampleClass]()
return array
}
}
There's a very well written answer here, but in short, you can define your protocol as such:
protocol DatabaseInjectable {
static func deriveObjectFromDBRow(row: [String]) -> DatabaseInjectable? // Method - 1
static func collectAllObjectsForDatabaseAction(action: (Database) -> Void) -> [DatabaseInjectable]? // Method - 2
}
You can make use of a typealias in your protocol DatabaseInjectable, and use this as an alias to Self type in the classes conforming to your protocol.
class Database {
var desc : String = "Default"
}
protocol DatabaseInjectable {
typealias MySelf
static func deriveObjectFromDBRow(row: [String]) -> MySelf?
static func collectAllObjectsForDatabaseAction(action: (Database) -> Void) -> [MySelf]?
}
class MyClass : DatabaseInjectable {
typealias MySelf = MyClass
static func deriveObjectFromDBRow(row: [String]) -> MySelf? {
return MyClass()
}
static func collectAllObjectsForDatabaseAction(action: (Database) -> Void) -> [MySelf]? {
return [MyClass(), MyClass()]
}
}
/* example */
let closure : (Database) -> () = { print($0.desc) }
var arr : [MyClass]? = MyClass.collectAllObjectsForDatabaseAction(closure)
/* [MyClass, MyClass] */
One drawback here is, however, that you could set e.g. typealias MySelf = Int (in the class) and have your functions return an integer/array of integers (rather than self/[Self]), and still conform to you protocol. Possibly this is a deal-breaker.