Objective-C can't find Swift protocol - objective-c

This question is basically the same as this one, but that one went unanswered.
TL;DR: Protocol does not show up in MyProject-Swift.h secret bridging file. And so (not unexpectedly) the Obj-C code can't find it.
I have been able to duplicate it in a from-scratch project. Here is what I did.
Create new one-view iOS Objective-C project.
Add a new Swift UIView subclass via "New File" menu.
Confirm that MyProject-Bridging-Header.h was created. (Visibly)
Confirm that the secret MyProject-Swift.h file was automatically created. (Way down there in DerivedData/.../DerivedSources).
Add an instance of this View to my ViewController.m.
Include the MyProject-Swift.h file in ViewController.m.
Successfully build -- sanity check
Now for the weirdness...
Add a Swift protocol file via "New File" menu.
Make ViewController conform to and implement this protocol.
Build fails at this spot in ViewController.m:
#import "MyProject-Swift.h"
#interface ViewController () <MyProtocol> // Can't find protocol declaration
Examining the MyProject-Swift.h file confirms that the protocol is not in there. But poking around some big pre-existing hybrid projects (that do build) I don't see any protocols in any of their -Swift.h files.
How do Swift protocols get recognized in Objective-C?

I have done this for my project
while defining protocol you can add #objc before the protocol definition
#objc protocol NewViewControllerDelegate {
}
And you are done
Note : I think #objc makes swift protocols and classes visible to objective c

Related

How to temporarily disable Swift to Objective-C bridging header auto-generation?

Background
Let's say project App is a 50/50 mixed Swift/Objective-C codebase.
Objective-C files import some Swift via auto-generated "App-Swift.h" file.
#import "App-Swift.h"
Recap on How it Works
"App-Swift.h" file automatically includes all the Swift's classes inherited from Objective-C ones: NSObject, UIView, UITableViewCell, UIViewController, etc; and of course all the #objc and #objcMemmbers attributed things.
The Issue
When anything is added to the "App-Swift.h" - all the Objective-C files that import it - have to be recompiled. Even if what was added to Swift is actually not used in any of Objective-C files, but we just inherited from, e.g., UIView.
It all adds up when you import "App-Swift.h" into many files and it slows you down.
Possible Proper Solutions
Break down the codebase into small modules, so interface segregates; avoid NSObject inheritance; Convert as much Objective-C to Swift as possible; private all #IBOutlet, #IBAction during development; etc.
The Question: Cutting a Corner
Is there a way to disable Swift to Objective-C bridging header ("App-Swift.h") auto-generation (but keep the last generated App-Swift.h) at least manually via any of Swift compiler flags?
Any other quick win ideas here?
Related References Revised
Swift and Objective-C interoperability
https://dmtopolog.com/code-optimization-for-swift-and-objective-c/
https://swift.org/blog/bridging-pch/
https://developer.apple.com/documentation/swift/imported_c_and_objective-c_apis/importing_swift_into_objective-c
Going into modules
https://blog.griddynamics.com/modular-architecture-in-ios/
https://www.bignerdranch.com/blog/it-looks-like-you-are-trying-to-use-a-framework/
https://www.bignerdranch.com/blog/it-looks-like-youre-still-trying-to-use-a-framework/

How do I call Swift code from Objective-C in a Framework target?

When you add a Swift file to an Objective-C project, Xcode will generate a Swift-to-ObjC header, as described here: http://ericasadun.com/2014/08/21/swift-calling-swift-functions-from-objective-c/
Without this header it is not possible to call Swift code from Objc-C. However Xcode is not auto-generating this header for my framework target.
If I create an Objective-C app and drop a Swift file into it, then it does auto-generate one, so I suspect it's because I'm building a framework and not an app. Without one its not possible to use the Swift code from the Obj-C code.
I tried using the one which was generated for the app (after renaming it and putting it in the appropriate DerivedData folder ) but Xcode didn't update it and actually it will eventually delete it, so manually creating or trying to maintain this file is not feasible.
How can I make Xcode generate this header for a framework target, so that I can call my Swift code from my Obj-C code?
And remember folks: the question is about calling Swift from Obj-C not calling Obj-C from Swift.
I created a new Framework project, added both Obj-C and Swift files, and was able to do this:
// MyObjCClass.m
#import "MyObjCClass.h"
#import <MyFramework/MyFramework-Swift.h>
#implementation MyObjCClass
- (void)test {
[[MySwiftClass alloc] init];
}
#end
Note that your Swift class must be public:
public class MySwiftClass: NSObject {
// ...
}
More information is available in Apple's Swift/Obj-C interop documentation under "Importing Swift into Objective-C".

Auto-generated "ModuleName-Swift.h" header not including Swift classes

I am trying to reference some Swift-defined classes from my Objective-C implementation file, but for some reason, though I've gotten the header file to auto-generate, it doesn't appear to be including any information about the Swift classes in the project.
My Swift class is attributed with #objc yet even after importing the "-Swift.h" file, I still get a "Use of undeclared identifier" error when compiling.
I can't figure out what I'm missing. I have Defines Modules set to YES in the project.
Also of note: if I command-click the symbol from my Obj-C file, Xcode successfully finds the definition in the Swift file.
Make sure in build setting you have got this setup:
Objective-C Bridging Header : $(SRCROOT)/Sources/SwiftBridging.h
Sometime when you import a swift file directly Xcode don't prompt you to add a bridging header. it's a must have step even you don't call objective-c from swift.
You may need to derive from NSObject.
I encountered a similar situation where some Swift classes were not being exposed to Obj-C through the auto generated header. The solution is to derive Swift classes from NSObject.
class SwiftClassNotInHeader { }
class SwiftClassInHeader : NSObject { }
From MyApp-Swift.h
SWIFT_CLASS("_TtC6Server18SwiftClassInHeader")
#interface SwiftClassInHeader : NSObject
- (SWIFT_NULLABILITY(nonnull) instancetype)init OBJC_DESIGNATED_INITIALIZER;
#end
SwiftClassNotInHeader is not in myApp-Swift.h

How to prevent circular reference when Swift bridging header imports a file that imports Hopscotch-Swift.h itself

I am integrating Swift into a large existing Objective C project and have run into what I think is a circular reference.
The classes in question are as follows:
Objective C Controller
#import "Hopscotch-Swift.h"
#interface MyController : UIViewController<MyProtocol>
...
#end
Swift Protocol
#objc protocol MyProtocol: NSObjectProtocol {
...
}
Bridging Header
#import "MyController.h"
This code fails to compile because the Hopscotch-Swift.h file will not generate.
I think this is due to a circular reference error as I can import Hopscotch-Swift.h into objective c headers that are not included in Hopscotch-Bridging-Header.h and it works fine.
Is there a workaround for this issue or should I file a radar with Apple?
Forward declaration should work, in your case.
In your .h:
#protocol MyProtocol;
#interface MyController : UIViewController<MyProtocol>
#end
In your .m:
#import "HopScotch-Swift.h"
From How can I add forward class references used in the -Swift.h header? and the Swift interoperability guide:
If you use your own Objective-C types in your Swift code, make sure to import the Objective-C headers for those types prior to importing the Swift generated header into the Objective-C .m file you want to access the Swift code from.
I ran into this when trying to use Swift classes inside Objective-C protocols, where the protocol was also implemented by another Swift class. It reeked of circular references and I guessed that it might be a problem trying to circularly generate the bridging headers, rather than a 'normal' circular include problem.
The solution, for me, was to just use forward declarations before the protocol declaration:-
// don't include the MyProject-Swift.h header
// forward declaration of Swift classes used
#class SwiftClass;
#protocol MyProtocol <NSObject>
- (SwiftClass *)swiftClass;
#end
The forward declaration by itself didn't work for me. It compiled without errors but still had warnings that the protocol couldn't be found. I treat all warnings as errors, so this isn't good enough.
I was able to fix it by moving the protocol implementation into another category header.
So here's what worked for me:
In my MyOtherSwiftFile.swift:
#objc protocol MyProtocol: class {
func viewController(didFinishEditing viewController: MyViewController)
}
In my MyViewController.h:
#interface MyViewController // Removed protocol implementation declaration here
#end
Added MyViewController+MyProtocol.h to project, and put this in there:
#interface MyViewController (MyProtocol) <MyProtocol>
#end
The methods themselves can stay where they are if you want.
After you implement the above and compile, you'll get compiler warning(s) somewhere in your code that requires that MyViewController implements MyProtocol. In that file, you will #import "MyViewController+MyProtocol.h"
Alternatively you can convert your protocol to an Objective-C protocol MyProtocol.h and then use it in Swift by including MyProtocol.h in your bridging header.
You could something like this in the .h file you suspect to trigger the circular reference:
#ifndef MY_HEADER_H
#define MY_HEADER_H
your header file
#endif

XCode Throwing Errors #implementation

I'm trying to learn some of the basics of developing OS X apps with XCode and Objective-C, but I am already running into problems.
I have a project I made from a while back which worked very well for me, however, when I try to replicate the results I had last time, I run into numerous errors.
I have two files, a .c and a .h named "AppDelegate"
in AppDelegate.h:
#import <Cocoa/Cocoa.h>
#import <WebKit/WebView.h>
#interface AppDelegate : NSObject {
IBOutlet WebView *gameFrame;
}
#end
then, in AppDelegate.c:
#import "AppDelegate.h"
#implementation AppDelegate
-(void)awakeFromNib
{
}
#end
In IB, there is an NSObject named 'AppDelegate' and its class is 'AppDelegate'.
However, when I try to run this, I get 11734 errors...
When I click on the error icon at the bottom of the XCode window, it lists a bunch of code that seems to be involving NSStrings, but I cant make any sense of it...
Also, within my code, the
#end
line in both the .c and the .h are highlighted with an error saying:
'Expected identifier or '(' before '#' token.'
I don't understand what XCode is tripping up on when it tries to compile, I don't see any logical place for a '(' to go and I don't think I left anything unidentified.
Any help would be appreciated.
That's because that isn't valid C code.
You named your module file AppDelegate.c, which indicates that it contains source code written in (more or less) pure C. But it does not: You wrote a class interface and implementation in Objective-C, which is a superset of C (all C is valid Objective-C, but not all Objective-C is valid C—in particular, classes aren't).
For this, you must name the module file AppDelegate.m (or anything else, as long as it ends with .m; naming it after the class is a convention worth following). The .m suffix indicates a module (usually containing a class implementation) written in Objective-C.
So, just rename your module file from AppDelegate.c to AppDelegate.m. Make sure you do this in Xcode, not the Finder: If you do it in the Finder, Xcode will only care that there is no longer a file named AppDelegate.c; it won't notice the rename.
For your convenience in creating future classes, Xcode provides a template in the “New File” panel for creating subclasses of certain Cocoa classes; your AppDelegate should be a subclass of NSObject, and templates are also provided for NSView, NSDocument, UIView, UIViewController, and a few others. The files created by the template will already have the correct extensions.