Generics and delegate and Nullablity related code - ios

Can someone explain me what does this code means? Is it a good coding practice to such code. MyProtocol and OtherProtcol are some protocol method. What does NSObject mean here?
#interface MYViewController () {
NSObject<MyProtocol> * abc;
NSObject<OtherProtcol> * def;
}

This class has 2 properties that accepts any object (subclass of NSObject) and must conform to MyProtocol and OtherProtocol
example:
#interface SomeClass {
}
myViewController.abc = [SomeClass new]; // error this class does not conform to MyProtocol
#interface AnotherClass<MyProtocol> {
}
myViewController.abc = [AnotherClass new]; // works
myViewController.def = [AnotherClass new]; // error AnotherClass does not conform to OtherProtocol
This is the new protocol oriented programming which you should use a lot instead of subclassing. Check wwdc protocol oriented programming with swift

Related

Making delegate methods not visible for other classes

I have 2 classes,
class A(Obj-C) and
class B(Swift).
Class A has a delegate protocol
#protocol ADelegate<NSObject>
- (void)someMethod:(NSString *)str;
#end
to which class B conforms:
class B: ADelegate { ... }
But the issue is, the other Objective-C classes which use class B as a property can access to those delegate methods to which my Swift class conforms. For example, there is a class C(Obj-C):
#interface Class_C_ViewController ()
#property (nonatomic, strong) B *classB_property;
- (void)viewDidLoad {
[self.classB_property someMethod: #""];
}
#end
So basically that Swift property can access and call the delegate methods from another Obj-C class.
Is there a way to make those methods private, so no other class can call those methods but Swift class?
I really hope that I could explain my issue. If you have any questions please let me know.

Proxy Pattern in iOS - Swift

I need to create proxy pattern in iOS using swift
I have tried it using Objective C and here is the code
MyProtocol.h
#import <Foundation/Foundation.h>
#protocol MyProtocol <NSObject>
#required
-(void)testMessage;
#end
TestBO.h
#import <Foundation/Foundation.h>
#import "MyProtocol.h"
#interface TestBO : NSObject <MyProtocol>
#end
TestBO.m
#import "TestBO.h"
#implementation TestBO
-(void)testMessage{
NSLog(#"Test Message");
}
#end
TestProxyHandler.h
#import <Foundation/Foundation.h>
#interface TestProxyHandler : NSProxy
#property (nonatomic, strong) id object;
- (instancetype)initWithProtocol:(Protocol *)protocol andObject:(Class)clazz;
- (void)forwardInvocation:(NSInvocation *)invocation;
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector;
#end
TestProxyHandler.m
#import "TestProxyHandler.h"
#import "TestBO.h"
#implementation TestProxyHandler
- (instancetype)initWithProtocol:(Protocol *)protocol andObject:(Class)clazz{
if ([clazz conformsToProtocol:#protocol(MyProtocol)]) {
self.object = [[clazz alloc] init];
}else{
NSLog(#"Error it does not conform to protocol");
}
return self;
}
- (void)forwardInvocation:(NSInvocation *)invocation{
NSString *selString = NSStringFromSelector(invocation.selector);
NSLog(#"Called %#",selString);
[invocation invokeWithTarget:self.object];
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
return [self.object methodSignatureForSelector:selector];
}
#end
I have invoked it using
id <MyProtocol> delegate = (TestBO *)[[TestProxyHandler alloc] initWithProtocol:#protocol(MyProtocol) andObject:[TestBO class]];
[delegate testMessage];
But I am not able to make it work in Swift even the initialzier is showing that the message
TestHandler.swift
import Foundation
class TestHandler: NSProxy {
var object: AnyObject
convenience override init(`protocol`: Protocol, andObject clazz: AnyClass) {
if clazz.conformsToProtocol() {
self.object = clazz()
}
else {
NSLog("Error it does not conform to protocol")
}
}
}
Does anyone have any clue to do this in swift ??
EDIT:
In java you can create runtime implementation of a method using the Proxy.newProxyInstance call but can this be achieved in iOS ? using swift ? Any clue ?
Comparing with Objective C and Swift, Swift offers extremely limited access to runtime language access . So based on my research till now it can’t be done :(
I even tried subclassing the NSProxy class in swift but just couldn’t call the super.init and code never compiles but however same thing works in objective C
So I ended up doing this approach
I created a protocol using
#objc protocol SomeProt {
// Some method
}
Note the keyword #objc before protocol is essential else you would not be able to pass it as a variable, also adding #objc limits the usage of protocol to objective c runtime features so don’t expect to get full features of protocols in swift
public func someMethod(`protocol` : Protocol, implementation : AnyClass) {
let isImplemented : Bool = implementation.conformsToProtocol(`protocol`)
// some code
}
If you need to use it in some dictionary or places where it should conform to NSCopying class then use
NSStringFromProtocol
and
NSProtocolFromString
methods
Now I have wrote a objective c helper class to do the initialization
ObjcHelper.h
#import <Foundation/Foundation.h>
#interface ObjcHelper : NSObject
+(NSObject *)objectForClass:(Class)clazz;
#end
ObjcHelper.m
#import "ObjcHelper.h"
#implementation ObjcHelper
+ (NSObject *)objectForClass:(Class)clazz{
return [[clazz alloc] init];
}
#end
Now to use it
let prot : SomeProt = ObjcHelper.objectForClass(NSClassFromString("PROT_HANDLER_CLASS_NAME")) as! SomeProt
However in future if anyone can offer a better answer then please be sure to post it here

How To Solve No Type or Protocol Named Error In Xcode 7?

I m trying to passing values from second class to first class for that I am using protocol and delegate process. Whenever I run my program I am facing below Issue.
No Type or Protocol Named 'locateMeDelegate'
Viewcontroller A .h
#interface first : UIViewController < locateMeDelegate > { }
In my case the issue was caused by importing the delegate's header file to the delegator's class .h file. This seems to create a sort of vicious circle. As soon as I deleted the import statement of the delegate's header from the delegator's .h file, the error went away.
Tipically, if you intend your protocol to be used by other classes you must declare it in the header file like this:
// MyClass.h
#protocol MyProtocol;
#interface MyClass : NSObject
#end
#protocol MyProtocol
- (void) doSomething: (MyClass*) m;
#end
After you declare it, you should implement the methods of the protocol in the implementation file, which should conform to the protocol like this:
// MyClass.m
#implementation MyClass <MyProtocol>
pragma mark - MyProtocol methods
- (void) doSomething: (MyClass *)m {
// method body
}
#end
After these two steps you're ready to use you protocol in any class you desire. For example, let's say we want to pass data to MyClass from other class (e.g. OtherClass.h). You should declare in OtherClass.h a property so that we can refer to MyClass and execute the protocol. Something like this:
// OtherClass.h
#import MyClass.h
#interface OtherClass : NSObject
#property (weak) id<MyProtocol> delegate;
#end
You don't forget to import the header file where you declared your protocol, otherwise Xcode will prompt No Type or protocol named "MyProtocol"
id<MyProtocol> delegate; means you can set as the delegate of OtherClass any object (id) that conforms to the MyProtocol protocol (<MyProtocol>)
Now you can create an OtherClass object from MyClass and set its delegate property to self. Like this:
// MyClass.m
- (void)viewDidLoad() {
OtherClass *otherClass = [[OtherClass alloc] init];
otherClass.delegate = self;
}
It's possible to set the delegate to self because the delegate can be any object and MyClass conforms to MyProtocol.
I hope this can help. If you want to know more about protocols you can refer to this two websites:
Working with Protocols - Apple Documentation
Ry's Objective-C Tutorial (This one is easy to pick up)
I also faced the same issue and it seems the error is from Xcode itself. Please Try running on Physical device. This would solve the issue faced.

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