Objective C Array completionHandler used in Swift - objective-c

I have a completion handler in a framework written in Objective C...
This is a typedef for a block type. It takes an array of PHErrors.
typedef void (^PHBridgeSendErrorArrayCompletionHandler)(NSArray *errors);
When I try to use this in Swift, I'm doing....
anObject.aMethod(completionHandler: { (errors: [ AnyObject?]) -> () in
...rest of code
}
But I keep getting this error:
Cannot convert value of type '([AnyObject?]) -> ()' to expected argument type 'PHBridgeSendErrorArrayCompletionHandler!'
Can anyone help, I'm baffled, it looks like it should work to me.

Or better yet, you can still use your typedef as typealias.
DEFINE
typealias PHBridgeSendErrorArrayCompletionHandler = (_ errors: [Error]?) -> Void
IMPLEMENTATION
func myFunctionWithErrorCompletion(completion: PHBridgeSendErrorArrayCompletionHandler) {
// Define empty array to add errors to
var errors:[Error]?
// Do Your Logic that may store errors to array
// Completion and pass errors
completion(errors)
}
USAGE
func anotherOfMyFunctions() {
// Call the function
myFunctionWithErrorCompletion { (errors) in
if let completionErrors = errors {
// React to errors
}
}
}

anObject.aMethod(completionHandler: { (errors: [ AnyObject?]) -> () in
}
should be
anObject.aMethod() { errors in
}
In order to dig any deeper, I have to know what PHBridgeSendErrorArrayCompletionHandler is

So my friend solved this problem by simply changing AnyObject to Any
(errors: [Any]?) in
Which baffles me because all objects in an NSArray are objects! So didn't think to try Any.
Im pretty new to Swift mind

Try this..
anObject.aMethod(completionHandler: { (errors:NSArray?) -> () in
...rest of code
}

Related

C API with structures in Swift - immutable value as inout argument

I'm working on a Swift 3 project that involves using some C APIs that I bridged from Objective-C.
Here is a sample snippet of the structure of the API:
typedef struct
{
StructMode mode;
StructLevel level;
} TargetStruct;
typedef struct
{
. . .
TargetStruct *targetStruct;
OtherStruct *otherStruct;
NonPointerStructA nonPointerStructA;
NonPointerStructB nonPointerStructB;
. . .
} InnerStruct;
typedef struct
{
InnerStruct innerStruct;
OtherStructB otherStructB;
} OuterStruct;
In my Swift code, my goal is to set a value of the TargetStruct from the OuterStruct, like the following:
// run function that returns an instance of TargetStruct
var targetStruct: TargetStruct = initializeTargetStruct()
// assign targetStruct to outerStruct
outerStruct.innerStruct.targetStruct = &targetStruct
However, I am getting the following error:
Cannot pass immutable value of TargetStruct as inout argument
If I set a value of a struct without the *, it will work fine:
var nonPointerStructA: NonPointerStructA = initializeNonPointerStructA()
outerStruct.innerStruct.nonPointerStructA = nonPointerStructA
I have tried setting the value of targetStruct like this, but for now I have no way to test it:
var targetStruct: TargetStruct = initializeTargetStruct()
outerStruct.innerStruct.targetStruct.initialize(from: &targetStruct, count: 0)
How to solve this problem? Thank you.
In Swift, prefix & is not an address-of operator. It is just needed to clarify that some expression is passed to an inout parameter. So, your first code is syntactically invalid in Swift.
Your C-structs are imported to Swift as follows:
struct TargetStruct {
var mode: StructMode
var level: StructLevel
//some auto generated initializers...
}
struct InnerStruct {
//...
var targetStruct: UnsafeMutablePointer<TargetStruct>!
var otherStruct: UnsafeMutablePointer<OtherStruct>!
var nonPointerStructA: NonPointerStructA
var nonPointerStructB: NonPointerStructB
//some auto generated initializers...
}
struct OuterStruct {
var innerStruct: InnerStruct
var otherStructB: OtherStructB
//some auto generated initializers...
}
(If something wrong, please tell me.)
As you see, targetStruct in your InnerStruct is a pointer, and initialize(from:count:) tries to write to the pointed region, but at the time you call initialize(from:count:), targetStruct holds its initial value nil, you know what happens when dereferencing null-pointer.
One way is to allocate a memory for the TargetStruct and use the pointer to the allocated region.
func allocateAndInitializeTargetStruct() -> UnsafeMutablePointer<TargetStruct> {
let targetStructRef = UnsafeMutablePointer<TargetStruct>.allocate(capacity: 1)
targetStructRef.initialize(to: initializeTargetStruct())
return targetStructRef
}
outerStruct.innerStruct.targetStruct = allocateAndInitializeTargetStruct()
This is a more general way than below, but you need to explicitly deinitialize and deallocate the allocated region. That's sort of hard to manage.
If you can confine the usage of the outerStruct in a single code-block, you can write something like this:
var targetStruct = initializeTargetStruct()
withUnsafeMutablePointer(to: &targetStruct) {targetStructPtr in
outerStruct.innerStruct.targetStruct = targetStructPtr
//Use `outerStruct` only inside this code-block
//...
}
In this case, the pointer held in outerStruct.innerStruct.targetStruct (== targetStructPtr) is only valid inside the closure and you cannot use it outside of it.
If any of the codes above does not fit for your use case, you may need to provide more context to find the best solution.
An example of nested use of withUnsafeMutablePointer(to:_:):
var targetStruct = initializeTargetStruct()
var otherStruct = initializeOtherStruct()
withUnsafeMutablePointer(to: &targetStruct) {targetStructPtr in
withUnsafeMutablePointer(to: &otherStruct) {otherStructPtr in
outerStruct.innerStruct.targetStruct = targetStructPtr
outerStruct.innerStruct.otherStruct = otherStructPtr
//Use `outerStruct` only inside this code-block
//...
}
}
When you need more pointers to set, this nesting would be a mess, but it's the current limitation of Swift.
An example of deinitialize and deallocate:
extension InnerStruct {
func freeMemberStructs() {
if let targetStructRef = targetStruct {
targetStructRef.deinitialize()
targetStructRef.deallocate(capacity: 1)
targetStruct = nil
}
if let otherStructRef = otherStruct {
otherStructRef.deinitialize()
otherStructRef.deallocate(capacity: 1)
otherStruct = nil
}
}
}
outerStruct.innerStruct.targetStruct = allocateAndInitializeTargetStruct()
outerStruct.innerStruct.otherStruct = allocateAndInitializeOtherStruct()
// Use `outerStruct`
//...
outerStruct.innerStruct.freeMemberStructs()
The code may not seem to be too complex (just a bunch of boilerplate codes), but it's hard to find when or where to do it. As your InnerStruct may be embedded in another struct which may need to be deinitilized and deallocated...
Hope you can find your best solution.

Macros with return value

I'm trying to reproduce this pattern in Swift
#define mustBeKindOfClassFailedReturn(object, objectClass, ret) \
if(![object isKindOfClass:objectClass]) { \
NSLog(([NSString stringWithFormat:#"%# must be kind of %# class, current class is %#", object, NSStringFromClass(objectClass), NSStringFromClass([object class])])) \
return ret; }
used like this
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout*)collectionViewLayout
insetForSectionAtIndex:(NSInteger)section {
mustNotBeNilFailedReturn(self.adapter, UIEdgeInsetsZero)
mustBeKindOfClassFailedReturn(self.adapter, [WBCollectionViewSectionAdapter class], UIEdgeInsetsZero)
Does anyone know a good solution to this?
Edit
I know about guard but using guard i have to rewrite a lot of code each time i'll have to override a method in my subclasses for exemple
/**
* mustOverride
*/
#define mustOverride \
{ NSLog(#"You must override this function") }
#define mustOverrideFailedReturn(ret) \
{ mustOverride \
return ret; }
EDIT 2
I've ended with solution is it the optimal one ?
func needOverride(function: String = __FUNCTION__, file: String = __FILE__, line: Int = __LINE__) -> Bool {
REVLogManager.SharedInstance.logErrorMessage("You must override this function", function: function, file: file, line: line, exception: nil, error: nil)
return false
}
func doesObject(function: String = __FUNCTION__, file: String = __FILE__, line: Int = __LINE__, matchingObject: AnyObject!, matchesClass matchingClass: AnyClass) -> Bool {
guard matchingObject.isKindOfClass(matchingClass) else {
let message = "\(matchingObject) must be kind of \(matchingClass) class, current class is \(matchingObject.dynamicType)"
REVLogManager.SharedInstance.logErrorMessage(message, function: function, file: file, line: line, exception: nil, error: nil)
return false
}
return true
}
I'm calling the method like this
public func actualScrollOffsetDistanceWithScrollView(scrollView: UIScrollView!) -> Float {
guard needOverride() else { return 0.0 }
return 0.0
}
And
guard doesObject(matchingObject: self, matchesClass: REVListSectionAdapter.classForCoder()) else { return }
Swift doesn't have a macro capability of this kind.
In terms of accomplishing your goal. The pattern you are following would most correctly be handled using guard statements. A function containing a guard statement must exit the enclosing scope (or trap) and may do so with a return.
Please check the Swift documentation for information about Control Flow and Early Exit control
My answer follows the same legacy pattern using in Swift. You can use classForCoder, but I prefer dynamicType for type checking.
func mustBeKindOfClassFailedReturn(object: AnyObject, objectClass: AnyClass, returnVal: Any?) {
if !object.isKindOfClass(objectClass) {
print("\(object) must be kind of \(objectClass) class, current class is \(object.dynamicType)")
return returnVal
}
return nil // or UIEdgeInsetsZero, or whatever
}
You may also get similar results with !(object is objectClass), but things get tricky when comparing certain number types. See Swift type inference and type checking issue
You can also replace AnyObject and Any with NSObject if you know you're dealing with Objective-C types. From your comment it seems like ret could be a value type, so that's why I make it an Any type.
Swift has a better solution for this kind of problem, the guard statement. In this case, just put this in your method.
guard let adapter = self.adapter as? WBCollectionViewSectionAdapter else {
/* return value if the adapter is not setup properly. */
return .Zero
}
/* continue with valid and correctly classed adapter */
If you're looking for a way to handle this for sub classes, you may want to consider generics. It will allow you implicit type safety without having to rewrite logic in your subclasses.

Objective-C To Swift: void (^safeHandler)(UIBackgroundFetchResult)

I am porting some AppDelegate code for a plugin Objective-C to Swift.
My Objective-C is pretty good but I am stumped at understanding whats going on here. This is the code I am stuck on porting:
void (^safeHandler)(UIBackgroundFetchResult) = ^(UIBackgroundFetchResult result){
dispatch_async(dispatch_get_main_queue(), ^{
completionHandler(result);
});
};
I understand that the the ^ is for code blocks, but looking at this as a whole I am lost as to what is going on and how to port this to Swift.
I don't understand how there are two bracketed portions here:
void (^safeHandler)(UIBackgroundFetchResult)
If you can advise what that syntax is and how to port to Swift I would greatly appreciate it!
It's a block, which is a closure in Swift. This block is named safeHandler and takes a UIBackgroundFetchResult parameter and returns void.
This is the equivalent type:
let safeHandler: (UIBackgroundFetchResult) -> ()
And the whole thing would be
let safeHandler: (UIBackgroundFetchResult) -> () = { result in
dispatch_async(dispatch_get_main_queue()) {
completionHandler(result)
}
}
Note: block syntax is notoriously wonky. You can use this site to see the various block syntax forms: http://goshdarnblocksyntax.com/

Having trouble converting a simple Objective-C block to Swift

Not sure what I'm doing wrong. I'm using this module https://github.com/wenzhaot/InstagramPhotoPicker (the header file for the block is here https://github.com/wenzhaot/InstagramPhotoPicker/blob/master/TWPhotoPicker/TWPhotoPickerController.h)
In Objective-C, the syntax is:
photoPicker.cropBlock = ^(UIImage *image) {
//do something
};
I tried converting it to swift, but I'm getting an error
photoPicker.cropBlock{ (image:UIImage) -> () in
//Do something
//error: cannot invoke 'cropBlock' with an argument list of type '((UIImage) -> ())'
}
How to get it to work?
You're just missing = sign. Also image is implicitly unwrapped optional:
photoPicker.cropBlock = { (image: UIImage!) -> () in
//Do something
}
or
photoPicker.cropBlock = { image in
//Do something
}

iap - conversion from objective c to swift

I'm trying to convert my app from objective c to swift, and i have everything except for the in app purchase working.
i have the objective c helper class imported in the project, but i'm having trouble doing the RequestProductsCompletionHandler section
in the old objective c version i have the code
[[MTIAPHelper sharedInstance] requestProductsWithCompletionHandler:^(BOOL success, NSArray *products) {
if (success) {
_products = products;
if([[self appData] isPro] == FALSE)
[[self bUpgrade] setUserInteractionEnabled:TRUE];
}
}];
and i'm trying to convert this section to objective c but so far i've been unable to convert the requestProductsWithCompletionHandler part
can anyone help?
i've tried creating the completion handler the same was as in objective c using
requestProductsWithCompletionHandler(sucess: Bool, products : NSArray)
but i get the compiler errors "Extra argument 'products' in call" and "Expected member name or constructor call after type name".
if i try it without the parameters i get "Missing argument for parameter #1 in call"
In Swift, your completion handler would be a closure. The syntax is semi-similar to blocks in Objective-C but, instead of defining the parameters outside the block:
^(BOOL success, NSArray *products) { /* ... */ }
you define them inside the closure:
{ (success: Bool, products: [AnyObject]!) in /* ... */ }
So, your call to requestProductsWithCompletionHandler should look something like this:
MTIAPHelper.sharedInstance().requestProductsWithCompletionHandler {
(success: Bool, products: [AnyObject]!) in
if success {
// etc.
}
}
You can also let Swift infer the parameter types for you:
MTIAPHelper.sharedInstance().requestProductsWithCompletionHandler {
(success, products) in
if success {
// etc.
}
}