Swift: Override Objective-c extension (anonymous) properties from subclass - ios

I've spent quite a bit of time figuring this out..and haven't found any success.
Put simply, I need a swift subclass of an objective c class to be able to override a certain property declared in the .m file inside of an extension. How would I do this? Essentially the property needs to be replaced with a custom subclass.
#interface SomeClass : NSObject
{
}
#end
//SomeClass.m
#interface SomeClass ()
#property (nonatomic, strong) UIScrollView scrollView;
#end
//Swift class
class NewClass: SomeClass {
let scrollViewSubclass = MyScrollView()
override var scrollView: UIScrollView! {
return scrollViewSubclass
}
}
Something like that.. just not sure how to do it. I can't even override scrollView because the swift subclass doesn't know it exists!

Related

call swift delegate in obj-c

I am trying to port an old obj-c application to swift, and in the process restructure and reprogramm everything. Some things need to be portet at a later point and I have to use old obj-c in swift, which isn't a problem, but I ran into a serious issue which seems like i cannot solve.
I have a obj-c "connection" class which is called from a swift wrapper. The problem is, i cannot pass the delegate object to obj-c or at least i dont know how.
Here is my code:
//swift protocol
#objc protocol ConnectionDelegate
{
#objc func connected() -> Void
}
//swift class
#objc class ConnectionManager : NSObject, ConnectionDelegate
{
var connectionThread : ConnectionThread
init(){
connectionThread.inti()
connectionThread.registerDelegate(self) //Value of type 'ConnectionThread' has no member of 'registerDelegate'
connectionThread.testFunc() //all ok
}
#objc func connected(){
}
}
//obj-c header ConnectionThread.h
#class ConnectionDelegate;
#property (nonatomic, weak) ConnectionDelegate* delegate;
-(void) registerDelegate: (ConnectionDelegate*) delegate;
-(void) testFunc;
//obj-c class ConnectionThread.h
#import ".....Swift.h"
#synthesize delegate;
-(void) registerDelegate:(ConnectionDelegate*) delegate
{
self.delegate = delegate;
}
-(void) testFunc
{
}
In the future, please copy and paste your actual code into your question. The code in your question is full of errors, which means it isn't your real code, and those errors might make it impossible to answer your question correctly.
So, assuming you haven't made too many errors in the code you posted, the problem is that you are lying to the compiler. Specifically, your Objective-C header file ConnectionThread.h says this:
#class ConnectionDelegate;
But ConnectionDelegate is not a class. It is a protocol, so you need to declare it as a protocol. Then you will also have to use the proper Objective-C syntax for a type that conforms to the protocol, which is id<ConnectionDelegate>.
// ConnectionThread.h
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
#protocol ConnectionDelegate;
#interface ConnectionThread : NSObject
#property (nonatomic, weak) id<ConnectionDelegate> delegate;
- (void)registerDelegate:(id<ConnectionDelegate>)delegate;
#end
NS_ASSUME_NONNULL_END
// ConnectionThread.m
#import "ConnectionThread.h"
#implementation ConnectionThread
- (void)registerDelegate:(id<ConnectionDelegate>)delegate {
self.delegate = delegate;
}
#end

Override property with different type

I want to implement the approach used by UITableView.
I have subclass UITableView with my own class FloatingTableView I want to override the delegate of UITableView which is UITableViewDelegate with my delegate of type FloatingTableViewDelegate just the way UITableView inherit from UIScrollView and override the UIScrollViewDelegate with UITableViewDelegate both class have same property with name delegate but have different types.
I have also tried to inherit my protocol with UITableViewDelegate
But when i try to create property with name delegate of type FloatingTableViewDelegate I get this error..
Property 'delegate' with type 'MyTableViewDelegate?' cannot override a
property with type 'UITableViewDelegate?'
Here is my sample code.
protocol MyTableViewDelegate: UITableViewDelegate {
func isDemoDelegateMethod()
}
class MyTableView: UITableView {
weak var delegate: MyTableViewDelegate?
}
The way it works for Objective C is because of the dynamic nature of the language. You can redeclare the type of super class and instead of synthesizing the property you would make it a dynamic type, which would let you redeclare it.
#protocol MyTableViewDelegate<UITableViewDelegate>
- (void)demoDelegateMethod;
#end
#interface WrapperTableView: UITableView
#property (nonatomic, weak, nullable) id <MyTableViewDelegate> delegate;
#end
#implementation WrapperTableView
#dynamic delegate;
#end
But, I doubt this would be possible with Swift, since, you are changing the type completely. It is because of Swift being strong static language.
Answer Edited
I got your approach. I write above approach in Objective-C and then inherit this class in Swift.
So if I have to override SuperClass property with different type I need to create a wrapper class in Objective-C inherit from desired SuperClass and then finally instead of inheriting directly from desired super class I should inherit from the newly created WrapperClass which is written in Objective-C
class MyTableView: WrapperTableView {
//Now Here the delegate object is of type MyTableViewDelegate
}
This approach is far better then
class MyTableView: UITableView {
private var myDelegate: MyTableViewDelegate?
override var delegate: UITableViewDelegate {
set{
myDelegate = newValue
}
get{
return myDelegate
}
}
}

Objective-C Bridging Header Not Working for Swift File

I am trying to migrate my project to Swift, and started by making an Objective-C Bridger File filled with #imports to relevant .h files. I've checked exhaustively that the Build Settings options and path are correct. I created a Swift file for a UITableViewController that looks something like this:
TableViewController.swift
class TableViewController {
var title: String = ""
var summary: String = ""
override init(style: UITableViewStyle) {
super.init(style: style)
}
override func viewDidLoad() {
super.viewDidLoad()
title = UIResources.getString(settingsKey, withSuffix: "title")
summary = UIResources.getString(settingKey, withSuffix: "summary")
}
...
}
However, every line starting with the first override result in errors like
Initializer does not override a designated initializer from its superclass
and
'super' members cannot be referenced in a root class
I'm pretty unfamiliar with working with Objective-C, so I'm not sure what I need to change, if anything. Here is the .h file of the class I imported in the bridging header also. I'm really stumped on this one.
TableViewController.h
#import <UIKit/UIKit.h>
#class TableViewController
#protocol TableViewControllerDelegate <NSObject>
- (void) tableViewControllerDidSave: (UIViewController *)controller forKey:(NSString *)key withNewValue:(id) value;
#end
#interface TableViewController : UITableViewController
#property (strong, nonatomic) id <TableViewControllerDelegate> delegate;
#property (strong, nonatomic) NSString *settingKey;
#property (strong, nonatomic) id stringValue;
#end
I didn't realize I needed to add the type to the class definition
class TableViewController : UITableViewController, TableViewControllerDelegate {
That's what you get when you blind trust objectivec2swift.com :P
I also added the variables and protocol outlined in the .h file to the Swift file.

Calling a Method on an Objective-C Delegate from Swift

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()
}
}

Can I force protocol conformation in Swift?

I'd like to do this:
UIView <UITextFieldDelegate>*
in swift.
Making an object that subclasses UIView also conform to the UITextFieldDelegate protocol.
You can express (id <UITextFieldDelegate, UIScrollViewDelegate>) using Protocol Composition
but not (UIView<UITextFieldDelegate> *). except for class definition.
// Obj-C
- (void)methodName:(id <UITextFieldDelegate, UIScrollViewDelegate>)arg { ... }
// Swift
func methodName(arg:protocol<UITextFieldDelegate, UIScrollViewDelegate>!) { ... }
Actually, an Obj-C method declared as - (void)methodName((UIView<UITextFieldDelegate> *))arg;, when it's bridged to Swift, you can call with any UIView instance.
EDIT:
After a little research, it seems you can declare your func like this
func myFunc<T:UIView where T:UITextFieldDelegate>(view:T) { ... }
Make a sub class of UIView and let the SubClassedView conforms to UITextFieldDelegate
In traditional way
#interface SubClassedView:UIView <UITextFieldDelegate>
#end
in swift
class SubClassedView:UIView, UITextFieldDelegate {
}

Resources