I am a beginner in objective-C. So please forgive if my question is silly.
In my root view controller A, I added a subview B.
In b there will be another subview C. C contains another subview D.
How can I call a method in A from D.
I know that we can use delegates for passing data to the parent controller.
But my question is that do i need to create delegate which calls C from D and another one for call B from C and so on?
Or is there any method which directly calls a method in A from D?
But my question is that do i need to create delegate which calls C from D and another one for call B from C and so on?
The view controller's job is to manage it's view and all of that view's subviews. If you've got a view that needs to send the view controller a message, like a control that needs to send a message somewhere when the user changes its value, then the view controller should be aware that it's there. In such a case, the view controller can take care of setting itself (or some other appropriate object) as said subview's delegate or target when the view hierarchy is loaded, like this:
- (void)viewDidLoad
{
self.needControl.delegate = self;
}
That way, the needy control doesn't need to know anything about the object that is its delegate. It's not assuming that the object is the view controller, or its parent view, or anything else. All it cares about is that it has a delegate, and that its delegate implements the necessary methods. And that, in turn, helps you keep your code more flexible and maintainable and maybe even reusable.
Do i need to create delegate which calls C from D and another one for call B from C and so on? No
You can use a single delegate to call a method in A from D. From your comments i came to know B,C,D are UIView's controlled your root view controller. So the job is easy you need to set a delegate as its root view controller upon creating each sub views.
1. View B is creating from the root view controller itself so viewB.delegate = self
2. View C is creating from the view B so viewC.delegate = self.delegate
3. Repeat same for view D also
Now all your views are controlled by your delegate rootViewController.
Finally This answer will help you to complete your task
You should structure your code so that class D does not know class A exists at all.
There are a few specific techniques that are common in iOS/Mac programming:
class D has a delegate property, and calls methods on it. Use this when only one object can receive the delegate method, particularly useful for things like a button asking if it should be enabled or disabled right now. Use interface builder to set the delegate of the view to your instance of class A.
class D should have a "target" property (type id) and an "action" property (type SEL), and it sends the action message/selector to the target object. useful for when a view has a specific single action that it triggers, such as when a button is pressed, or the user presses Enter in an text field. Use interface builder to set the target and action of the view to your instance of class A.
class D sends messages and metadata to [NSNotificationCenter defaultCenter], and class A tells the notification center that it wants to observe those notifications. Useful when potentially many objects need to be notified when something happened, such as when a text field receives or looses keyboard focus.
class D has a property or properties sends Key Value Observing notifications whenever it the value of the property changes. Class A would tell the Key Value Observing system that it wants to know whenever a specific property on class D changes. This is useful when you care specifically about some data, such as when the value of a text field changes.
All of these techniques are described in more detail here on stack overflow or in Apple's official documentation.
Class B and C also should not know that class A exists. Class A should be the one that knows how to find the other objects, unless you can use interface builder (the first two options allow that).
Add your A_viewCon.h file into your D_viewCon.h file
create object of A_viewCon and set #property and #synthesize as properly.
call method of A_viewCon in D_viewConwrite following code.
[self.objectOFA_viewCon performSelector:#selector(MethodNameOFA_viewCon) withObject:nil afterDelay:0];
U can register Class A to observe a NSNotification like ->
- (void)addObserver:(id)observer selector:(SEL)aSelector name:(NSString *)aName object:(id)anObject;
and post NSNotifications from Object of class D like ->
- (void)postNotificationName:(NSString *)aName object:(id)anObject userInfo:(NSDictionary *)aUserInfo;
This way u do not need to keep a reference/delegate and still u can communicate between alive objects.
Related
I think the solution to this is going to need to use delegation, but I'm unfamiliar with how to use them.
So in my project, I have my main viewcontroller/storyboard that contains a UIScrollView. That UIScrollview calls another storyboard (xib file) as a subview. The other storyboard (which is an xib file) is controlled with another swift file.
My question is, when I call an action inside of my other storyboard, how can I call a function from the main viewcontroller. Like say the viewdidload from the first viewcontroller.
I can't make the whole thing a global function, it needs to stay inside its class. So if I try to do ViewController.viewDidLoad() it needs (I think) an instance variable or something.
Thanks.
You can try:
Using weak variable (property) in the other class with type UIViewController
Assign the parent view controller to that property after the other view is initialized
Good reads about weak, strong, unowned references Here And Here
Firstly, if you want to call it with class name as you said above declare your method with "class". So its just like static in Java. It makes it generic to call it anywhere in your project. Make a separate extension.
class func myfunc(){
}
if you want to send data from B to A controller. You use what is called delegation. You give the work of B to A. Make a protocol above B for functions that you want to do or send with them. Call them in B. And then in A write code for those functions. So that you have the data from B to A
Else you demand something like common data. Create a singleton class and initialize properties methods there. You can use objects for that and call it in other controller to modify or make different instances.
You dont call viewDidLoad(). As the name says it loads once. If you want something that modify everytime you screen appears, use viewWillAppear
I am basically trying to implement a video conference functionality using opentok.
I have two view controllers.
Class A that has a grey image(to tell user is offline).
It calls setsession from class B to establish the session.
uses ClassADelegate and implements setUserOnlineImage that sets the class A grey image to green.
Class B holds a method useronline.
Has a class method sharedinstance that gives out the singleton instance of the class
viewdidload ->sets a variable type = 2;
setsession ->sets a variable type = 1;
It also has a protocol "ClassADelegate"
Protocol ClassADelegate has method setUserOnlineImage.
Has a callback method session:streamCreated: that is called when a subscriber is created and setupPublisher that publishes the video
The flow is like this.
first Class A calls the setsession from Class B to establish session.
Then when a connect button is clicked the viewdidload is called and then the setupPublisher is called, view is modified loaded and all that.
Now when a subscriber tries to connect session:streamCreated: is called. here when i try to print type value it comes as one, likewise many other variables also become nil which inturn results in just giving the audio and the video isnt seen.
where as if first session:streamCreated: is called (first video is received and then connect is clicked) the flow works fine and the print statement in session:streamCreated: correctly prints type value as 2.
Someone help me figure out whats happening.
I want to know why the type value is getting changed & various other variables become nil. This is preventing the video from showing. Am i missing something? Is any other instance is been taken(but I am using a singleton instance)?
The flow you describe doesn't follow any of the known patterns of how UIViewControllers should behave. Specifically, you shouldn't need to use a singleton instance of a view controller. I think you need to reconsider the architecture, specifically the relationship between these two view controllers.
By the way, the viewDidLoad method is called on the view controller as soon as its view property becomes available, which can be before its on the screen. If the view controller is loading its view from a storyboard or nib, viewDidLoad is called as soon as that view is ready. Otherwise if you are implementing loadView, viewDidLoad is called after that method is finished.
Can you describe what Class A and Class B are trying to accomplish? It sounds like Class A is a view controller for some type of status view that shows a user's online/offline status. Class B sounds like its the OTSessionDelegate as well as the view controller for where the publisher/subscriber views will be placed. Why are these not the same View Controller? (generally view controllers are meant to control a "screenful" of content, unless you are using View Controller Containment). If these two view controllers are not on the screen at the same time, can you use a segue to pass data between them when the transition occurs?
UPDATE:
The additional information is useful for me to give you a recommendation. The thing I'm still uncertain about is if you actually do have these 2 view controllers' views on screen at the same time. This solution should work in both cases.
Outside of a segue, one view controller should not really be calling another view controller's methods directly (so calling setsession as you described is a bad idea). You shouldn't even set one as the delegate of another. At most they should share a Model object to communicate. The OTSession can be seen as a Model object. The challenging limitation is that when using the delegation pattern, only one object (you chose Class B) can be informed of updates. Rather than using the delegation pattern, I think you should use NSNotifications. In order to accomplish this, you should "wrap" the OTSession model in your own model object, setting your own model object as the delegate. Then you can notify both controllers of interesting changes as they happen. I've created a diagram to demonstrate:
In this diagram, all the downward solid arrows are owning references. VideoConference would be your own class and it would implement the OTSessionDelegateProtocol. On initialization, the VideoConference instance would create and own an OTSession instance. When something happens that Class A or Class B need to know about (such as the remote user coming online), VideoConference can send an NSNotification, which both controllers can be observers. Here is a useful article about NSNotifications.
I have a UINavigationController that has a bunch of PhotoViewAViewControllers in its stack.
This happens because each PhotoViewAViewController has a button to add more photos and it chains them together. There is also a count on each page of the total.
How do I update the count? I have read to do this use delegation. But can a class be a delegate of itself?
Also curious, can class A be a delegate of class B and vice versa?
Yes, an instance of a class can be a delegate for itself, or you could have a circular delegate relationship. Neither of these situations are common though.
In your case you should post a notification when the count changes so that all interested controllers can observe the event and update.
Note that an alternative is to check and update the count in viewWillAppear:
I am trying to build a MVC app with Objective-C. It is supposed to be a questionnaire app. I have all the questions and multiple choice answers stored into a property list, because I have different of questionnaires that I want to be able to load with this app. The idea is that the main model will keep track which item it should read of the property list, and select the corresponding view and viewController.
So schematically I have the following problem.
The RootView shows the start menu, that selects which questionnaire you will be able to take.
The RootViewController is the first controller called by the app delegate. It is supposed to instantiate the model and show the RootView. It furthermore controls the buttons of the RootView.
The model is supposed to wrap the items of the property list into a fitting datastructure, and supply it to the view controllers that need it.
The SelectedViewController is a controller that is a template specifically made for a type of question. The question could be a multiple choice, an open question, a 3, 5 or 7 choice likert scale kind of question, anything really. The template name that these view controllers will really get is ViewController.
The SelectedView is a tailor made view to the question type and will get the same name format as all the selected view controllers.
Here are my ideas.
My initial hunch is to use the delegate pattern, and set the model as a delegate to any SelectedViewController.
I could also use the delegate pattern to the RootViewController, and let him monitor if the SelectedViewController should be destroyed (via a delegate message). In that case, I can implement a prepareForSegue in the RootViewController to the SelectedViewController.
Since it is a questionnaire from a plist I could also add a prepare for segue to
every selected viewcontroller, but that will probably be a problem,
since there are at least 15 different ways of displaying the
questions.
Apparently there is also something like Key-Value Observing, according to this question. So that's also something I could use.
I think there is a definite way to deal with this, because the design patterns in iOS are pretty wel described, so there should be a few options for this really (or only just one). At the moment I am leaning towards setting the RootViewController as a delegate to the SelectedViewController and let the RootViewController handle the model. In this way I am extending the RootViewController to also hold all common functionality that every SelectedViewController should have.
But I am really not sure if this is the way to go, because my knowledge on design patterns is limited. My question is: what is the right option to choice in this specific situation (e.g. views and view controllers selected via a .plist file)?
There is no need for a specific pattern - you can deal with accessing an instance of a model object by name, i.e. in the same exact way that you deal with making a specific view and the view controller.
Let's say you are looking to connect the QuizQuestionViewController4MC and its QuizQuestionView4MC to their model. Let's assume that the model class is called QuizQuestionModel4MC, and that it needs to be configured with an object that you get from a key #"4MC" in the plist. Since your code learns the name of the model class only at runtime, you can create an instance using reflection:
NSDictionary *dataFromPlist = ... // Someone passes this to you
NSString *identifier = dataFromPlist[#"identifier"]; // Returns #"4MC"
NSString *ctrlName = [NSString stringWithFormat:#"QuestionViewController%#", identifier];
NSString *modelClassName = [NSString stringWithFormat:#"QuizQuestionModel%#", identifier];
id model = [[NSClassFromString(modelClassName) alloc] init];
// Configure the model with the data from plist
[model setPlistData:dataFromPlist];
// The model is ready to be used - give it to the view controller
MyBaseViewController *ctrl = [storyboard – instantiateViewControllerWithIdentifier:ctrlName];
// Give the view controller its model - now it is ready to be used
[ctrl setModel:model];
Note the class of the view controller - MyBaseViewController. This is not your root view controller, it's a base class for all your specific view controllers. It is this view controller that knows about a model, but it does not know the specific subclass in the model hierarchy. Each subclass of the view controller knows about its specific model subclass, so it can access the information from the model class directly, without going through selectors or KVP.
Of course it is up to the designer of the app to "wire up" correct view controllers to the correct models. In terms of the above example, QuizQuestionViewController4MC needs to know the structure of the QuizQuestionModel4MC in order to avoid sending unrecognized selectors to an incorrect class.
I have one problem let assume A and B are 2 view controller from A user push to B view controller,In B user starts some download by creating object C(which is NSObject class) and sets B as delegate to C(assign),now user want go back to A then dealloc of B calls object releases, C delegate fails to give call back(crashes).I want to get call and allow user to move to other view controller thats way i am retain the delegate in C class but retain of delegate is wrong ...
what are all solutions ...
Thanks in Advance.
I see two options:
You do not need the downloaded data. Solution: set the delegate to nil.
You need the data. Solution: You either set a new delegate that exists, or the delegate should make sure it will be around (f.e. by being a singleton)
That happens because of an issue in your architecture: you're assigning the global task of background downloading to a view controller that may or may not be in memory.
If you want to be able to continue the download regardless of the presence of B, then:
Create a class "downloader" that takes care of downloading files (I believe you call it C in your example).
Such class should have a delegate of type "weak" so that if the original delegate goes away, the app won't crash (NOTE: this is only available if you use ARC). If you need to globally monitor the progress of your download, switch to NSNotification instead of delegate so that multiple object can monitor at the same time.
Initialize an instance of C somewhere else: either in A or before that.
Inject the instance of C into B so that B by creating a custom init method or a #property.