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.
Related
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
I have created a custom class "CustomSCNView" that inherits from SCNView. I want to use the custom class in another view controller. So I need to create a CustomSCNView object and use it to another class to manipulate things. But how can I create a CustomSCNView object in another class.
This is not working:
CustomSCNView *customView = [[CustomSCNView alloc]init]; //in viewcontroller.m
Sorry forgot to mention I used the interface builder to drag a SCNView to the view controller and then set its class to CustomSCNView.
I'm a bit confused by your question, but I've created a sample project at https://github.com/NSGod/CustomSCNView that may do what you're looking for.
First, the storyboard has 2 CustomSCNViews laid out side by side in the ViewController's view. Like you did, I dragged 2 SCNViews from the IB palette to the view and then set the custom class to be CustomSCNView.
Second, is the CustomSCNView class which is defined as follows:
#import <Cocoa/Cocoa.h>
#import <SceneKit/SceneKit.h>
#interface CustomSCNView : SCNView
#property (nonatomic, assign) BOOL allowsRotation;
#end
You can see, it has an allowsRotation property that any other object can set.
To set a default value for allowsRotation, other than NO, you can override initWithCoder: which is what's used when you set up the views in Interface Builder like you did:
#import "CustomSCNView.h"
#implementation CustomSCNView
- (id)initWithCoder:(NSCoder *)coder {
if ((self = [super initWithCoder:coder])) {
_allowsRotation = YES;
}
return self;
}
#end
The ViewController then has 2 IBOutlets to both CustomSCNViews.
#import <Cocoa/Cocoa.h>
#import <SceneKit/SceneKit.h>
#class CustomSCNView;
#interface ViewController : NSViewController
#property (weak) IBOutlet CustomSCNView *sView1;
#property (weak) IBOutlet CustomSCNView *sView2;
#end
ViewController.m:
#import "ViewController.h"
#import "CustomSCNView.h"
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_sView1.allowsRotation = NO;
_sView2.allowsRotation = YES;
}
#end
You can see that in viewDidLoad, you can set the allowsRotation property of both views to whatever you want. When you run this application, 2 instances of CustomSCNView are created for you automatically (via initWithCoder:), when the storyboard/nib files are loaded. There's no need to create another instance of a CustomSCNView to be able to set the properties of the 2 existing instances you already have.
If you look at the documentation for SCNView it tells you:
You can create a SceneKit view by using its initWithFrame:options:
method or by adding it to a nib file or storyboard.
So you cannot use the init method unless you have implemented your [CustomSCNView init] method to call [super initWithFrame:options:].
If you need access to custom subclass properties from Interface Builder, mark those properties IBInspectable (and possibly implement IBDesignable). That's documented by Apple here, and nicely summarized on NSHipster.
In any initialization path, you must call the superclass's designated initializer. For SCNView, that appears to be initWithFrame:options: (not documented as such, but the header strongly implies it). See this document on multiple initializers and subclassing.
That said, though, subclassing SCNView is a code smell that you might be fighting the framework and working too hard.
//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 have UIViewController named ParentViewController.h and .m
Then I added UIView inside this ParentViewController.
I had uiview.h and uiview.h added and assigned to UIView inside ParentViewController.
From
-(void)drawRect:(CGRect)rect {}
which is located in uiview.m, I need to access to properties inside ParentViewController.
How do I do this? Am I using UIView wrong?
ParentViewController.h
#import <UIKit/UIKit.h>
#interface ParentViewController : UIViewController
//I want my uiview to access this variable.
#property (nonatomic, strong) NSMutableArray *usedByUIView;
#end
ParentViewController.m
#import "ParentViewController.h"
#import "uiview.h"
#implementation ParentViewController
- (void)viewDidLoad {
...
}
#end
uiview.h
#import <UIKit/UIKit.h>
#interface uiview : UIView
#end
uiview.m
#import "uiview.h"
#implementation uiview
-(id) initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if(self){
}
return self;
}
- (void)drawRect:(CGRect)rect {
NSLog(#"start drawing using the data from usedByUIView");
}
#end
There are a few answers on this subject but, summarizing them, you don't, at least not the way that you're doing it. UIView's do not have access to their view controller's and aren't supposed to need access. Of course, in the real world, sometimes it's not worth the overhead of coding around independent views so people hack in access to the controller access. This can be done by keeping an instance variable in the view, pointing to the controller, and assigning a reference to it after the view has loaded, or by overriding the init so you also pass a view controller, or lots of other ways. But before you do that think through the logic of why you want access to the controller from the view and see if there isn't a different way to do it.
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.