Call custom Objective-C methods in Swift? - objective-c

I'm currently taking several Swift classes online to figure this new syntax out, but I feel like I've run into a wall that I can't really figure out.
My question is: What do I need to do to call custom Objective-C methods inside Swift? Why doesn't Swift recognize where the code is coming from? Why do I get errors like, "UIViewController does not have a member named 'customMethod'"? Is it an import problem?
Now that you know my question, here is why I'm asking and the background
I have an objective-c .m file that calls this method:
- (void)configureMyApp
{
// overridden by subclasses
}
Then this one:
- (void)addAppElement:(MyAppElement *)element
{
[self addAppElement atIndex:[self.elements count]];
}
In my Swift app I've set up the bridging header and imported the .h file into said header file
I attempted calling the configureMyApp method through this Swift function:
func configureMyApp()
{
self.addAppElement...
}
but it doesn't recognize that function as coming from my imported objective-c file, and neither does myswiftfile.swift recognize addAppElement
The way I would call it in obj-c would be this:
- (void)configureMyApp
{
[super configureMyApp];
[self addAppElement:.....];
}
Is there anything else I need to do to import the obj-c code? What could I be missing?

This error: UIViewController does not have a member named 'customMethod' indicates that you're trying to call customMethod on an object typed as UIViewController, not as your custom subclass of UIViewController.

Related

Calling an Objective-C function defined in a .h file from Swift

I want to call this Objective-C function from Swift code.
The accepted answer on this question shows how to use an Objective-C class in Swift, not a function. Secondly, the Objective-C implementation in it is contained in a .m file, while the one I have linked above is a .h file.
What is the easiest way I can call an Objective-C function defined in a .h file from Swift?
As mentioned in the comments first you'll need to do all the usual steps for using Objective-C classes from Swift (bridging header, etc.) Then you'll already be able to call your function and you'd only need a bit of tweaking to make it more usable in Swift.
func CopyLaunchedApplicationsInFrontToBackOrder_Swift() -> [[String: AnyObject]]? {
guard let cfarray = CopyLaunchedApplicationsInFrontToBackOrder() else {
return nil
}
let array = unsafeBitCast(cfarray, to: NSArray.self) as [AnyObject]
guard let result = array as? [[String: AnyObject]] else {
return nil
}
return result
}
If your function is implemented in .h file it would be better to move implementation into a corresponding .m file leaving in .h only it's declaration:
#import Foundation;
CFArrayRef CopyLaunchedApplicationsInFrontToBackOrder(void);
It's also possible to put this declaration into your bridging header and leave implementation in the .h file, but that would be unusual making your code more error prone and harder to maintain.

Can't access properties of swift 4 class from objective-c

I've seen a lot of questions and answers on this, but none of them seem to cover or solve my situation.
I have a project originally written in Objc, and now, one by one, I'm replacing all classes with Swift 4 syntax.
My problem is, that I cannot access swift properties in my Objective C files.
This is what I have so far:
I have this one swift file, called MessagesViewController.swift that starts as follows:
#objc class MessagesViewController: UIViewController, UITableViewDataSource, UITableViewDelegate{
#objc var mailboxNumber:NSNumber = 0
...
Then, in there is the objc class "MessagesBoxController" that needs to access mailboxNumber in the prepareForSegue method:
So, in MessagesBoxController.h I import the generated interface header:
#import "myProduct-Swift.h"
and in MessagesBoxController.m I have this boilerplate method:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
MessagesViewController *destViewController = segue.destinationViewController;
NSIndexPath *selectedIndexPath = [_tv indexPathForSelectedRow];
destViewController.mailboxNumber =selectedIndexPath.row+1;
}
So, the Swift class "MessagesViewController" is recognised fine; no complaints by the compiler whatsoever. Its properties though are not exposed:
auto complete doesn't suggest mailboxNumber and upon building the project, I get the error
"Property 'mailboxNumber' not found on object of type
'MessagesViewController *'"
What part is missing to make this work?
OK,
So, the basic setup is correct.
I ended up cleaning the project. I then got the message that "myProduct-Swift.h" could not be found.
Then I quit XCode and deleted the derived data. That helped.

UIView instancetype from Obj-C at Swift

Hello everyone I'm getting close to programming Swift then feel right away that I'm new to Swift
In my project in Obj-C I created many classes UIView that I used in my app
I have a problem with the implementation of these classes UIView from Obj-C for Swift ...
In short, until now I have always used this...
My class UIView had various init with frame etc ... but a directly instancetype that elaborated all
-(instancetype)initializeNotificationViewWithTitle:(NSString *)notificationTitle
notificationMessage:(NSString *)notificationMessage
notificationType:(UTNotificationType)notificationType
notificationMode:(UTNotificationMode)notificationMode
now I can not fit it in Swift many of you surely know that Swift is the most simple of Obj-C but I still can not adapt
You can make me understand how to implement this function I posted this in Obj-C Swift ?
The method you provided looks like a simple init method and init method in swift looks like
init(title: String, message: String, type: UTNotificationType, mode: UTNotificationMode) {
//init
}
and use it as
let aView = NotificationView(title:"title", message:"message", type: someType, mode: someMode)

Can Objective-C code call Swift class extensions?

I searched some posts, I think I cannot write an extension under Swift, and call it from Objective-C code, right?
#objc like attributes only support methods, class, protocols ?
You can write a Swift extension and use it in Objective-C code. Tested with Xcode 6.1.1.
All you need to do is:
create your extension in Swift (#objc annotation needed since Swift 4.0.3)
#import "ProjectTarget-Swift.h" in your Objective-C class (where "ProjectTarget" represents the XCode target the Swift extension is associated with)
call the methods from the Swift extension
I found out that in Swift 4.0 I had to add #objc in front of my extension keyword in order for the Swift extension methods to become visible by an instance of the Objc class I was extending.
In short:
File configuration setup:
CustomClass.h
CustomClass.m
CustomClassExtension.swift
In CustomClassExtension:
#objc extension CustomClass
{
func method1()
{
...
}
}
In my AppDelegate.m:
self.customClass = [[CustomClass alloc] init];
[self.customClass method1];
This solution works for Swift 2.2 and Swift 3. Note that only extensions for classes (not for structs or enums) will be accessible from Objective-C.
import UIKit
extension UIColor {
//Custom colours
class func otherEventColor() -> UIColor {
return UIColor(red:0.525, green:0.49, blue:0.929, alpha:1)
}
}
Then #import "ProductModuleName-Swift.h" in your ObjC file.
Swift 4
extension UIColor {
// As of Swift 4.0.3, the #objc annotation is needed if you want to use the extension in Objective-C files
#objc
class func otherEventColor() -> UIColor {
return UIColor(red:0.525, green:0.49, blue:0.929, alpha:1)
}
}
As covered in the other answers, importing the generated Swift header works in most cases.
An exception to this is when the category is defined on a bridged type (i.e. the extension is defined on String and not NSString). These categories will not automatically be bridged to their Objective-C counterparts. To get around this, you'll either need to use the Objective-C type (and cast the return value in your Swift code with as String) or define an extension for both the Swift and Objective-C types.
Import "#import "ProductModuleName-Swift.h" header in objective-c file and add #objc infront of your extentsion in swift file. It will working fine in swift 4.2 and swift 5
If think you have configured everything correctly (marked your Swift entities with #objcMembers or #objc, imported the bridging header "ProductModuleName-Swift.h" and so on) – but still getting the No visible #interface for 'FooClass' declares the selector 'fooSelector' error:
Check if you see your interfaces in the bridging header by ctrl + cmd clicking on it. If you don't, check out my answer to this question: Swift to Objective-C header does not contain Swift classes

What is the correct way of accessing a Swift Delegate from Objective-C?

Environment: Xcode 6.1.1 & Xcode 6.2 Beta
Greetings:
I need to publish a NSString within a Swift doc from a neighboring Objective-C doc within the same project. For example, display "Hello World" generated in Objective-C upon a Swift page. I've made a proof-of-concept demo; based on feedback.
I'm thinking of using an ObjC --> Swift delegate via a protocol pattern as shown below:
Note: the Swift file is the delegate.
Here I'm calling the delegate method in Swift, from Objective-C:
#pragma mark - Action methods
- (IBAction)sendDelegateAction:(UIButton *)sender {
[_delegate radiusString:#"Hello World"];
}
I've instantiated the Objective-C file to link the delegate to the instance (I hope I got it right):
let geo32Controller = MyObjCTableViewController()
geo32Controller.delegate = self
So far, the compiler complained that the Swift protocol couldn't be found.
Here's the protocol (declared in Swift):
#objc protocol DiscoveryContributeProtocol {
// optional
func radiusString(radiusString:String)
}
And here's the delegate reference to that protocol in the Objective-C header file:
#interface MyObjCTableViewController : UIViewController<UITableViewDelegate, UITableViewDataSource>
#property (nonatomic, weak) id<DiscoveryContributeProtocol> delegate;
#end
However, the compiler can't find the protocol:
BTW: when I put the bridge reference in the ObjC's header file, I get a compiler error:
Two Questions:
Do I have the correct pattern (did I instantiate the ObjC correctly) ?
How do I make the Objective-C portion see the Swift protocol for the delegate link?
You have the right idea, but have a few bugs that are preventing this from working.
You've declared Geo32Boundaries as conforming to the DiscoveryContributeProtocol, but it doesn't need to and doesn't actually implement it, it only has a property that conforms to that protocol. That's the source of the "Method 'radiusString:' not implemented" error:
#interface Geo32Boundaries: UIViewController // <-- that's all you need
You're setting the delegate incorrectly -- the code you have there looks like it's trying to set a class instance of Geo32Boundaries to self, but you're also trying to call it like a function. You'll need to set the delegate on a the instance of the Geo32Boundaries view controller that is being presented to the user. I don't know where that code lives, so I can't give a great example, but it'll be something like:
geo32Controller.delegate = self
Lastly, though not a bug, your protocol should really be called DiscoveryContributeDelegate -- we usually don't use "protocol" in the protocol name.