Syntax to Call Asynchronous Shared Instance Method from Within Closure in Swift - ios

I am having trouble with syntax to call a shared instance method from within a closure:
Here is my code:
func getContactImage (contact:Contacts, completion:#escaping (_ myimage: UIImage)->()){//open 1 method
var animg = UIImage(named:"default.png")!
let surl = "https://~/contactimage.png"
Utilities.shared.downloadImage(surl: surl as NSString, completion: image as UIImage ->Void in animg = img)
completion(animg)
}
The line Utilities.shared.downloadImage gives several errors including:
Cannot convert value of type 'UIAccessibilityTraits' (aka 'UInt64') to type 'UIImage' in coercion
The shared instance method looks like this:
#objc func downloadImage(surl: NSString, completion : #escaping (UIImage) -> Void ) {
//download image
}
What is the correct syntax to call the shared instance method from within closure?

Use
Utilities.shared.downloadImage(surl) { (img) in
// use img here
}
Also change function
#objc func downloadImage(_ surl: String, completion : #escaping (UIImage) -> Void ) { }
func getContactImage (contact:Contacts, completion:#escaping (_ myimage: UIImage)->()){//open 1 method
var animg = UIImage(named:"default.png")!
let surl = "https://~/contactimage.png"
Utilities.shared.downloadImage(surl) { (img) in
completion(img)
}
}
BTW encourage using SDWebImage

Related

How to use below closure variable in Swift

I am working on clouser in swift iOS, I have tried to create variable using clouser and add 2 clouser in single variable, variable declaration I did right, but I don't understand how to access it in my code.
here is the variable declaration.
var multipleClouser: ((_ success: (Bool), _ failer:(Error) -> Void)?
Most probably you meant callback, like
var multipleClouser: ((_ success: (Bool), _ failer: (Error?)) -> Void)?
and usage, like
multipleClouser?(true, nil)
or
multipleClouser?(false, SomeErrorHere)
set up like
multipleClouser = { success, error in
if success {
print("Done!")
} else {
print("Failure")
if let error = error {
print("\t with error: \(error)")
}
}
}

swift question about "#escaping" inside class

I am a newbie and maybe this is a silly question but I need some help.
I have this code like below but I wonder that should I remove "#escaping" inside the checkSignedIn function.
Class A{
public func checkSignedIn(complete: #escaping (Bool) -> Void) {
_ = Amplify.Auth.fetchAuthSession { (result) in
do {
let session = try result.get()
complete(session.isSignedIn)
} catch {
print("Fetch auth session failed with error - \(error)")
complete(false)
}
}
}
I imagine that using "#escaping" will escape the return value from closure if I assign complete() to a variable like below.
Class A{
var complete: (() -> Void)?
public func checkSignedIn(complete: #escaping (Bool) -> Void) {
_ = Amplify.Auth.fetchAuthSession { (result) in
do {
let session = try result.get()
self.complete = complete(session.isSignedIn)
} catch {
print("Fetch auth session failed with error - \(error)")
self.complete = complete(false)
}
}
}
Then I can call A.complete again.
Am I wrong? I appreciate it if you teach me about this.
No, they won't be the same.
The complete: #escaping (Bool) -> Void defines this:
a function (or a callback) that takes 1 argument (Bool), and returns nothing (Void). It's an equivalent of function that looks like this:
func complete(_ value: Bool) { }
this function escapes the scope of the function it's passed to, as it runs asynchronously (that's #escaping keyword meaning)
And then this function is called with complete(session.isSignedIn), where session.isSignedIn is a boolean argument you pass in, just as function's definition states, and function returns nothing
The statement self.complete = complete(session.isSignedIn) won't compile:
You defined self.complete as (() -> Void) type - that is a function or callback that takes no arguments, and returns nothing. It's an equivalent of function:
func y() { }
So complete(session.isSignedIn) returns Void type as we know. Assigning Void type to (() -> Void) type is not going to work.
If you want to save the escaping function / callback to be used elsewhere, you can do this:
// Make sure signature of the variable matches that of a function argument
var complete: ((Bool) -> Void)?
public func checkSignedIn(complete: #escaping (Bool) -> Void) {
// Save callback at the start of the function
self.complete = complete
// Then continue to a asynch part of the code:
_ = Amplify.Auth.fetchAuthSession { (result) in
// Inside this callback, you still can use the function argument
complete(session.isSignedIn)
...
}
// But in another function, you have to use self.complete, e.g.:
func x() {
// Use saved callback. You don't have to say `self` here, just using it for clarity
self.complete(true)
}

call function in swift file from objective-c file with completion handler (closure) syntax

I am having trouble calling a function in a swift file from an objective-c file where there is a closure in the swift function.
This is the Swift function
//In Utilities class
static func getString(query: NSString, completion: #escaping (_ response: NSString) -> Void) {
completion("hello")
}
This is how I try to call it in the objective-c class:
[Utilities getString:#"hi there" completion:^(NSString* response) {
NSLog(response);
}];
I'm getting the error 'No known class method for selector 'getString:completion:'
What is wrong with above?
Note: I am able to call a simpler method without the closure/completion bloc.
in swift class
static func myTest () {
print("function called")
}
called from objective-c class with:
[Utilities myTest];
SO the problem seems to relate to the closure syntax.
Surround the class with
#objcMembers class Utilities:NSObject {
or the function
#objc class func getString(query: NSString, completion: #escaping (_ response: NSString) -> Void) {
[Utilities getStringWithQuery:#"hi there" completion:^(NSString* response) {
NSLog(response);
}];

Is it possible to overload static method by closure signature in Swift 3?

Is it possible to overload static method by closure type in Swift 3?
For example, i have a struct with 2 methods:
struct Some {
static func doSomething(first: String, #escaping completion: ([Int]?) -> Void) {
...
}
static func doSomething(first: String, #escaping completion: ([Int]?, String?) -> Void) {
...
}
}
But when i try to call the first method Some.doSomething(first: "Hello") { (numbers) in ... } (with closure with one parameter) compiler gives me an error:
Ambiguous use of 'doSomething(first:completion:)'
Yes you can overload static method by closure type in Swift 3, but you
need to specify the type of the parameter for the first function as
its parameters partially matches with that of second function
Some.doSomething(first: "") { (number:[Int]?) in
}
Some.doSomething(first: "") { (number, value) in
}

Access Private UIKit Function Without Using Bridging Header

Consider the private C function _UICreateScreenUIImage, which returns a UIImage snapshot of the current device screen:
OBJC_EXTERN UIImage *_UICreateScreenUIImage(void) NS_RETURNS_RETAINED;
I can put this in a bridging header and access it in Swift like so:
MyApp-Bridging-Header.h
#import UIKit;
UIImage *_UICreateScreenUIImage(void) NS_RETURNS_RETAINED;
MyClass.swift
let image = _UICreateScreenUIImage()
print(image) // <UIImage: 0x7fc4ba6081c0>, {375, 667}
Is there a way I can access _UICreateScreenUIImage in pure Swift without using a bridging header?
An initial thought was to create an extension on UIImage, but the extension is expecting me to declare the body of the function in the extension:
extension UIImage {
public func _UICreateScreenUIImage(_: Void) -> UIImage // "Expected '{' in body of function declaration"
}
This implementation is flawed anyways, as _UICreateScreenUIImage isn't a method on UIImage.
Is exposing and accessing this method possible in pure Swift?
People seem to be confusing my question with "How do I take a screenshot?" That's not what I'm asking. I'm asking how do I access methods like UIImage *_UICreateScreenUIImage(void); in Swift. It could be any private method, such as +(UIImage *)_deviceSpecificImageNamed:(NSString *)name inBundle:(NSBundle *)bundle; or +(UIImage *)_pu_PhotosUIImageNamed:(NSString *)name;
.
It's a lot easier than you would expect:
#asmname("_UICreateScreenUIImage")
func _UICreateScreenUIImage() -> UIImage
// That's it – go ahead and call it:
_UICreateScreenUIImage()
As it happens, #asmname has actually just been changed in the 2.3 builds to #_silgen_name, so be ready to adjust accordingly:
#_silgen_name("_UICreateScreenUIImage")
func _UICreateScreenUIImage() -> UIImage
To my knowledge, #_silgen_name does not provide resolution of Objective-C methods. For this, there is the evenmore powerful Objective-C runtime API:
let invokeImageNamed: (String, NSTimeInterval) -> UIImage? = {
// The Objective-C selector for the method.
let selector: Selector = "animatedImageNamed:duration:"
guard case let method = class_getClassMethod(UIImage.self, selector)
where method != nil else { fatalError("Failed to look up \(selector)") }
// Recreation of the method's implementation function.
typealias Prototype = #convention(c) (AnyClass, Selector, NSString, NSTimeInterval) -> UIImage?
let opaqueIMP = method_getImplementation(method)
let function = unsafeBitCast(opaqueIMP, Prototype.self)
// Capture the implemenation data in a closure that can be invoked at any time.
return { name, interval in function(UIImage.self, selector, name, interval) }
}()
extension UIImage {
// Convenience method for calling the closure from the class.
class func imageNamed(name: String, interval: NSTimeInterval) -> UIImage? {
return invokeImageNamed(name, interval)
}
}
UIImage.imageNamed("test", interval: 0)
As far as handling NS_RETURNS_RETAINED, this won't be generated for you. Instead, you can use a return type of Unmanaged, and wrap that in a function to your convenience:
#_silgen_name("_UICreateScreenUIImage")
func _UICreateScreenUIImage() -> Unmanaged<UIImage>
func UICreateScreenUIImage() -> UIImage {
return _UICreateScreenUIImage().takeRetainedValue()
}

Resources