I have a sequencer with each track that has buttons as an outlet collection. The code all works fine in it's own view controller however I want to transfer all the methods to a singleton so that I can control the playback from other views.
for instance I have
#property (strong, nonatomic) IBOutletCollection(UIButton) NSArray *trackOneOutletCollection;
However I have methods which act on the alpha and tags of each button; the methods contain these vales which I don't know how to access from the singleton. I thought the singleton was where I store all the data and then call it from the class file view controller?
You can use Inheritance concept to achieve this functionality.you need to create one ParentViewController that hold IBOutletCollection property. and rest of all View Controller is child of ParentViewController. then you can access IBOutletCollection in other view ontroller. like this way.
ParentViewController:-
#interface ParentViewController : UIViewController
#property (strong, nonatomic) IBOutletCollection(UIButton) NSArray *trackOneOutletCollection;
#end
ChildViewController;-
#interface YourViewController : ParentViewController
#end
.m file
#implementation YourViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"trackOneOutletCollection = %#"self.trackOneOutletCollection);
}
#end
Related
//MigrationVC.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#interface MigrationVC : UIViewController
#end
//MigrationVC.m
#import "MigrationVC.h"
#interface MigrationVC()
#property (strong, nonatomic) IBOutlet UILabel *label;
#property (strong, nonatomic) IBOutlet UIProgressView *progressView;
#end
#implementation MigrationVC
#end
//CoreData
#import "CoreData.h"
#import "MigrationVC.h"
#interface CoreData()
#property (nonatomic,retain) MigrationVC *migrationVC;
#end
-(void)obsererForKeyPath:(NSString*)keyPath object:(id)object change:(NSDictionary*)change context:(void*)context
{
if([keyPath isEqualToString:#"migrationProgress"])
{
dispatch_async(dispatch_get_main_queue(),^{
float progress=[[change objectForKey:NSKeyValueChangeNewKey] floatValue];
self.migrationVC.progress=progress;
});
}
}
I am trying to learn CoreData and migration right now but this is giving me a quite a headache.
I am trying to access the outlet properties from another classes but always gives red warning (Property 'label' not found on object of type MigrationVC*).
I tried adding a NSString property in .h file which was accessible but when i tried to change the outlet from .m to .h file i couldn't ctrl+drag the view in the .h file.
I never had this problem. I have accessed outlet from .m file many times in the past but it just gives me warning now.
How can i access the properties while outlet in .m file?
I cannot outlet the properties in .h file.
You have to transfer you outlet properties from .m file to .h file (copy and paste). If you want your properties to be public so they have to be declared in header file. If you want them to be private - declare them in implementation file.
//MigrationVC.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#interface MigrationVC : UIViewController
#property (strong, nonatomic) IBOutlet UILabel *label;
#property (strong, nonatomic) IBOutlet UIProgressView *progressView;
#end
//MigrationVC.m
#import "MigrationVC.h"
#interface MigrationVC()
#end
#implementation MigrationVC
#end
As others have pointed out, you need to declare your properties in your header file if you want them to be accessible from other classes. You can, and you should. If you think you can't do that, explain why.
More important, though, is that you should not do what you are trying to do. You should not try to access a view controller's view objects from outside the view controller. That violates the principle of encapsulation, an important principle of object-oriented design. (It means that code outside of your view controller is dependent on the appearance of your view controller. If you later decide to make internal changes to your view controller, you are very likely to break outside code.) In addition to the somewhat abstract "It's bad design" reason for not doing it, it often doesn't work, because at the time to try to modify a view controller's views, they don't exist yet.
Instead, you should create DATA properties (like strings, or floating point progress values) in your view controller and expose those. Then have your view controller's viewWillAppear method install the data into it's views as appropriate. That way the data properties become part of the view controller's public contract without being tied to the internal details of the view controller.
You properties are declared in the private category so they are not visible for other classes. Only properties declared in a header file are visible.
In CoreData.m your MigrationVC is set as retain. I don't know if you can use it since with ARC.
#property (nonatomic,retain) MigrationVC *migrationVC;
It should be
#property (nonatomic,strong) MigrationVC *migrationVC;
And in MigrationVC your outlets should be weak not strong and in .h to be accesible from CoreData.m
I am planning to create two UIViewController. Basically, there are some buttons in one of the two view controllers. When I press one of these buttons, I want to trigger some action in another view controller. Are there some ways to make it possible?
There are so three possible ways to do that,
Using NSNotificationCenter, Using Delegates and the last one is using Blocks, The first option is easy to learn.
Add the observer in to FirstViewController
Post notification in SecondViewController (when user clicks the button)
For reference follow this link
Hope this helps
Yes, you can use a delegate for that.
For example, you may have this ViewControllers.
//FirstViewController.h
#protocol ProtocolName <NSObject>
- (void)doSomething;
#end
#interface FirstViewController
#property (nonatomic, strong) id<ProtocolName> delegate;
#property (weak, nonatomic) IBOutlet UIButton *button;
- (IBAction)action:(id)sender;
#end
Here we need a protocol, who defines one or more methods to be implemented in any Object who implement this protocol. And also we need a delegate, that is an object who implements this protocol (in this case called "ProtocolName", but you can name it as you wish).
And then a second ViewController
//SecondViewController.h
#import "FirstViewController.h" //Need this to reference protocol
#interface SecondViewController <ProtocolName>
#end
With we are saying that SecondViewController will implement ProtocolName protocol, so in his .m file we need to do this.
//SecondViewController.m
- (void)doSomething{
//Do something
}
And here comes the magic.
Let's say that when you tap the button in FirstViewController it triggers the doSomething method in SecondViewController. So, you need to do something like this.
//FirstViewController.m
//...
SecondViewController secondVC = [[SecondViewController alloc] init];
this.delegate = secondVC; //DON'T FORGET THIS
//...
- (IBAction)action:(id)sender{
[this.delegate doSomething];
}
And this is the delegate pattern.
When the views are simple, their IBActions and IBoutlets are in viewcontroller, viewcontrollers assigns respective models to be loaded and viewcontroller get notified when models are prepared.
As My project contains lot of custom views for each viewcontroller, I want to implement actions in custom view itself and set data from controller (ViewController).
I should be able to use the same controllers and models for both iPhone and iPad where only UI changes.
I am concerned about how to pass data from view to viewcontroller and displaying data back on view when model changes?
Can anyone please suggest me to pass data between views <---> viewcontroller (controller) <---> model?
To do this I use Delegate design-pattern. It looks like this :
MyView.h
#protocol MyViewDelegate <NSObject>
- (void)customViewDidSomething;
#end
#interface MyView : UIView
#property (nonatomic, assign) id<MyViewDelegate> delegate
#end
MyView.m
- (void)userDidSomething {
[_delegate customViewDidSomething];
}
MyViewController.h
#import "MyView.h"
// ViewController has to implement the protocol
#interface MyViewController <MyViewDelegate>
#property (nonatomic, retain) IBOutlet MyView myView;
MyViewController.m
- (void)viewDidLoad { // Set the delegate somewhere
_myView.delegate = self
}
- (void)customViewDidSomething {
// Ok VC is aware that something happened
// Do something (tell subview to do something ?)
}
Instead of using different custom views, try using a UIViewController and then use the viewcontroller's view to display your UI. Also, this will also ensure that you will be able to communicate between the views and controller efficiently without confusion.
I have a UIViewsubclass. I am not able to create an instance of another View Controller in this UIView class, so that i can access the variables set in my UIView subclass in this View Controller? Can anyone guide me on this
#import <UIKit/UIKit.h>
#import "DirectoryFormViewController.h"
#class NIDropDown;
#protocol NIDropDownDelegate
- (void) niDropDownDelegateMethod: (NIDropDown *) sender;
#end
#interface NIDropDown : UIView <UITableViewDelegate, UITableViewDataSource>
{
NSString *animationDirection;
UIImageView *imgView;
DirectoryFormViewController *dict; // i am not able to create this
}
#property (nonatomic, retain) id <NIDropDownDelegate> delegate;
#property (nonatomic, retain) NSString *animationDirection;
-(void)hideDropDown:(UIButton *)b;
- (id)showDropDown:(UIButton *)b:(CGFloat *)height:(NSArray *)arr:(NSArray *)imgArr: (NSString *)direction;
#property(nonatomic)int countryID;
#end
My DirectoyFormViewController:
#import <UIKit/UIKit.h>
#import "NIDropDown.h"
#interface DirectoryFormViewController : UIViewController<DropDownListDelegate,CLLocationManagerDelegate,UISearchBarDelegate,UITextFieldDelegate,NIDropDownDelegate>
#property(nonatomic)NSMutableDictionary *countryName;
#property(nonatomic,copy)NSMutableDictionary *sortName;
#property(nonatomic,copy)NSMutableDictionary *resultName;
#end
I want to set countryName,sortName and resultName in my NIDropDown
Thanks
Here's the short answer: you should never, ever, not for any reason create an instance of a view controller inside of a UIView. So the fact that you have not been successful so far is a good thing.
The Apple way of development on iOS is to use the Model, View, Controller design pattern. In MVC, the controller controls the models and the views and mediates communication between the two... not the other way around.
My suggestion is that you read the link and fully understand it before moving forward with development. With an understanding of the topics covered you'll never do things like have a UIView that's a table view delegate / datasource (because by doing that, your view is aware of the model, and that breaks MVC), and you'll hopefully never try to do things like create a UIViewController in a UIView.
I have a storyboard in which I have specified a parent view controller and two container views (made up of two UITableViewControllers). In my parent view controller I have buttons that are used to filter the content of the two tables.
My problem is figuring out how to send messages to the container views to perform these filters. I imagine we use delegates but is there a best practice way of implementing these delegates?
Subject to some caveats, you could define properties for each of the two contained tables, connect the outlets in your .xib, and message them directly in your button handlers.
For example:
#interface ParentViewController : UIViewController
#property (nonatomic) IBOutlet Table1Class *table1;
#property (nonatomic) IBOutlet Table2Class *table2;
#end
#implementation ParentViewController
...
- (IBAction)table1FilterButton:(UIButton *)sender
{
[self.table1 filterBy:...];
}
- (IBAction)table2FilterButton:(UIButton *)sender
{
[self.table2 filterBySomethingElse:...];
}
#end
Now, the caveats - you probably won't want to do this if you anticipate that the number of contained view controllers is likely to grow significantly, as it will be unwieldy to have table1, table2, table3, ..., tableN. You'll probably also want to find a way to extract a common interface (in the form of a protocol) from the two contained view controllers, in order to write less divergent code for handling the filtering of each table.
Maybe something like this, instead:
#protocol ContainedTableProtocol
#property (nonatomic) NSPredicate *contentFilterPredicate;
#property (nonatomic) NSComparator sortComparator;
#end
#interface ParentViewController : UIViewController
#property (nonatomic) IBOutlet UITableViewController<ContainedTableProtocol> *table1;
#property (nonatomic) IBOutlet UITableViewController<ContainedTableProtocol> *table2;
#end
#implementation ParentViewController
- (IBAction)filterTable1ButtonAction:(UIButton *)sender
{
[self filterTable:self.table1];
}
- (IBAction)filterTable2ButtonAction:(UIButton *)sender
{
[self filterTable:self.table2];
}
- (void)filterTable:(UITableViewController<ContainedTableProtocol> *)table
{
// Create predicate and comparator as needed...
NSPredicate *predicate = ... ;
NSComparator comparator = ... ;
table.contentFilterPredicate = predicate;
table.sortComparator = comparator;
}
#end
This uses a common interface to apply the filtering operations to each table view controller, and then codes to that interface rather than an API specific to a particular Table1Class or Table2Class.
You can see the answer at How do I create delegates in Objective-C?.
The simpler way is declare the delegate in the Childs and implement in the parent (ie: The childs send data to the parent).