Is it possible to go deeper than nearest superclass (i.e. super.super)? - objective-c

Assume that I want to skip one level in call super.viewDidLoad(), for example. So I wish to be able to do something like this:
override func viewDidLoad() {
super.super.viewDidLoad()
}
or
-(void)viewDidLoad {
[[super super] viewDidLoad];
}
This code will not compile. Is this possible by some other solution?

For expository purposes only, the following code does as requested. It only fails to crash when compiled without ARC, which means it has a bug in it. It does no error checking.
Never use this code unless you are playing around and trying to learn.
#import Foundation;
#import <objc/runtime.h>
#import <objc/message.h>
#interface M : NSObject
- (void)print;
#end
#implementation M
- (void)print { NSLog(#"M"); }
#end
#interface N : M
#end
#implementation N
- (void)print { NSLog(#"N"); }
#end
#interface O : N
#end
#implementation O
- (void)print {
Class mysupersuper = [[self superclass] superclass];
Method supersuperMethod = class_getInstanceMethod(mysupersuper, _cmd);
method_invoke(self, supersuperMethod);
}
#end
int main(int argc, char **argv)
{
O *o = O.new;
[o print];
return 0;
}
I compiled it using the command: clang -framework Foundation -fno-objc-arc -fmodules test.m.

Here is what you could do in Swift. Suppose you have classes A and B:
class A
{
func fun() { print("called fun() in A") }
}
class B : A
{
override func fun() { print("called fun() in B") }
}
You can't modify their definitions, but want to call fun() from A in a class C derived from B. You could do that as follows:
extension B
{
func funInA()
{
super.fun()
}
}
class C : B
{
override func fun() { funInA() }
}
I think you can pull off something like this in Objective-C using categories.

Related

Use delegate in objective c class to call swift method

I have two files
Question.m
Question.h
These two are written by Objective-C
MainView.swift
This is written by Swift
Question Class has the delegate
#interface Question : NSObject{
id delegate;// put MainViewController here
- (void)trythisfunction{
[delegate test] // compiler doesn't find this method.
}
}
and I make class instance and put MainViewController as delegate of Question in MainViewController.swift
class MainViewController: UIViewController {
override func viewDidLoad(){
q = Question()
q.delegate = self // put self in delegate
}
func test(){
NSLog("test is OK")
}
}
However Compiler found error [delegate test]
Question.m:169:19: No known instance method for selector 'test:'
How can I solve this??
You need to make few changes.
Below class declaration doesn't compile because you can't declare variables inside interface.
#interface Question : NSObject{
id delegate;
- (void)trythisfunction {
[delegate test]
}
}
I have fixed above and the class now looks like this,
# Question.h file
#import <Foundation/Foundation.h>
#interface Question : NSObject
#property (nonatomic, strong) id delegate;
#end
Below is the implementation of the class
# Question.m file
#import "Question.h"
#implementation Question
#synthesize delegate;
- (void)trythisfunction{
[delegate test];
}
#end
As we are integrating this swift and so we will need a Bridging Header whose content look like.
#import "Test.h"
Finally in your swift class now you can import this class
import UIKit
class MainViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let q = Test()
q.delegate = self
}
func test(){
NSLog("test is OK")
}
}
And above code works like a charm.

swift 3 _ObjectiveCBridgeable conformance

I am trying to make a swift 3 struct conform to _ObjectiveCBridgeable but I am not sure what else I need to satisfy the protocol. Below is my struct and the _ObjectiveCBridgeable conformance. I am missing something but I am not sure what it is.
struct Box {
let contents: Any
}
extension Box: _ObjectiveCBridgeable {
typealias _ObjectiveCType = thing;
init(fromObjectiveC source: _ObjectiveCType) {
contents = source.contents
}
static func _isBridgedToObjectiveC() -> Bool {
return true
}
static func _getObjectiveCType() -> Any.Type {
return _ObjectiveCType.self
}
func _bridgeToObjectiveC() -> Box._ObjectiveCType {
return thing(contents: self.contents)
}
static func _forceBridgeFromObjectiveC(_ source: Box._ObjectiveCType, result: inout Box?) {
result = Box(contents: source.contents)
}
static func _conditionallyBridgeFromObjectiveC(_ source: Box._ObjectiveCType, result: inout Box?) -> Bool {
_forceBridgeFromObjectiveC(source, result: &result)
return true
}
}
// Objc
#interface thing : NSObject
#property (readonly) id contents;
-(instancetype)initWithContents:(id)contents;
#end
#implementation thing
- (instancetype)initWithContents:(id)contents {
if ((self = [super init])) {
_contents = contents;
}
return self;
}
#end
As the underscore tells you, _ObjectiveCBridgeable is private. Its purpose is "to accommodate the specific needs of bridging Objective-C object types to Swift value types". You cannot adopt it for your own types; it works by means of "compiler magic under the hood".
There is a proposal on the table to provide a public version, but it has not yet been implemented.

Is it possible to declare an Objective-C method outside a class?

I know that you can declare a C function outside of a class, but is it possible to declare a Objective-C method outside of a class?
Example:
// Works
void printHelloC()
{
NSLog(#"Hello.");
}
// Error
-(void) printHelloOC
{
NSLog(#"Hello.");
}
int main (int argc, const char * argv[])
{
#autoreleasepool {
printHelloC();
[self printHelloOC];// 'self' obviously would not work but you get the idea
}
return 0;
}
It depends. You can do something similar with method adding at runtime:
#import <objc/runtime.h>
void myCustomMethod(id self, SEL _cmd, id arg1, id arg2)
{
NSLog(#"This is a test, arg1: %#, arg2: %#", arg1, arg2);
}
int main(int argc, char *argv[])
{
Class NSObjClass = [NSObject class];
class_addMethod(NSObjClass, #selector(myNewMethod::), (IMP) myCustomMethod, "v#:##");
NSObject myObject = [NSObject new];
[myObject myNewMethod:#"Hi" :#"There"];
[myObject release];
return 0;
}
But that is about it outside of a #class construct, and it really just covers up what happens with a category.
You can use a category for this.
As an instance method:
#interface NSObject (MONStuff)
- (void)printHelloOC;
#end
#implementation NSObject (MONStuff)
- (void)printHelloOC
{
NSLog(#"Hello.");
}
#end
// in use:
NSObject * obj = ...;
[obj printHelloOC];
As a Class method:
#interface NSObject (MONStuff)
+ (void)printHelloOC;
#end
#implementation NSObject (MONStuff)
+ (void)printHelloOC
{
NSLog(#"Hello.");
}
#end
// in use:
[NSObject printHelloOC];
Of course, you must associate that with a class - so it's not exactly the same as you posted, but it's a close definition + declaration separate from the formal class declaration.
A method without an associated class is a meaningless concept. Functions, as you've noted, are just fine.
No, it is not possible - you will need to either use global C functions or class (+) methods.
Objective c functions are always associated with a class. If you mean you want to use an objective-c function without instantiating a class, you can of course write a class method (notice the plus sign instead of the usual hyphen)
#interface Test
+ (void)aClassMethod;
#end
then you can call it by calling
[Test aClassMethod];

Declare an ObjC parameter that's a Class conforming to a protocol

In Objective-C, it is possible to pass a class as a parameter to a method:
- (void) methodThatTakesClass:(Class)theClass;
And it is possible to pass an instance that is conforming to a protocol as a parameter:
- (void) myConformInstance:(id <MyProtocol>)theObject;
Is it possible to use the combined functionality? A method which takes a class which is conforming to a certain protocol.
Yes. The following is a valid program which will log the NSObject class.
#import <Foundation/Foundation.h>
void f(Class <NSObject> c) {
NSLog(#"%#",c);
}
int main() {
f([NSObject class]);
}
This would cause a compiler error if you tried to pass a class which doesn't conform to NSObject, such as the Object class. You can also use it for methods.
- (void)printClass:(Class <NSObject>)c;
also valid:
#interface Something: Object {
}
- (void) foo:(int(*)(void))bar;
#end
#implementation Something
- (void) foo:(int(*)(void))bar {
return (*bar)();
}
#end
int someFunc( void ) {
return 9;
}
int main ( int argc, char **argv ) {
Something *object = [[Something alloc] init];
printf( "%i\n", [object foo:&someFunc] );
[object release];
return 0;
}

How to deal with double composition and inheritance?

I found this related question: How do I use composition with inheritance?
I would like to do the same with Objective-C, that is to say that a GenericView knows that its property obj is a GenericObject, and that a SpecializedView knows that the very same obj property is a SpecializedObject.
Here is an example that will be clearer:
//
// Example.m
#import <UIKit/UIKit.h>
/* HEADER */
// Electrical Machine
#interface ElectricalMachine : NSObject {
}
- (void)plugIn;
#end
// Toaster
#interface Toaster : ElectricalMachine {
}
- (float)getThermostat;
#end
// GenericView
#interface GenericView : NSObject {
ElectricalMachine *machine;
}
- (void)doSomethingGeneric;
#property (nonatomic, retain) ElectricalMachine *machine;
#end
//SpecializedView
#interface SpecializedView : GenericView {
}
- (void)doSomethingSpecialized;
#end
/* IMPLEMENTATION */
// GenericView
#implementation GenericView
#synthesize machine;
- (void)doSomethingGeneric {
Toaster *toaster = [[Toaster alloc] init];
[toaster plugIn];
self.machine = toaster;
[toaster release];
}
#end
// SpecializedView
#implementation SpecializedView
- (void)doSomethingSpecialized {
/* ERROR HERE
* Incompatible types in initialization
* 'ElectricalMachine' may not respond to '-getThermostat'
*/
float r = [machine getThermostat];
r = r;
// ...
}
#end
As you see, I get an error at the end, because for SpecializedView the machine property is an ElectricalMachine, not a Toaster.
Thank you very much for your help!
Old Question
Here is the first version of my question, which was maybe too cryptic:
I have the following generic view:
#interface GenericView {
GenericObject obj;
}
- (id)doSomething;
I also have the following specialized view:
#interface SpecializedView : GenericView {
}
- (id)doSomethingElse;
I have the following object:
#interface GenericObject {
}
- (id)plugIn;
and the following specialized object:
#interface SpecializedObject : GenericObject {
}
- (float)toastTime;
Let's say I want GenericView to handle GenericObject, and SpecializedView to handle the same object, knowing that it is SpecializedObject.
Let me explain by showing implementations:
GenericView doSomething
- (id)doSomething {
[obj plugIn];
}
SpecializedView doSomethingElse
- (id)doSomethingElse {
// ERROR here
float time = [obj toastTime];
}
I will get the following warning:
'GenericObject' may not respond to '-toastBread'
and the following error:
Incompatible types in assignement
Which is logical, since I have defined the type of obj as GenericObject. I want to be able to use methods from GenericObject in GenericView, and methods from SpecializedObject in SpecializedView. Is there a way to precise that obj has to be a GenericObject in GenericView to be handled, and has to be a SpecializedObject to be dealt with in SpecializedView, without adding a property? How would you do that?
Objective-C is a dynamically-typed language and methods are resolved at runtime, not compile time. If in SpecializedView, obj is in fact of an object of type SpecializedObject (even though it's declared as GenericObject), it will in fact respond to a toastBread message. The compiler will generate a warning but you can ignore it.
If SpecializedView may have both GenericObjects and SpecializedObjects, you can make sure that obj responds to toastBread using the respondsToSelector: message (inherited from NSObject):
if ([obj respondsToSelector:#selector(toastBread)]) {
[obj toastBread];
}