Inheritance from an Objective-c base view controller from Swift - ios

I am trying to migrate a UIViewController Objective-C class to Swift. This view controller is inheriting from a BaseViewController where I have common functionality that I want to have in all controllers. The problem I am having is that the generated myproject-Swift.h is not able to find my BaseViewController.
Is there any way to implement a UIViewController in swift that inherits from a BaseViewController (subclass of UIViewController) written in Objective-C? Is there a bridging problem?
It can be reproduced with this minimal code:
BaseViewController.h
#import <UIKit/UIKit.h>
#interface BaseViewController : UIViewController
#end
BaseViewController.m
import "BaseViewController.h"
#implementation BaseViewController
#end
ViewController.swift
import UIKit
class ViewController : BaseViewController {
}
AppDelegate.m
#import "AppDelegate.h"
#import "projectname-Swift.h" // Replace with your project name
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
ViewController *vc = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
self.window.rootViewController = vc;
[self.window makeKeyAndVisible];
return YES;
}
projectname-Bridging-Header.h
#import "BaseViewController.h"

As pointed out in the accepted answer on How can I add forward class references used in the -Swift.h header?
Interoperability guide (Importing Swift into Objective-C):
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.
The example is solved by importing BaseViewController before the importing projectname-Swift.h in:
AppDelegate.m
#import "AppDelegate.h"
#import "BaseViewController.h"
#import "projectname-Swift.h" // Replace with your project name
// ...

It looks like they have fixed the issue. Currently under XCode6-Beta6 the problem reported by #atxe does not occur anymore. Therefor you can finally roll your AppDelegate.m header back to:
#import "AppDelegate.h"
#import "projectname-Swift.h" // Replace with your project name

Related

Inherit from a Swift class in Objective C

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

cannot find protocol declaration for ''

I have searched for related questions, but nothing has worked for me so I will describe my problem. I have two classes. Lets call them ClassA and RootViewController. RootViewController has a button that will trigger an action and delegate it to ClassA. The header for RootController looks like this:
#import <UIKit/UIKit.h>
#protocol RootViewControllerDelegate;
#interface RootViewController : UIViewController <UIPageViewControllerDataSource> {
}
...
#end
#protocol RootViewControllerDelegate <NSObject>
-(void)buttonPressed : (UIButton *) button;
#end
The ClassA header looks like this:
#import "RootViewController.h"
#interface RightPanelViewController : UIViewController <RootViewController>
...
#end
And I get the error :"Cannot find the protocol declaration for 'RootViewController'. Like I said, I have read some questions related to the same topic, the documentation for delegates, but I'm not able to see what the problem is. I would appreciate some help on this matter.
Change your interface line to
#interface RightPanelViewController : UIViewController <RootViewControllerDelegate>
ie. the name in angle brackets must match exactly with the name in your #protocol definition.

Using Protocol with Objection to get instance of object

I am new to objective C and trying to implement objection (dependency injector).
But its not working below is the code i am using
My Protocol File
#import <Foundation/Foundation.h>
#protocol InfoquestProtocolTest <NSObject>
-(void):nothing;
#end
My .h file is below
#import <Foundation/Foundation.h>
# import "InfoquestProtocolTest.h"
#interface InfoquestImplementation : NSObject<InfoquestProtocolTest>
#end
my .m file implementing protocol
#import "InfoquestImplementation.h"
#implementation InfoquestImplementation
-(void):nothing{}
#end
Code for module file of objection
#import "InfoquestTestConf.h"
#import <Objection/Objection.h>
#import "InfoquestViewController.h"
#import "InfoquestImplementation.h"
#implementation InfoquestTestConf
-(void)configure
{
[self bindClass:[InfoquestImplementation class] toProtocol:#protocol(InfoquestProtocolTest)];
}
#end
Code for getting object from objection
JSObjectionInjector *injector = [JSObjection createInjector];
[JSObjection setDefaultInjector:injector];
InfoquestTestConf *Module = [[InfoquestTestConf alloc] init];
[injector withModule: Module];
id<InfoquestProtocolTest> testing2 = [injector getObject:[#protocol(InfoquestProtocolTest)];
But when i try to call using [testing2 nothing]; i am getting error and autocomplete doesnt show up nothing.
Thanks
gaurav
You have a syntax error:
You should replace:
-(void):nothing;
with
-(void)nothing;
here is an error in your syntax.please change :
-(void):nothing;
to:
-(void)nothing;
Hence you are using custom delegates. So first you have to set the delegate to your class where you are implementing the method of your protocol.

Declare project wide variable in Objective C

I was wondering if there is a way to declare a project wide variable like you get when you start a application with a UINavigationController and you can call that navigation controller from anywhere in you application because of how its been declared in the applications Delegate.
I am wanting to create a project (global) var that allows me to call SVProgress hud or dismiss it from anywhere in my application. I have this issue where I load a UIViewController onto the navigation stack, start the SVProgress hud then make a request to my DB.. if I get an error back i need to handle a few things one of them is to be able to dissmiss the SVProgress hud.
This is the code I have so far
AppDelegate.h
#import "SVProgressHUD.h"
#interface MYAPPAppDelegate : UIResponder <UIApplicationDelegate> {
//..
}
#property (strong, nonatomic) SVProgressHUD *svprogressHud;
AppDelegate.m
#synthesize svprogressHud;
not really sure if this is possible hopefully someone out there will be able to help me out.
Here is a link to SVProgress git
One thing you can do from your view controller is grab the app delegate and cast it to the type of your delegate like so:
#import "MYAPPDelegate.h"
MYAPPDelegate *ad = (MYAPPDelegate *)[[UIApplication sharedApplication] delegate];
[ad.svprogressHud displayOrWhatever];
Not really the cleanest but should get the job done.
Just add the header file name into you pre-compiled header (<projectname>_Prefix.pch) file inside of the #ifdef __OBJC__
Like as:
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import "SVProgressHUD.h"
#endif
Then it will give you access to the file across all files.....
Just extending Roberts answer, In order to avoid repeating the code to get the app delegate and then cast it into MYAPPDelegate, I would create a header file/class in your project with a utility function.
Create new header called AppUtils.h
#import "MYAPPAppDelegate.h"
#ifndef AppName_AppUtils_h
#define AppName_AppUtils_h
static inline MYAPPAppDelegate* AppDelegate() {
return (MYAPPDelegate *)[[UIApplication sharedApplication] delegate];
}
#endif
Where ever you need access to these variables import the header AppUtils.h and use the helper function. Example:
#import "AppUtils.h"
...
- (void)foo {
// use app delegate
UIViewController *rootVC = AppDelegate().rootViewController;
}

linking a static library in ios

I have created a math based application in Xcode 4.4. I am using tabbar based app with the help of storyboard.
I have written all my math functions in a separate class called CalculationMethods which is the subclass of NSObject.
My ViewController:
// FirstViewController.h
#import <UIKit/UIKit.h>
#import "CalculationMethods.h"
#interface FirstViewController : UIViewController
#end
// FirstViewController.m
#import "FirstViewController.h"
#import "CalculationMethods.h"
#interface FirstViewController ()
#end
#implementation FirstViewController
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"%f",[self julianDateFinder: [self currentDayMonthAndYearFinder]]);
}
#end
As you can see I have included my CalculationMethod.h file in both FirstViewController.h and the FirstViewController.m file, but when I use the methods of that class such as julianDateFinder and currentDayMonthAndYearFinder, Xcode errors, saying:
"No Visible #interface for 'FirstViewController' declares the selector 'CurrentDayMonthAndYearFinder'"
I am new to iOS and XCode. Can anyone help me solve the error?
In the FirstViewController, to use any of the methods in the CalculationMethods class, you need to create an instance of CalculationMethods. And then access a method using this syntax: [instanceOfCalculationMethods aMethodInCalculationMethods];
For example in your case, try this:
In the FirstViewController.h file, before the #end:
CalculationMethods *_calculationMethods;
And in the viewDidLoad method:
_calculationMethods = [CalculationMethods alloc] init];
NSLog(#"%f",[_calculationMethods julianDateFinder: [_calculationMethods currentDayMonthAndYearFinder]]);
I think you're misunderstanding how Objective C works slightly.
Without adding details of the CalculationMethods.h header file I can't help you much, but that compiler warning is telling you that FirstViewController doesn't have the method currentDayMonthAndYearFinder.
The reason that this is the case is because you're calling performing the selector CurrentDayMonthAndYearFinder on self which in the context of your FirstViewController instance is in fact the instance of FirstViewController
You said it yourself that your method CurrentDayMonthAndYearFinder is on your CalculatorMethods class so I suggest you either create an instance of your CalculatorMethods class or call the class method named CurrentDayMonthAndYearFinder on your CalculatorMethods class.
The problem here is weather or not you've defined instance methods or class methods.
Do yourself a favour and update your question with the contents of CalculationMethods.h

Resources