I'm try to convert code from Objective-C to Swift -
Objc-C part - no errors.
AppDelegate:
- (OWTConferenceClient*)conferenceClient{
return _conferenceClient;
}
-(void)conferenceClient:(OWTConferenceClient *)client didReceiveMessage:(NSString *)message from:(NSString *)senderId{
}
- (void)conferenceClient:(OWTConferenceClient *)client didAddParticipant:(OWTConferenceParticipant *)user{
}
-(void)conferenceClient:(OWTConferenceClient *)client didAddStream:(OWTRemoteStream *)stream{
}
to Swift
AppDelegate:
func conferenceClient() -> OWTConferenceClient { <--- Error here: Invalid redeclaration of 'conferenceClient()'
return conferenceClient
}
func conferenceClient(_ client:OWTConferenceClient, didAdd stream:OWTRemoteStream){
}
func conferenceClient(_ client:OWTConferenceClient, didAdd user:OWTConferenceParticipant) {
}
func conferenceClient(_ client:OWTConferenceClient, didReceiveMessage message:String, from senderId:String) {
}
What is wrong with Swift part?
It might be that you have a (global or instance) variable named conferenceClient which then interferes with that function.
You need to rename the variable (in ObjC, it had an underscore _conferenceClient)
Related
I came across this code on apple documentation on how to implement Game Center achievements. But I don't quite understand what "- (void)" really mean and how I can use it in a class.
- (void) challengeViewController:(MyAchievementChallengeViewController*)controller wasDismissedWithChallenge:(BOOL)issued
{
[self dismissViewControllerAnimated:YES completion:NULL];
if (issued)
{
[controller.achievement issueChallengeToPlayers:controller.players message:controller.message];
}
}
Can someone explain to me the use of keyword void in this context?
It means that the function has no return value.
The return type of the function is in front of the function name in Objective-C. So (void) is the return type.
So the Obj-C - (void) myFunc is equivalent in Swift to func myFunc() -> Void or the -> Void can simply be omitted to get func myFunc().
That function would translate to
func challengeViewController( _ controller: MyAchievementChallengeViewController, wasDismissedWithChallenge challenge: Bool) {
}
Trying to get completion block back from swift code, but looks like I'm doing something wrong.
My objC code which I want to replicate for my swift view controller TestViewController
I just need Bool and BMError back in completion block
Code in which I'm doing wrong:
TestViewController *changeVC = [[TestViewController alloc] initWithCompletionData:completion ];
My swift code which I tried to replicate like objc function:
#objc public class TestViewController {
var completionData: ((Bool, BMErrors?) -> Void)?
public required init?(coder aDecoder: NSCoder) {
fatalError("Not implemented")
}
#objc public init(completionData completion: ((Bool, BMErrors?) -> Void)?) {
super.init(nibName: nil, bundle: nil)
self.completionData = completion
}
func verifySuccess(result: QuestionResult, error: BMErrors?) {
if (result.success) {
// how to pass completionData
}
}
}
You can call TestViewController.completionData like this: self.completionData?(false, error) or self.completionData?(false, nil) if you don't want to pass error.
Im converting some code from Objective C.
-(nonnull NSString*) endpoint {
return #"LoginRequest";
}
The Swift converter produces
func endpoint() -> nonnull NSString {
return "LoginRequest"
}
However nonnull is not recognised by swift. This should also be an overrider function.
I believe it should be along the lines of
override func endpoint() -> NSString {
return "LoginRequest"
}
but it brings up an error.
Method does not override any Method from its superclass. I shouldnt need to remove the override, if I do, it conflicts with the original in the Objective C imported library.
Could you help please?
solved it
override func endpoint() -> String {
return "LoginRequest"
}
I wonder what's the Swift equivalent in calling a method on id in which the availability of the method is determined at runtime. Specifically I'm looking to do this pattern in Swift:
-(IBAction) handleEvent:(id) sender {
BOOL didDisable = NO;
if([sender respondsToSelector:#selector(setEnabled:)]) {
[sender setEnabled:NO];
didDisable = YES;
}
[self doSomethingAsyncWithCompletionHandler:^{
if(didDisable) {
[sender setEnabled:YES];
}
}];
}
The biggest problem is that setEnabled: is imported in Swift as a property (e.g. UIBarItem) and none of the following constructs compile
func handleEvent(sender: AnyObject) {
// Error: AnyObject does not have a member named "enabled"
sender.enabled? = false
// Error: (BooleanLiteralCompatible) -> _ is not identical to Bool
sender.setEnabled?(false)
}
You can in fact do it exactly the same way you were doing it before: by calling respondsToSelector:. Indeed, that is exactly what your proposed expression does:
sender.setEnabled?(false)
That expression is actually a shorthand - it calls respondsToSelector: first, and then calls setEnabled: only if the respondsToSelector: test passes. Unfortunately, as you say, you can't get that code to compile. That, however, is merely a quirk of Swift's known repertory of available methods. The fact is that, although it is a little tricky to get it to compile, it can be done - and once you get it to compile, it behaves just as you would expect.
However, I'm not going to explain how to make it compile, because I don't want to encourage this kind of trickery. This sort of dynamic messaging is discouraged in Swift. In general, dynamic messaging tricks such as key-value coding, introspection, and so forth are not needed in Swift and are not consonant with Swift's strong typing approach. It would be better to do things the Swift way, by casting optionally to something that you have reason to believe this thing might be and that has an enabled property. For example:
#IBAction func doButton(sender: AnyObject) {
switch sender {
case let c as UIControl: c.enabled = false
case let b as UIBarItem: b.enabled = false
default:break
}
}
Or:
#IBAction func doButton(sender: AnyObject) {
(sender as? UIControl)?.enabled = false
(sender as? UIBarItem)?.enabled = false
}
In Swift 2.0 beta 4, your prayers are answered; this code becomes legal:
#IBAction
func handleEvent(sender: AnyObject) {
if sender.respondsToSelector("setHidden:") {
sender.performSelector("setHidden:", withObject: true)
}
}
If you want to avoid using the respondsToSelector: method you could define a protocol instead. Then extend the classes you want to use that is already in conformance with this protocol's definition (enabled) and define the function with a generic variable conforming to your protocol.
protocol Enablable{
var enabled:Bool { get set }
}
extension UIButton : Enablable {}
extension UIBarButtonItem : Enablable {}
//....
func handleEvent<T:Enablable>(var sender: T) {
sender.enabled = false
}
If you need to use it with an IBAction method a little bit of a work around is required since you cannot use generics directly on them.
#IBAction func handleEventPressed(sender:AnyObject){
handleEvent(sender);
}
We also need a matching generic function without Enablable conformance so that we can call handleEvent without knowing wether or not sender is Enablable. Luckily the compiler is smart enough to figure out which of the two generic functions to use.
func handleEvent<T>(var sender: T) {
//Do Nothing case if T does not conform to Enablable
}
As a workaround/alternative, you can use Key-Value Coding:
#IBAction func handler(sender: AnyObject) {
if sender.respondsToSelector("setEnabled:") {
sender.setValue(false, forKey:"enabled")
}
}
This works with both Swift 1.2 (Xcode 6.4) and Swift 2.0 (Xcode 7 beta).
I'm just studying the "message-forwarding" of Objective-C. I write a test program to verify if I can "swallow" an unrecognized selector at run-time. So I did this:
- (void) forwardInvocation: (NSInvocation *) anInvocation {
if ([anInvocation selector] == #selector(testMessage)){
NSLog(#"Unknow message");
}
return;
}
But it still throws "unrecognized selector" error at run time. After searching the resolution I know that I need to override method "methodSignatureForSelector:", so I write another proxy class called "Proxy" and the following method:
(NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
if ([Proxy instancesRespondToSelector: selector]) {
return [Proxy instanceMethodSignatureForSelector: selector];
}
return [super methodSignatureForSelector:selector];
}
But, actually, I don't want to implement such another proxy class to accomplish this method. All I want to do is that ignore this unknown selector. But If I just type this, it does not work:
(NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
return [super methodSignatureForSelector:selector];
}
So, I wonder there is any way that can simply "swallow" this error? (Not using exception handler, I wanna a "forwarding"-like way). Thanks!
You probably need to generate a signature object, which is a bit tricky:
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
NSMethodSignature *sig = [super methodSignatureForSelector:selector];
if (!sig) {
if (selector == #selector(testMessage)) {
// Create a signature for our fake message.
sig = [NSMethodSignature signatureWithObjCTypes:"#:"];
}
}
return sig;
}
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
// Do whatever you want with the invocation.
}
The biggest issue seems to be the argument to signatureWithObjCTypes:. See Apple's type encoding documentation. Every method has at least two arguments: id self (type #) and SEL _cmd (type :).
Another way would be to have a dummy method, say - (void)dummy { } and then use sig = [super methodSignatureForSelector:#selector(dummy)]; to get the signature for your faked method.