I'm successfully mixing and matching Obj-C and Swift in an Xcode 7 project. However, I can't seem to figure out how, in an Objective C class, to inherit from a Swift class (and yes I know about declaring that Swift class as #objc for visibility). In this case the desired Swift superclass MySwiftViewController is a subclass of UIViewController. For now, in Obj-C, I'm inheriting directly from UIViewController and not gaining access to the capabilities I added in MySwiftViewController.
Here's what i understand:
-- To declare an Obj-C class as inheriting from something, that must be in the .h file after the ':':
#import <UIKit/UIKit.h>
#interface RootViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
#end
-- To make Swift classes visible, that is #imported:
#import "MyProject-Swift.h"
However, you cannot import the Swift auto-generated bridging header into the Obj-C .h file. You also cannot forward-declare an opaque superclass with #class. So, is this possible and how?
Unfortunately, it's not possible to subclass a Swift class in Objective-C. Straight from the docs:
You cannot subclass a Swift class in Objective-C.
See Apple's guide on interoperability for more details on what you can and cannot access with Objective-C.
As for Xcode 8.0 and earlier there is dirty-hacky solution, that probably will be fixed in the future.
If you want to subclass from swift file, you can add objc_subclassing_restricted attribute. You can make it as macro for convenience.
Code:
Swift class.
import Foundation
class SwiftClass : NSObject {
func say() {
print("hi");
}
}
Objc class:
#import <Foundation/Foundation.h>
#import "test-Swift.h"
#define SWIFT_SUBCLASS __attribute__((objc_subclassing_restricted))
SWIFT_SUBCLASS
#interface ObjcClass : SwiftClass
- (instancetype)init;
#end
#implementation ObjcClass
- (void)say {
NSLog(#"oops");
}
#end
But, as I understand, it is not supported, and you may have any sort of bugs because of it. So it is not guide to action, and more like curious thing to know.
In fact, it can be achieved by category:
Swift code
import UIKit
#objc open class TestModel: NSObject {
#objc var testName: String = String()
}
Objective C .h file code
#import <Foundation/Foundation.h>
#import "Test-Swift.h"
#interface TestModel (Add)
- (void)configTestName;
#end
Objective C .m file code
#import "TestModel+Add.h"
#implementation TestModel (Add)
- (void)configTestName {
self.testName = #"12323";
}
#end
Related
I have a framework with Objective-C and Swift mixed together. It compiles alone but when I import it in the Objective-C iOS app, Swift classes are not found but Objective-C classes are found.
My Swift classes are found inside the framework when importing MyFramework-Swift.h
The iOS app and framework are two different projects in the same workspace.
Defines Module and Embedded content contains Swift Code are set to Yes for all targets and my Swift classes are public with #objc
I tried to use #import MyFramework and #import <MyFramework/MyFramework-Swift.h> with no success.
I don't see the MyFramework-Swift.h header file in the framework's Headers directory into the projects. Not sure if this is normal. It is generated in DerivedData
EDIT: I managed to reproduce the problem with a very simple workspace in Xcode 8 (but probably the same in 7.3):
Create a new Cocoa touch framework TestFramework in objective-C
Create a A.h file
#class B;
#interface A : NSObject
-(void)print:(B*)caller;
#end
Create a A.m file
#import <Foundation/Foundation.h>
#import "TestFramework-Swift.h"
#import "A.h"
#implementation A
-(void)print:(B*)caller {
[caller test];
}
Create a B.swift file
import Foundation
#objc public class B : NSObject {
public func test() {
print("test");
}
}
Set A.h as a public header
import A.h into TestFramework.h
Try to compile the framework
Here the TestFramework-Swift.h is not found
Set Install Objective-C compatibility header to No
Try to compile the framework
Now it compiles !
Create a new iOS Objective-C Single view application App
Update the ViewController.m like this
#import "ViewController.h"
#import TestFramework;
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
B* b = [[B alloc] init];
A* a = [[A alloc] init];
[a print: b];
}
[...]
#end
You should have an error on B but not A. I also set Defines Module to Yes in both project without success
Ok I finally found the answer. Install Objective-C compatibility header must be set to Yes and the import must be #import <TestFramework/TestFramework-Swift.h>and not #import "TestFramework-Swift.h" inside the framework
I m trying to passing values from second class to first class for that I am using protocol and delegate process. Whenever I run my program I am facing below Issue.
No Type or Protocol Named 'locateMeDelegate'
Viewcontroller A .h
#interface first : UIViewController < locateMeDelegate > { }
In my case the issue was caused by importing the delegate's header file to the delegator's class .h file. This seems to create a sort of vicious circle. As soon as I deleted the import statement of the delegate's header from the delegator's .h file, the error went away.
Tipically, if you intend your protocol to be used by other classes you must declare it in the header file like this:
// MyClass.h
#protocol MyProtocol;
#interface MyClass : NSObject
#end
#protocol MyProtocol
- (void) doSomething: (MyClass*) m;
#end
After you declare it, you should implement the methods of the protocol in the implementation file, which should conform to the protocol like this:
// MyClass.m
#implementation MyClass <MyProtocol>
pragma mark - MyProtocol methods
- (void) doSomething: (MyClass *)m {
// method body
}
#end
After these two steps you're ready to use you protocol in any class you desire. For example, let's say we want to pass data to MyClass from other class (e.g. OtherClass.h). You should declare in OtherClass.h a property so that we can refer to MyClass and execute the protocol. Something like this:
// OtherClass.h
#import MyClass.h
#interface OtherClass : NSObject
#property (weak) id<MyProtocol> delegate;
#end
You don't forget to import the header file where you declared your protocol, otherwise Xcode will prompt No Type or protocol named "MyProtocol"
id<MyProtocol> delegate; means you can set as the delegate of OtherClass any object (id) that conforms to the MyProtocol protocol (<MyProtocol>)
Now you can create an OtherClass object from MyClass and set its delegate property to self. Like this:
// MyClass.m
- (void)viewDidLoad() {
OtherClass *otherClass = [[OtherClass alloc] init];
otherClass.delegate = self;
}
It's possible to set the delegate to self because the delegate can be any object and MyClass conforms to MyProtocol.
I hope this can help. If you want to know more about protocols you can refer to this two websites:
Working with Protocols - Apple Documentation
Ry's Objective-C Tutorial (This one is easy to pick up)
I also faced the same issue and it seems the error is from Xcode itself. Please Try running on Physical device. This would solve the issue faced.
I am suppose to extend a objective C class in swift which has a class extension in different header file with +Protected. The same is implemented in one .m file as usual.
But my problem is If i subclass this class I cannot use the variables and cannot call any methods which are private. But in Objective C if I subclass and import the same +Protected.h file in .m file I can use the private vars and methods of the super class. Can anyone show the way to do it I mean subclass and use the private methods and vars of it in swift as we are able to do in Objective C. Example is show below
#interface Parent : NSObject
#end
In seperate header file
#interface Parent()
#property NSInteger money;
-(void)spend;
#end
#import "Parent+Protected.h"
#implementation Parent
#end
Using other files for new class
#interface ObjCChild : Parent
#end
#import "Parent+Protected.h"
#implementation ObjCChild
-(void)spend {
self.money--;
}
#end
I am trying the same in swift
class SwiftChild : Parent {
override func spend () {
self.money--
}
}
Here only ObjCChild can spend money not swift child(Even it wont get money :) ). Can anyone help swift child.???
i am using custom UIView class in my project which is written in obj-c and now i want to bind delegate in swift class and how can i implement that in swift class.
When you add objective-c classes in swift project, you'll be prompted for
'Create bridging header' -> click on 'create bridging header'. Now you can use objective-c code in your swift.
In your Objective-C bridging header file, import every Objective-C header you want to expose to Swift.
In Build Settings, in Swift Compiler - Code Generation, make sure the Objective-C Bridging Header build setting under has a path to the bridging header file.
The path should be relative to your project, similar to the way your Info.plist path is specified in Build Settings. In most cases, you should not need to modify this setting.
For more detail refer
Modifying the solution as per your problem:
//Objective-c class
// Test.h
#import <Foundation/Foundation.h>
#protocol TestDelegate <NSObject>
- (void)testMethod;
#end
#interface Test : NSObject
#property (weak, nonatomic) id<TestDelegate> delegate;
#end
//Test.m
#import "Test.h"
#implementation Test
#synthesize delegate;
- (void)callDelegate
{
[delegate testMethod];
}
#end
//Swift bridging header
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//
#import "Test.h"
//Swift class
class ViewController: UIViewController, TestDelegate {
.
.
.
func testMethod() {
print("Delegate");
}
}
I'm writing some Swift classes that build upon functionality in our objective-c app. I have a objective-c class with a delegate that conforms to a protocol. I'm trying to call a method on that delegate from inside of a Swift class I'm simplified it down to this.
FredTestProtocol.h:
#protocol FredTestProtocol
- (void) dumbMethod;
#end
FredTestClass.h:
#import <Foundation/Foundation.h>
#import "FredTestProtocol.h"
#interface FredTestClass : NSObject <FredTestProtocol>
#property (nonatomic, weak) NSObject <FredTestProtocol> *delegate;
#end
FredTestClass.m:
#import "FredTestClass.h"
#implementation FredTestClass
- (void) dumbMethod
{
NSLog(#"Boy, this is a dumb method");
}
#end
FredSwiftClass.swift
import Foundation
class FredSwiftClass {
func test()
{
let ocObject = FredTestClass()
ocObject.delegate.dumbMethod() // Error occurs here.
}
}
The indicated line produces the error "'NSObject' does not have a method named 'dumbMethod'" I've tried a lot of ways to eliminate the error, to no avail. I'm sure I'm missing something really fundamental. Can someone tell me how I should go about calling the delegate method from Swift?
When Swift examines the property delegate it simply sees that is is an NSObject and the fact that you have noted that it implements a protocol is ignored. I can't find any specific documentation as to why this is the case.
You can address this in a couple of ways.
First, you can redefine your delegate property to use class anonymity, then Swift will just see it as some object that implements the protocol -
FredTestClass.h
#import <Foundation/Foundation.h>
#import "FredTestProtocol.h"
#interface FredTestClass : NSObject <FredTestProtocol>
#property id<FredTestProtocol> delegate;
#end
Then your Swift code will compile as written.
or you can leave your delegate definition as is and tell Swift that you want to access the delegate as an instance of an object that implements the protocol via downcast -
FredTestSwift.swift
import Foundation
class FredSwiftClass {
func test()
{
let ocObject = FredTestClass()
let theDelegate=ocObject.delegate as! FredTestProtocol
theDelegate.dumbMethod()
}
}
Pretty sure I've got it.
func test()
{
let ocObject = FredTestClass()
if let myDelegate = ocObject.delegate as? FredTestProtocol
{
myDelegate.dumbMethod()
}
}