Convert a swift closure into a block - ios

I need to pass a callback parameter from a swift class to an Objective-C one.
I have searched for the way to do it, but I am struggling, I got this:
public typealias RequestCallBackObject = (gbRequest: AnyObject!, status: ServiceStatus, response: AnyObject?) -> ()
But how would it be in Objective-C ?

It should be something like this:
-(void) testMethod:(void(^) (id gbRequest, ServiceStatus *serviceStatus, id response) ) blockName {
}
Swift's AnyObject equivalent is id in Objective-C.

Related

Use Swift to interact with an Objective C method that expects a block as an argument

I am trying to write some Swift code that calls an existing Objective C function. The Objective C function looks like:
+(void) getCurrentUserprofileWithCompletion:(RequestCallback)completion {...}
where RequestCallback is defined in a .h file as:
typedef void (^RequestCallback) (ResponseInfo *responseInfo);
I have tried a number of different things, but nothing seems to work. The code that looks the most logical to me is:
let callback: (responseInfo: ResponseInfo) -> Void = {(responseInfo: ResponseInfo) -> Void in
if let organization: Organizations = Organizations.organizationWithId(orgId) {
completionBlock(false, nil)
} else {
self.switchOrganization(user, organization: organization, completionBlock: completionBlock)
}
}
Users.getCurrentUserprofileWithCompletion(callback)
but this is getting the error
cannot convert value of type '(responseInfo: ResponseInfo) -> Void' to expected argument type 'RequestCallback!'
Does anyone have any idea what I am doing wrong here? I have scoured the internet looking for help including the various Apple documentation, but either I am blind or misreading because nothing seems to be working.
Thanks in advance!
Just remove the type specification for responseInfo a use the type RequestCallback
let callback: RequestCallback = { responseInfo -> Void in
if let organization: Organizations = Organizations.organizationWithId(orgId) {
completionBlock(false, nil)
} else {
self.switchOrganization(user, organization: organization, completionBlock: completionBlock)
}
}
Users.getCurrentUserprofileWithCompletion(callback)

Cannot convert value of type 'String.Type' to expected argument type 'String!'

I am using a library MDWamp written in objective C and it has a property of the following type
#property (nonatomic, strong) void (^deferredWampCRASigningBlock)( NSString *challange, void(^finishBLock)(NSString *signature) );
This is the signature in swift
public var deferredWampCRASigningBlock: ((String!, ((String!) -> Void)!) -> Void)!
and when I try to instantiate it in swift in the following manner
self.wamp?.config.deferredWampCRASigningBlock?(str : String , { (str2 : String) -> Void in
})
but I get this error
Cannot convert value of type 'String.Type' to expected argument type
'String!'
Any suggestions would be appreciated.
It means you're passing the data type. Please pass the value.
Lets walk through what deferredWampCRASigningBlock is:
((String!, ((String!) -> Void)!) -> Void)!
This is a void function that takes two things:
a String!
a void function that takes a String!
So when you call it, you must pass it those things. A string and a function.
let challenge = "challenge"
let finishBLock: String! -> Void = { signature in }
self.wamp?.config.deferredWampCRASigningBlock?(challenge, finishBlock)
From some of your comments, you seem to not know what challenge should be at this point. That suggests you should not be calling this function. This function is intended to be called by the part of the program that does know challenge is.
The confusion may be related to "when I try to instantiate it." The code you've given doesn't instantiate anything. It is trying to call the function. Perhaps what you really meant was to create the function and assign it:
self.wamp?.config.deferredWampCRASigningBlock =
{ (challenge: String!, finishBlock: ((String!) -> Void)!) -> Void in
// ...
}
Try this
self.wamp?.config.deferredWampCRASigningBlock = {( challenge: String!, finishBlock) -> Void in
//calculate signature using any algorithm and return in finishBlock see below example
let sign = challenge.hmacSHA256DataWithKey(“secretKey”)
finishBlock(sign)
}
You'r passing String.Type not string value.
Instead of:
self.wamp?.config.deferredWampCRASigningBlock?(str : String , { (str2 : String) -> Void in
})
It should be:
self.wamp?.config.deferredWampCRASigningBlock?(str : "some string" , { (str2 : String) -> Void in
})
cell.lblname?.text = String(describing: tasks[indexPath.row])
cell.lbladdress?.text = String(describing: tasks[indexPath.row])
cell.lblphone?.text = String(describing: tasks[indexPath.row])

Block conversion in swift from Objective-c

How to convert following block from Objective-C to Swift. Am using Objective-C files in Swift using bridge header. But small confusion in block conversion
Objective-C Block:
+ (void) while:(id)obj name:(void(^)(type*))callback;
Sample output:
[Sub while:keeper viewControllerChanged:^(NSString* newNickname) {
NSLog(#"\nVC2- Now screen is in: %#", newNickname);
}];
How to convert this in swift ?
EDIT:
Swift block error is
Sub.while(obj: AnyObject!, viewControllerChanged: ((String!) -> Void)!)
When you define :
class func while1(obj:AnyObject, callback name:((newNickname:NSString?) -> Void)) {
}
And when call function :
self.while1(self) { (newNickname) -> Void in
print("\nVC2- Now screen is in:" + "\(newNickname)")
}
EDIT :
Okay, Then you just want to call it from swift..right..? Then use this statement :
ClassName.while1(obj as AnyObject) { (nickName:String!) -> Void in
print(nickName)
}
But first make sure that in your definition statement "type" indicates for what DataType, so please define there actual DataType
+ (void)while:(id)obj name:(void(^)(type*))callback;
to --> For example :
+ (void)while1:(id)obj name:(void(^)(NSString *))callback;
And one more thing to note that while in built in keyword, please do not use it if possible.
You can call like this:
YourClassName.while2(Yourparameter , name: {(nickName : String) -> Void in
})
I hope this help.
I'm not sure if you are asking how to write blocks in swift or if I'm not completely getting your question. But if it's the first then...
(void(^)(type*))callback
becomes
callback: (param:type*)->(returnType*)
i.e.
func doSomething(callback:((number:Int)->()))
is called like
doSomething(callback:{number in
print("\(number)")
})

Closure declaration in swift 2.0

In swift 2.0, what is the correct closure declaration? I've seen examples done like below, but it doesn't seem to work for me.
In SomeClass:
var successBlock: (Bool) -> () = { _ in }
and it would be called like this:
self.successBlock(true)
Then in SomeOtherClass:
let someClass = SomeClass
someClass.successBlock {
success in
//code here
}
Bit this gives me an error: (_) -> is not convertible to Bool
I've tried googling around a bit but with no luck...
Is there a syntax change with swift 2.0 or is it me?
If you're trying to set the successBlock, you should do it with an = sign:
someClass.successBlock = { success in
// code here
}
EDIT: You mentioned that you only want your other class to "listen", but what does "listen" mean? If you want to listen to every time the closure gets called with some value and do something depending on it, you may want to have an array of closures instead:
var successBlocks : [Bool -> Void] = []
which you can invoke like this:
let value = true
successBlocks.forEach{ $0(value) }
When you want to listen to invocations, you can do this:
someClass.successBlocks.append( { success in
// do the stuff
} )
which won't override any other closures already in the array, so probably that's what you wanted to do.

Initializing object with closure as only parameter in Swift

I have an auto-generated swift class from one of my Obj-C pods that looks like this:
typealias BlockDomainMapperMappingBlock = (AnyObject!) -> AnyObject!
class BlockDomainMapper : DomainMapper {
var mappingBlock: BlockDomainMapperMappingBlock! { get }
/*not inherited*/ init!(block: BlockDomainMapperMappingBlock!)
}
When trying to initialize the object like so:
let domainMapper = BlockDomainMapper { (objectToMap : AnyObject!) -> AnyObject! in
return LoginCredentials(token: objectToMap)
}
I get the following error:
Cannot find an initializer for type 'BlockDomainMapper' that accepts
an argument list of type '((AnyObject!) -> AnyObject!)'
This baffles me, as I am using the auto-complete in X-Code to generate the most of the code (except: (objectToMap : AnyObject!), which starts out as an AnyObject! placeholder.)
EDIT: This is the objective-C code that generates the swift class:
typedef id (^BlockDomainMapperMappingBlock)(id dataToMap);
#interface BlockDomainMapper : GLTDomainMapper
#property (nonatomic, readonly, copy) BlockDomainMapperMappingBlock mappingBlock;
+ (BlockDomainMapper *)mapperWithBlock:(BlockDomainMapperMappingBlock)block;
#end
EDIT 2: Wow! After looking at the Obj-c code again, I think it either botched the mapperWithBlock conversion, or I'm using the wrong syntax to invoke that kind of class method.
Try:
let domainMapper = BlockDomainMapper() { (objectToMap : AnyObject!)
(i.e. include () after BlockDomainManager())
It looks to me like the Objective-C code you're starting from has a "class factory" convenience method mapperWithBlock: for creating BlockDomainMapper objects. That's not the same thing as an initializer. It uses an initializer.
Your initializer is the equivalent of an Objective-C call +initWithBlock:
If you want to call your initializer you need to add a parameter label:
let domainMapper = BlockDomainMapper(block:
{ (objectToMap : AnyObject!) -> AnyObject! in
return LoginCredentials(token: objectToMap)
}
That should work.
(I'm still learning the finer points of Swift, so I'm not 100% positive, but I think that's what you need to do.)
I now know what I did wrong. Here's some code that works.
let domainMapper = BlockDomainMapper { (objectToMap : AnyObject!) -> AnyObject! in
return LoginCredentials(token: objectToMap as! String)
}

Resources