问题
I previously asked a question on how to create a protocol with optional methods. The response was, pretty much, use Objective-c. See it here.
I did, and everything worked fine, because I was using
var delegate: SessionDelegate?;
That is, "delegate" is an optional SessionDelegate. In order to call methods from that delegate I could simply write:
self.delegate?.willOpenSession?(self);
Which was fine. But then I though, why make the delegate optional? So I changed it:
var delegate: SessionDelegate;
Obviously, the call changes too:
self.delegate.willOpenSession?(self);
The problem is, this last line (and any other of the kind) says: 'SessionDelegate' does not have a member named 'willOpenSession'. Why doesn't this work?
Here's my code:
SessionDelegate.h
@class Session;
@protocol SessionDelegate <NSObject>
@optional
- (BOOL)willOpenSession:(Session*)session;
- (void)didOpenSession:(Session*)session;
- (void)didFailOpenningSession:(Session*)session withError:(NSError*)error;
- (BOOL)willCloseSession:(Session*)session destroyingToken:(BOOL)destroyingToken;
- (void)didCloseSession:(Session*)session destroyingToken:(BOOL)destroyingToken;
@end
xxx-Bridging-Header.h
#import <Foundation/Foundation.h>
#import <FacebookSDK/FacebookSDK.h>
#import "SessionDelegate.h"
Session.swift
import Foundation
protocol Session {
var delegate: SessionDelegate { get set };
var isOpen: Bool { get };
var isCached: Bool { get };
func open();
func close();
func destroy();
}
FacebookSession.swift
import Foundation
class FacebookSession : Session {
var delegate: SessionDelegate;
var isOpen: Bool {
get {
return FBSession.activeSession().isOpen;
}
}
// TODO
var isCached: Bool {
get {
return false;
}
}
init(delegate: SessionDelegate) {
self.delegate = delegate;
}
func open() {
if self.isOpen {
return;
}
// Trigger the "will" event
self.delegate.willOpenSession?(self);
// Handle session state changes
var completionHandler: FBSessionStateHandler = {
session, status, error in
if error {
// Login failed for some reason, so we notify the delegate.
// TODO we should turn this NSError message into something more generic (that is, not facebook specific)
self.delegate.didFailOpenningSession?(self, withError: error);
}
else if status.value == FBSessionStateClosedLoginFailed.value {
// Login failed with no error. I'm not sure this ever happens
self.delegate.didFailOpenningSession?(self, withError: error);
}
else if status.value == FBSessionStateOpen.value || status.value == FBSessionStateOpenTokenExtended.value {
// Session is now open, we should notify the delegate
self.delegate.didOpenSession?(self);
}
else {
// There's no error but the session didn't open either. I don't think this ever happens, but if it does, what should we do here?
abort();
}
};
// Open the session, prompting the user if necessary
if FBSession.openActiveSessionWithReadPermissions([], allowLoginUI: true, completionHandler: completionHandler) {
// If we end up here, the session token must exist, se we now have an open session
self.delegate.d didOpenSession?(self);
}
}
func close() {
}
func destroy() {
}
}
Best regards.
Edit: I also tried the following
self.delegate.willOpenSession?(self as Session);
And
self.delegate.willOpenSession(self as Session);
Neither works.
Edit: After all, it doesn't work if I use
var delegate: SessionDelegate?;
Edit: The previous change also changes the error message. Now I have optional SessionDelegate (as I said in the previous edit) and the following line
self.delegate?.willOpenSession?(self)
Says: "Could not find member 'willOpenSession'"
回答1:
You're getting this error because you define Session
as a protocol, but the Objective-C method definitions in the SessionDelegate
protocol are expecting a Session
class or subclass. In Swift you can use protocol names interchangeably with class names in method definitions, but in Objective-C there's a difference:
- (void)willOpenSession:(Session *)session; // expects instance of Session class or subclass
- (void)willOpenSession:(id<Session>)session; // expects object conforming to Session protocol
From the code you posted I can't tell why you've declared Session
as a protocol -- does it add functionality to disparate classes? Could it instead be a superclass that FacebookSession
(and presumably other sessions) simply inherits from? Changing Session
to a class (and stubbing the methods) would solve the issue. Otherwise you'll need to change your SessionDelegate
methods to expect an id<Session>
, but for me that broke the compiler.
来源:https://stackoverflow.com/questions/24591921/sessiondelegate-does-not-have-a-member-named-xxx