DeskA
1
Is there a way to add a __attribute__((noescape)) to a parameter in Swift? I'm running into an issue with an Objective-C method that requires it.
In a large mixed project, I'm overriding UITableView.performBatchUpdates(_:completion) in a UITableView subclass in Swift.:
class MyCustomTableView: UITableView {
// how to annotate the updates parameter as NS_NOESCAPE?
public override func performBatchUpdates(_ updates: (() -> Void)?, completion: ((Bool) -> Void)? = nil) {
// do some bookkeeping
super.performBatchUpdates(updates, completion: completion)
}
}
This subclass is also used in the Objective-C parts of the project, so it get's added to the Project-Swift.h header and Swift automatically converts it to the following:
@interface MyCustomTableView : UITableView
- (void)performBatchUpdates:(void (^ _Nullable)(void))updates completion:(void (^ _Nullable)(BOOL))completion;
@end
However, Objective-C requires that this method is annotation with NS_NOESCAPE ( = __attribute__((noescape))).
I don't see a direct way to add this in Swift? How do I solve this?
tera
2
Swiss has this limitation: you can't have a closure non-escaping and optional at the same time, Optional<()->Void> is always escaping. With non optional closures (not your case) you just use @escaping to make the closure escaping and by default the closure is non escaping.
Are you getting some compilation error or what?
DeskA
3
We're getting warnings (which we also cannot turn off) in the Project-Swift.h generated header file, because Objective-C requires an NS_NOESCAPE.
tera
4
If you don't fear missing it in other possibly important cases, you may switch that warning off by adding -Wno-missing-noescape to Xcode's "Other Warning Flags".
DeskA
5
Yes we don’t wanna do that. So there’s no swift solution for this?
tera
6
Not sure, possibly no pure Swift solution.
As you are using Obj-C anyway, as a workaround you may create an obj-c wrapper:
Wrong code
@interface UITableView(Extras)
- (void)performBatchUpdates2:(void (^ _Nullable)(void))updates completion:(void (^ _Nullable)(BOOL finished))completion;
@end
@implementation UITableView(Extras)
- (void)performBatchUpdates2:(void (^ _Nullable)(void))updates completion:(void (^ _Nullable)(BOOL finished))completion {
[self performBatchUpdates:updates completion:completion];
}
@end
and override performBatchUpdates2 instead of performBatchUpdates from Swift. You'll get no warning in this case.
Edit: no, that won't work, scratch that.
tera
7
This will work, a sketch:
Obj-C:
@interface ObjcTableView: UITableView
-(void)performBatchUpdates2: ...
@end
@implementation ObjcTableView
-(void)performBatchUpdates: ... {
[self performBatchUpdates2: ...];
}
-(void)performBatchUpdates2: ... {
[super performBatchUpdates: ...];
}
@end
Swift:
class MyCustomTableView: ObjcTableView {
override func performBatchUpdates2(...) {
....
}
}
Or just live with the warning!
1 Like