I read enough information about singleton and delegation. So, I think I understand what is singleton. About delegation I still confuse. I understand conception of delegation, but I need to create my protocol for understanding delegation.
Ok, I create singleton for work with my entities from CoreData. Maybe I wrong and it is not singleton, tell me please about it. My singleton is FetchData.
Fetchdata.h
#import <Foundation/Foundation.h>
#interface FetchData : NSObject <UIApplicationDelegate>
+(FetchData*) fetchData;
-(NSArray*)fetchLogin:(NSString*)name;
-(BOOL)newGroup:(NSString*)group forLogin:(NSString*)login;
-(NSMutableArray*)contactsForGroup:(NSString*)group;
-(BOOL)newContact:(NSString*)name surname:(NSString*)surname withDatas:(NSArray*)array;
//other methods
#end
Fetchdata.m
#import "FetchData.h"
#import "Contact.h"
#import "Login.h"
#import "Group.h"
#import "AppDelegate.h"
#interface FetchData ()
#property (nonatomic, strong) NSEntityDescription *loginEntity;
#property (nonatomic, strong) NSEntityDescription* groupEntity;
#property (nonatomic, strong) NSManagedObjectContext* context;
#property (nonatomic, strong) NSEntityDescription* contactEntity;
#property (nonatomic, strong) AppDelegate* appDelegate;
//other properties
#end
#implementation FetchData
#synthesize //my properties
+(FetchData*) fetchData
{
static FetchData* fetchData = nil;
if (!fetchData)
fetchData = [[super allocWithZone:nil]init];
return fetchData;
}
+(id)allocWithZone:(NSZone *)zone
{
return [self fetchData];
}
//implementation my methods
#end
So, it is very easy to work with CoreData now for me. I need only import FetchData and simply use methods for create/delete/change/add/sort...
SomeClass.m
#import "FetchData.h"
#define fetching [FetchData fetchData]
But I think that I can use for my aim delegation. Or maybe it is the best decesion as compared with singleton. So I want to remake singleton for delegation. And I need help with this question. What I must do?
If I understand correctly I need create protocol with all my methods from FetchData.h, FetchData.m I can leave without changes. And in SomeClass I need import FetchData and add my protocol. Like:
#import <Foundation/Foundation.h>
#protocol FetchingDelegate
//all methods from FetchData.h
#end
#interface FetchData : NSObject
#property (nonatomic, strong) id <FetchingDelegate> delegate;
#end
FetchData.m
#interface FetchData()
//all properties without changing
#end
#implementation FetchData
#synthesize //all properties and delegate
//implementation of methods
#end
SomeClass
#import "FetchData.h"
#interface SomeClass : NSObject <FetchingDelegate>
#end
#implementation SomeClass
-(void)viewDidLoad
{
FetchData* fetching = [FetchData new]
fetching.delegate = self
}
//and now I can use any methods from protocol like [fetching anyMethod]
//such I used with singleton
The idea of a singleton is that your entire app can access this one class. Multiple view controllers may need data coming from your database. In your case, I would change your fetchData method (and maybe change its name as it doesn't really follow convention now):
+(FetchData*) fetchData
{
static FetchData *fetchData;
dispatch_once_t token;
dispatch_once(&token, ^{
if (!fetchData)
fetchData = [super init];
}
return fetchData;
}
Delegates are meant for one-on-one communication, meaning that one object has a delegate and sends any messages to that one particular delegate.
That means that a singleton and delegation don't go well together. The singleton is made to send messages to multiple receivers, while the delegation pattern is meant for one-on-one communication. So you have two options: you could either not use a singleton and use the delegation pattern, or you could use a singleton, and use NSNotificationCenter to notify observers of changes.
Related
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
I want to write a custom delegate method to receive an event in one of my view controllers from another view controller. Should I use blocks here instead of delegates. Which is the preferred one ?
#protocol MyClassDelegate
-(void)doSomethingInDelegate;
#end
#interface MyClass : NSObject
#property id<MyClassDelegate> delegate;
-(void)doSomething
#end
#implementation MyClass
-(void)doSomething
{
[self.delegate doSomethingInDelegate];
}
#end
#interface MyOtherClass<MyClassDelegate> : NSObject
...
#end
#implementation MyOtherClass
-(void)doSomethingInDelegate
{
NSLog(#"Doing something in delegate");
}
#end
In most cases, if you have a very small number of delegate methods (ideally just 1), then blocks may be a good replacement. If you have several delegate methods, then blocks can become awkward.
UITableView has dozens of delegate methods between UITableViewDelegate and UITableViewDataSource. Configuring that with blocks would be unwieldy and make code reuse very difficult. If a particular way of "being the delegate" may be highly reusable (like in UITableViewController), then delegates are a much more powerful pattern.
On the other hand, if your delegate would wind up having just a single "thisActionFinished:` method, then a delegate is likely overkill and it's better to just pass a block. There are many cases that this is true, and we used to have to need to create a lot of one-method delegate protocols, and it was a bit of a pain. Blocks made that common pattern a lot easier.
But it's not a universal replacement for delegation, and blocks have many other purposes that have nothing to do with callbacks. So it's important to learn both techniques.
Looking to your specific example, there are several mistakes. Let's do it in both delegate and block forms.
Delegate
// Since the protocol needs to know about the class, you need to warn the
// compiler that this class exists.
#class MyClass;
// Declare the delegate protocol. Delegate method names should follow this
// pattern with "did", "should", or "will" in their names. Delegate methods
// should always pass the delegating object as the first parameter. A given
// delegate may be delegating for several instances.
#protocol MyClassDelegate
-(void)myClass:(MyClass *)class didSomething:(id)something;
#end
// Declare the class that has a delegate. Notice that `delegate` should be `weak`
// here. In your example, it's `strong`, and that will almost always lead to a
// retain loop. With rare exceptions, delegates are not retained.
#interface MyClass : NSObject
#property (nonatomic, readwrite, weak) id<MyClassDelegate> delegate;
-(void)doSomething;
#end
// Do the thing
#implementation MyClass
-(void)doSomething {
[self.delegate myClass:self didSomething:#"SOMETHING"];
}
#end
// The delegate object almost always has a strong pointer to the thing it delegates
// for. That's why you want the `delegate` property to be weak.
// Note that your syntax was wrong. "MyOtherClass <MyClassDelegate>". That's
// the new generic syntax, not the protocol syntax. Protocols go at the end.
#interface MyOtherClass : NSObject <MyClassDelegate>
#property (nonatomic, readwrite, strong) MyClass *c;
#end
// And the obvious impl
#implementation MyOtherClass
- (instancetype)init {
self = [super init];
if (self) {
self.c = [MyClass new];
self.c.delegate = self;
}
return self;
}
-(void)myClass:(MyClass *)class didSomething:(id)something {
NSLog(#"Doing something in delegate");
}
#end
Block
Let's do the same thing if this were a block-based API.
// If your callback takes no arguments and returns nothing, then you can
// use dispatch_block_t here. But often you need parameters or return
// something, and for that you should usually make a typealias. Welcome to the
// spiral world of block syntax.
typedef void(^MyClassCallback)(id something);
// Instead of a delegate, we have a callback. We might have several. We might
// have a block that returns the row height. But if you're doing a lot of
// that, just use a delegate. Note that blocks should always be `copy`.
#interface MyClass : NSObject
#property (nonatomic, readwrite, copy) MyClassCallback callback;
-(void)doSomething;
#end
// And here's how you use the block. It's just like a function.
#implementation MyClass
-(void)doSomething {
if (self.callback != nil) {
self.callback(#"SOMETHING");
}
}
#end
// And the delegate.
#interface MyOtherClass : NSObject
#property (nonatomic, readwrite, strong) MyClass *c;
#end
#implementation MyOtherClass
- (instancetype)init {
self = [super init];
if (self) {
self.c = [MyClass new];
// And here's the syntax for creating the block.
self.c.callback = ^(id something) {
NSLog(#"Doing something in delegate");
};
}
return self;
}
#end
Notice we don't need an extra method in the delegate just to hold one line of code, and we don't need to define a protocol. That's the big reason for the move to blocks for lightweight delegation. It keeps related code close together. But when the code gets complicated, "together" gets crazy, and blocks are not longer a good solution. Back to delegates, which do that very well.
This is my first day of Objective C so I apologise for the lack of knowledge.
I need to import an existing SKD into an App and I done it successfully. Now I need to create the delegate methods and I don't understand how can I do it.
This is the structure of the header file included from the SDK (SDKManager.h):
#protocol SDKManagerDelegate;
#interface SDKManager : NSObject
#property (nonatomic, weak) id<SDKDelegate> delegate;
+(void)initialize:(NSString*)appId withKEY:(NSString*)key;
+(void)setHandler:(id)delegate;
#end
#protocol SDKManagerDelegate <NSObject>
#required
-(void)appDidReceiveTokens:(NSDictionary*)items withResponse:(NSDictionary*)response;
#end
So, from my FirstViewController.m I was able to import the header and call two methods:
#import "FirstViewController.h"
#import "SDKManager.h"
#interface FirstViewController ()
#end
#implementation FirstViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[SDKManager setHandler:[UIApplication sharedApplication].delegate];
[SDKManager initialize:#"AppId"withKEY:#"1234"];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
but I have noticed that I am not able to call the other methods (i.e. appDidReceiveTokens).
Actually the instructions require to create those methods but I have no idea where.
Any help is really appreciated.
Thank you
You do not call delegate methods directly in the files in which you are implementing the delegate methods. Review Apples documentation on the concept of Delegation.
To implement this properly you would adopt the delegate in your class, then implement the delegate methods that are #required and/or #optional.
You've correctly created the delegate protocol and a property to store the SDKManager's delegate.
Your setHandler: and initialize:withKEY: methods are class methods, whereas the delegate property belongs to each instance of SDKManager. Without seeing your implementation file (.m) for SDKManager, it's hard to know why you've set it up this way. You may be attempting to follow a singleton pattern - if so, read up on it, e.g. here.
The reason for that is you have class methods which sets the calls setHandler method and the delegate is property, so where do you assign the delegate and when and how do you call the delegate. I hope you understand what a class and instance is. So, you cannot call the delegate until you create instance of your object.
You have two different class methods which is used to set some attributes to the class, would it make sense to have them as property.
More generic and better way to do this would be like this,
#protocol SDKManagerDelegate <NSObject>
#required
-(void)appDidReceiveTokens:(NSDictionary*)items
withResponse:(NSDictionary*)response;
#end
#protocol SDKManagerDelegate;
#interface SDKManager : NSObject
- (instancetype)initWithAppId:(NSString *)appId
key:(NSString *)key
delegate:(id<SDKManagerDelegate>)delegate;
#end
#interface SDKManager ()
#property (nonatomic, copy, readonly) NSString *appId;
#property (nonatomic, copy, readonly) NSString *key;
#property (nonatomic, weak, readonly) id<SDKManagerDelegate> delegate;
#end
#implementation SDKManager
- (instancetype)initWithAppId:(NSString *)appId
key:(NSString *)key
delegate:(id<SDKManagerDelegate>)delegate
{
if (self = [super init]) {
_appId = [appId copy];
_key = [key copy];
_delegate = delegate;
}
return self;
}
- (void)doSomeNetworkRequestHere
{
[self fetchTokenFromServer:^(NSDictionary *tokens, NSDictionary *response){
[self.delegate appDidReceiveTokens:tokens
withResponse:response];
}];
}
- (void)fetchTokenFromServer:(void(^)(NSDictionary *tokens, NSDictionary *response))completion
{
}
#end
Say I have a CatModel object:
#interface CatModel : NSObject
#property (nonatomic, copy) NSString *name;
#property (nonatomic, strong) UIImage *catImage;
- (void)addWhisker:(Whisker*)whisker;
And I have a CatView:
#interface CatView : UIView
#property (nonatomic, strong) CatModel *dataSource;
#end
I want the CatView to automatically add a whisker image when it detects that a whisker was added to its dataSource. I don't want to add a Whisker to the CatModel instance and also add an addWhisker method to the CatView. What's the best way to do this?
Sounds like you may use key-value observing, but unfortunately, NSArray or any other collections are not KVO-compatible.
Instead, you may wish to create a delegate functionality:
#protocol CatModelObserving
#optional
- (void)catModel:(CatModel *)model didAddWhisker:(Whisker *)whisker;
#end
...
#interface CatModel
#property (weak, nonatomic) id <CatModelObserving> observer;
#end
Then you would ensure that the CatView conforms to that protocol and implements that method:
- (void)catModel:(CatModel *)model didAddWhisker:(Whisker *)whisker {
// handle it properly
}
In your CatModel.m, inside the -addWhisker: method you should notify the observer that a whisker has been added:
if (self.observer && [self.observer respondsToSelector:#selector(catModel:didAddWhisker:)]) {
[self.observer catModel:self didAddWhisker:whisker];
}
If you wish to have multiple "observers", you may consider using GCD and block-based "notifications", like so:
[catModel addDidAddWhiskerBlock:^(Whisker *whisker) {
// handle it properly
}];
But I will not discuss that method in this answer. As a hint I can suggest using NSMutableArray storing all those blocks, then iteratiating through those blocks in the -addWhisker: method and calling each block.
I have 2 classes that I want to be able to access each others properties, but I don't want those properties accessed from anywhere else. Is there a way to do this? Is the only way to accomplish this through subclassing? Is there no way to establish a "special" relationship between two classes?
If I understand your question, you effectively want class A and class B, which are unrelated by inheritance, to be aware of more innards than are publicly advertised?
Say A has a property called innardsForB that only instances of B should access. You can use class extensions to declare the non-public interface to A.
A.h
#interface A:NSObject
... regular class goop here ...
#end
A-Private.h
#interface A()
#property(nonatomic, strong) Innards *innardsForB;
#end
A.m
#import "A.h"
#import "A-Private.h"
#implementation A
// because "A-Private.h" is #import'd, `innardsForB` will be automatically #synthesized
...
#end
B.m
#import "B.h"
#import "A-Private.h"
#implementation B
...
- (void)someMethod
{
A *a = [self someASomewhere];
a.innardsForB = [[Innards alloc] initForMeaning:#(42)];
}
Protocols are designed for that purpose. You cannot stop 3rd party classes from implementing or using a protocol. Methods within these are public but not nessecarily part of the public interface.
Communication between objects:
http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/CocoaFundamentals/CommunicatingWithObjects/CommunicateWithObjects.html
I you want that classA access classB's properties and classC does't you simply déclare a reference of classA in ClassB and don't declare it in ClassB.
Example :
#interface ClassA
#property (nonatomic, strong) UILabel *label1;
#end
#import "ClassB.h"
#import "ClassA.h" // To access public properties and all methods declared in ClassA.h
#implementation ClassB
ClassA *classA = ....;
classA.label1.text = ...;
#end
From this example, ClassB can access all public(déclared in CalssA.h) proerties and methods of ClassA.
You can use delegate also to do this.
On obj-c properties are protected. That means you can only accede properties by inheritance.
#interface A : NSObject{
NSObject* prop;
}
#end
#implementation A
#end
#interface B : A
#end
#implementation B
- (void)protected{
self->prop; // yep
}
#end
#interface XXX : NSObject
#end
#implementation XXX
- (void)test{
A* a = [[A alloc] init];
a->prop; // wrong, will not compile
}
#end
If you want to access hidden properties via method, you can use simply category hidden in implementation, or bridge. But there is no way to establish a "special" relationship between two classes. But you can enforce this relationship with your code design.