iOS: what is the equivalent of an event listener in Objective-C? - objective-c

In some of my learning I saw someone mention that in your view controller you can have a model and have some sort of listener on the model for changes in it. I don't think I'm using the right names for these, which is probably why my searches haven't turned up anything. Essentially I want to move my server calls from the controllers into my models, but I need some sort of listener on them to know when the call is complete to update my views.

look into delegates
delegates tutorial
or blocks a bit more advanced
basic blocks tutorial
just start with delegates,
you can also use NSNotification NSNotification tutorial but is not recommended as it broadcast to every class, and you might only need to send messages to a specific class not every one

Belong to C# world, i have to go to objective c (for my job).
I think the event equivalent in objective c is this implementation :
Create protocol with all your event's methods :
#protocol MyDelegate <NSObject>
- (void)myEvent;
#end
In your class which should send the event, add :
#interface MyClassWichSendEvent : NSObject
#property (nonatomic, retain) IBOutlet id<MyDelegate> delegate;
#end
Raising the event where you want, for example :
- (IBAction)testEvent:(NSButton*)sender
{
[self.delegate myEvent];
}
Now in your listener class, you should listen the events like this :
Add the protocol to your class that listening
#interface Document : NSDocument<MyDelegate>
In the implementation, on init or in interface builder, you must link delegate of your object instance to listen with self of your class which listen.
In code
-(void)awakeFromNib
{
myObjToListen.delegate = self;
}
In Interface Builder -> IBOutlet from delegate to your listen's class.
And finally, implement your method in your listener class :
- (void)myEvent
{
NSLog(#"i have listen this event !");
}
Sorry for my english, i hope that help people who went from java or C#.

You're looking for KVO - key/value observing:
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html
http://nachbaur.com/2011/07/29/back-to-basics-using-kvo/
Delegates + Notifications are good for communicating between objects but they don't automatically send msgs when a value changes (which from your question, that is what you are asking about)

I think you may be looking for NSNotificationCenter which is a way to pass messages to whoever may be listening. So you can send out a notification from an event in your model and just listen for it in your controllers. A cleaner method might be to implement your own protocol with delegates.

Objective C uses delegates
This post has a nice example: How do I create delegates in Objective-C?

Related

Objective-C : Accessing fields in implementation

Is it possible to fields defined only in implementation but not in interface definition ?
#interface MyInterface .... #end --> dict not defined here!!!
#implementation MyInterface
...
NSDictionary *dict;
...
#end
In this case if somewhere I somehow accessed to this class, can I access to the dict or should I create a getter just like in Java ?
Edit after #Rob's answer
Thanks for the answer Rob, I wish I have the implementation of these interface and classes. Instead I am trying to bind two different libraries ( I know it is reallllly bad as architectural point of view but this is where I end up).
Basically, I am in react-native world. And we are using react-native-video as our player layer. But since AVPlayer does not support some subtitle types our head company sent us a library that needs a player instance and a view instance to draw subtitle on the view. I believe they will bind to events of the player and draw sub titles based on player states.
So react-native-video is in this github repo with the interface and implementation.
I find the UIView that includes the properties and casted it to the object itself RTCVideo in this case). But now I am stuck. I can go and change some stuff as per your suggestion in the "Development Pods" to be able to access but this is my last bullet :) I prefer to convince these two libraries in a friendly way :)
Yes, but the above syntax isn't what you want. The modern way to do this is with a class extension.
Your header file is the same:
#interface MyInterface
#end
But in your .m file, you create an extension by appending ():
#interface MyInterface ()
#property (nonatomic, readwrite) NSDictionary *dict;
#end
Now, inside your .m file, you can access self.dict normally, but outside of your .m file it won't appear available.
For full details, see Programming with Objective-C: Class Extensions Extend the Internal Implementation.
The syntax you've written actually creates a static (global) variable called dict that isn't tied to any instance.
It is possible to create raw instance variables using a {...} syntax, either on the extension or on the implementation, but this isn't used that often today, except for managing raw buffers that you don't want accessors for. The syntax is either:
#interface MyInterface () {
NSDictionary *_dict;
}
...
#end
or on the implementation:
#implementation MyInterface {
NSDictionary *_dict;
}
...
#end
But I recommend simple extensions with properties any time you can. And if you are considering creating an accessor for it, you definitely want to use #property and let the system do it for you.
If I understand your edits correctly, you're trying to read the internal ivars of an object that doesn't expose them with an accessor, correct? I believe specifically you want to access _player.
There's several common ways to do that. The key feature you want is Key-Value Coding.
The simplest approach for this problem is -valueForKey:
AVPlayer *player = [view valueForKey:#"player"];
The first thing -valueForKey: looks for is _<key>, and if it's just an object pointer (as in this case), it just returns it.
(This can be broken if a class return false for +accessInstanceVariablesDirectly, but the default is true, and it's unusual to override this.)
Another very common approach is to just declare any methods you know exist as a category. (This won't work for _player, since it's not a method, but in case you need similar things.) Imagine you wanted to call the "private" method -removePlayerTimeObserver. In your .m file, just say you know about it using a category:
#interface RCTVideo (PrivateMethods)
- (void)removePlayerTimeObserver;
#end
And since you know about it, you can call it:
[video removePlayerTimeObserver];
If you're wrong, and that method doesn't really exist, then the program will crash. In Objective-C, almost all rules are advisory. You can break them if you want to. ObjC programmers tend to be big rule-followers because otherwise the program crashes and ObjC has very clear rules that are pretty easy to follow. It's not because the system forces us to.

Proper use of Objective-C protocols

I'm using my free time to play with Objective C. I was reading about Protocols but I'm afraid I might be using it wrong, considering I'm using it the same way (almost the same at least hehe) I do with C# code.
So, here is what I got. I have a protocol, a class manager to weakly couple my views and two views that implement the protocol.
#protocol IView <NSObject>
- (void) loadViewToScreen;
#end
#interface ViewManager : NSObject
#property (atomic, weak) id<IView> document;
#property (atomic, weak) id<IView> browser;
//Singleton
+ (id) getInstance;
#end
Then I call one view the views from each other.
ViewManager *vm = [ViewManager getInstance];
[vm.browser loadViewToScreen];
I'm not interested here what the best way to load views into the screen. It's just a mock code to test protocols.
I could not get the manager to use pointers to the protocols. So I'm afraid I'm getting view copies around. Did I get this right?
Thanks,
Lucas
A protocol, concpetually, is just a part of the type of an object or class. You can't get a pointer to a protocol. (Well, actually you can obtain a protocol object, but that's runtime mocking which doesn't seem to be what you want).
Don't be afraid about getting copies, though. Unless you copy an object or assign it to a copy property, you'll get pointers to the same instance.

Multicast delegates - multiple classes receiving notifications from UI controls in iOS

I understand that UI controls such as UITextField notify of client interactions / events via their delegate, which is defined as a class that supports the required protocol.
I have often found myself wanting to receive notifications of UI event in more than one class, so would want to support multicasting. For example, specifying more than one delegate for a UI control. I am pretty sure that there is no iOS framework feature that supports this. I was wondering if anyone had come up with a decent solution to this problem?
There is a cocoa feature that lets you build multicast delegates with relative ease - it's the Message Forwarding system built into the framework.
Make a class that overrides forwardInvocation:, and return an instance of your object instead of a delegate. This is what is sometimes called a "Trampoline object". The logic inside your forwardInvocation: implementation can now decide which "real" objects should receive the message, and forward the invocation to one or more of them.
As an update to this accepted answer, I created my own multicasting delegate implementation here:
http://www.scottlogic.co.uk/blog/colin/2012/11/a-multicast-delegate-pattern-for-ios-controls/
You could implement your UI control in your class, and then your class will receive notification from this UI, you can send message to another class (using the same delegate technic - implement delegate property in first class, and then in second class implement delegate method from 1-st class).
For example, for UITextField method -textFieldDidEndEditing:
In first class -
1) implement protocol:
#protocol TextControllerDelegate <NSObject>
#optional // Delegate protocols
- (void)textFieldDidEndEditing:(UITextField *)textField;
#end
2) #property (nonatomic, unsafe_unretained, readwrite) id <TextControllerDelegate> delegate;
3)in method - (void)textFieldDidEndEditing:(UITextField *)textField inside the class, call [delegate textFieldDidEndEditing:textField]
In second class:
1) implement object of first class, set delegate to self (to second class).
2) implement method - (void)textFieldDidEndEditing:(UITextField *)textField
One technique to support multicasting is to give your delegating class the following methods:
#interface Delegator : NSObject
- (void)addDelegate:(id<MyProtocol>)delegate;
- (void)removeDelegate:(id<MyProtocol>)delegate;
#end
And store the reference to the delegates in an NSHashTable.
See the implementation here:
http://arielelkin.github.io/articles/objective-c-multicast-delegate/

Objective C View to Controller Communication

What is the proper way to accept user input in a view and then transfer it to that view's controller? I know the NotificationCenter is one option, but surely there is a more elegant way to transfer data from a view to its controller?
All help is greatly appreciated and I always accept an answer!
Use the delegate protocol design pattern, or target-action by subclassing UIControl. Think about how a UIButton tells a view controller that it's been pressed. In interface builder, you connect an action - a selector something like touchUpInside: to a target - the view controller that owns it. In non-IB, you directly tell the UIButton what selector and what target to use.
Both methods make sense in different cases. For a UITextField, for example, it makes more sense to use delegation because it's possible for the text field to send you any number of events, such as an event when the user begins editing, ends editing, or types a character.
For a button, it makes more sense to use target-action because there's really only one event expressed in different forms.
For swipes and drags and other gestures, use UIGestureRecognizers.
You're looking for Delegation or a Data Source. You can see more information about this here, Delegation and Data Sources
A brief example of this would be, something along the lines of this:
//MyViewSubclass.h
#protocol MyViewSubclassDelegate
//Implement your delegate methods here.
-(void)didTouchView;
#end
#interface MyViewSubclass {
id<MyViewSubclassDelegate>delegate;
}
#property(nonatomic,assign)id<MyViewSubclassDelegate>delegate;
Of course, #synthesize your delegate in MyViewSubclass.m
Now in the class's header, that you want the delegate of MyViewSubclass to be, you need to conform to the `MyViewSubclassDelegate Protocol.
#import "MyViewSubclass.h"
#interface MyViewController : UIViewController <MyViewSubclassDelegate>
In your #implementation of MyViewController., implement the MyViewSubclassDelegate method of -(void)didTouchView.
When you initialize and create your MyViewSubclass object, you set MyViewController as the delegate:
myViewSubclass.delegate = self // Self being MyViewController.
In your MyViewSubclass, when you're ready to forward any information, or simply want to fire a method you would do [self.delegate didTouchView]
Hope this helps !
You are looking for delegation, where the controller set itselfs as the delegate of the view. You know it from UITableViewDelegate.
Make your view a subclass of UIControl and implement the target/action design pattern - use the sendActionsForControlEvents: method to message the controller.
Often the UIKit objects like UITextField have delegate methods that you can implement to perform your business logic. E.g UITextField has a delegate method called - textFieldDidEndEditing: that gets called after the user has dismissed the keyboard.

Creating a new event in Interface Builder

I am developing a new component to be used in Interface Builder, which subclasses UIPickerView to create an interface that is similar to UIDatePicker but also includes seconds. I would like for the developer who uses my component to be able to drag a new Object from the library, configure it to be a TimePickerView class, and use it from there.
That bit works perfectly, but now I would like to implement some of the events that are available in a standard UIDatePicker, specifically the "Value Changed" event. I am not sure how to declare an event in this manner without using a delegate protocol. I am also not sure how to make XCode aware of events that are available on an object. Therefore, I am really asking three questions:
How can I declare an event, such as the Value Changed event on a UIDatePicker?
How can I fire an event from within my TimePickerView?
How can I make XCode aware of this event so that a developer can easily link an event to a controller?
As this doesn't seem to be easy to do, I suspect there could be a reason for this; therefore I would also appreciate comments on my approach and arguments for why I should create a delegate protocol to make this happen.
In Objective C and cocoa framework there's nothing like declaring an event(as you would do for example in C#), the same behavior of an event is achieved using the delegate pattern(this is how all cocoa class handle events), so to implement a custom events with the delegate pattern you can do in this way, for example :
Protocol and Custom class interface declarations :
#protocol myDelegate <NSObject>
-(void)valueChanged:(double) value;
#end
#interface UAKTestDelegate : UIPickerView
#property(weak) id<myDelegate> delegate;
#end
Somewhere in the implementation (fire the event) :
//Example of firing the event ....
if([[self delegate] respondsToSelector:#selector(valueChanged:)]) {
[[self delegate] valueChanged:1.0];
}
So, this first part of the answer should address the first two questions in your post(create and fire custom events), but the response to the third answer is simply you can't ...
Xcode(in this case interface builder) knows about the events that UIControl(or a subclass of it) implements, but there's no way to tell it about your own custom events.
So i think that in your case (if you can) you could subclass directly UIDatePicker and eventually override valueChanged if you need to.