I'm working on a project in objective C where i have to modificate some variables which are in a view controller from uiviews.
So i've tried somethings like this :
ViewController.h :
#property (nonatomic) bool Contact;
One of the UIViews :
ViewController * View;
View.Contact = YES;
I've also tried to make a setter method like this in the ViewController :
-(void) SetterContact:(bool)boolean;
And so to modificate from a UIView like this :
[View SetterContact:YES];
But it's looking working.
I've read that i have to init the object in which is containt the variable, but in memory management it's not really good to make some initializations from object who are already actives no ?
So if View is already init, i'm not going to call the init method from another UIView no ?
Thanks for your help !
If you want bool variable to be accessible from other viewController.Then simply wirte it as :-
#property BOOL Contact;
and make an object of ViewController in which you have declared contact variable as BOOL and access this variable using like this:-
OtherViewController *otherViewController=[[OtherViewController alloc] init];
otherViewController.Contact=YES;
As it is a instance variable it has to be accessed using class object.
use #property (nonatomic, assign, getter = isContact) BOOL contact; in your .h file.
Respect naming conventions
#property (nonatomic,retain) UIViewController *myController;
don't forget to synthesize
#synthesize myController = _myController;
If you want to implement your own setter do this: respect the naming convention
-(void)setMyController:(UIViewController*)controller;
or if by any bizarre reason you can't respect naming convention you can point the property to the method you want
#property (nonatomic,retain,setter=myBizarreSetterMethod:) UIViewController *myController;
this can help you out as well question in stackoverflow
Related
i have defined variable in GroupView.h
#interface GroupView()
{
NSMutableArray *chatrooms;
}
#end
#implementation GroupView
Now i want to pass this variable in segue
#interface FriendsViewController ()
#end
#implementation FriendsViewController
else if ([segue.identifier isEqualToString:#"showGroupView"]) {
GroupView *groupView = (GroupView *)segue.destinationViewController;
groupView.chatrooms = [NSMutableArray arrayWithArray:chatrooms];
}
i know that chatrooms has to be property in header file to code this way but it is not
So is there any way to use this variable in segue.
Thanks for help.
chatrooms defined as an ivar like you have done is accessed using -> notation:
groupView->chatrooms = [NSMutableArray arrayWithArray:chatrooms]
This is generally discouraged, though. You should use a property instead:
#interface GroupView
#property (strong) NSMutableArray *chatrooms;
#end
Incidentally, if you're using an NSMutableArray, that indicates that you want to modify the element list of the array directly and not just replace the array wholesale. If you only ever want to replace the array with a whole new array every time, I suggest using NSArray instead.
Another point to make here is that you're attempting to cast the object held at segue.destinationViewController as a GroupView. You have either named a UIViewController subclass in a very misleading way, or you are not accessing the GroupView as a correct member of the UIViewController that is returned to you.
Normally, if you are not building the SDK or something. You don't really have a better reason not to expose it in the header file. However, you can expose the property in the extension and declare a private property in the host class(It's really not able to pass if you just declare a local variable). For example, You have a extension called GroupView+Helper. So, you can pass it into the property exposed in the extension. And then internally translate into the GroupView.
In GroupView.m:
#interface GroupView
#property (strong, nonatomic) NSMutableArray *chatrooms;
#end
In GroupView+Helper.h
#property (strong, nonatomic) NSMutableArray *internalChatrooms;
Also, you need to import the GroupView+Helper in the GroupView.
It will make your chatrooms private and internalChatrooms protected.
I am trying to do the following, and not able to find a straightforward answer.. It is related to this :Passing uitextfield from one view to another. But not exactly.
I have a Firstview.m, from which I push to a Secondview.m. The Secondview.m has a UITextView. I allow the user to edit the UITextView on Secondview.m. Now I want to store this text value in a variable in Firstview.m. One way to to do this is as follows
in Firstview.h
#property (nonatomic) Secondview *secondView;
That is keep a secondView variable in Firstview itself. But this doesn't seem efficient. Ideally I should only have 1 NSString text field in FirstView. What is the right way to do this ? Thanks
You can achieve this by using Delegation in Objective-C.
In your SecondView.h add following right after Header Inclusion
#protocol YourDelegateName <NSObject>
-(void)setText:(NSString *)strData;
#end
Also add delegate property to your header for accessing them in calling class, like below (This goes with other properties declaration in SecondView.h file):
#property (nonatomic, weak) id<YourDelegateName> delegate;
Now, Comes the calling the delegate part. Say, you want to save the text value of UITextView of SeconView in strTextViewData of FirstView class, when the following event occurs:
- (IBAction)save:(id)sender
{
[self.delegate setText:self.txtView.text]; // Assuming txtView is name for UITextView object
}
Now, In FirstView.h add YourDelegateName in delegate list like below:
#interface FisrtView : ViewController <YourDelegateName>
#property (nonatomic, reatin) NSString *strTextViewData;
#end
And then in FisrtView.m file when you create instance of SecondView class, set delegate to self like below:
SecondView *obj = [[SecondView alloc] initWithNibName:#"SeconView" bundle:nil];
obj.delegate = self; // THIS IS THE IMPORTANT PART. DON'T MISS THIS.
Now, Implement the delegate method:
-(void)setText:(NSString *)strData
{
self.strTextViewData = strData;
}
Applying this to your code will do what you want. Also, Delegation is one of the most important feature of Objective-C language, which - by doing this - you will get to learn.
Let me know, if you face any issue with this implementation.
Simple question, I would just like to hear what other people do, and what best practice might be. To clear some things up.
When declaring an instance variable in one of my view controllers. Where is the proper place to declare it? I want the instance variable to available to all methods/function in the view controller
I've seen it done this way, in the .h file in curly braces after the #interface:
#interface ViewController : UIViewController {
NSString *test3;
}
I've seen it done this way, in the .m file in curly braces after the #interface:
#interface ViewController () {
NSString *test1;
}
And I've seen it done this way, in the .m file in curly braces after the #implementation:
#implementation ViewController {
NSString *test2;
}
What is the best practice? Is there any difference? If so what may they be, and what makes one way better than another?
All help will be appreciated,
Thanks.
Any of those will work, but current best practice is to use a property. If you want it to be accessible only inside your class:
#interface ViewController ()
#property (copy, nonatomic) NSString *test1;
#end
An access it like this:
self.test1 = #"Hello, world";
But, if you want it to be accessible to other classes as well, put it in the public interface:
#interface ViewController : UIViewController
#property (copy, nonatomic) NSString *test1;
#end
And then access it like this:
someInstanceOfViewController.test1 = #"Hello, world";
If you need to access the instance variable directly (and this applies only inside the class in most cases), for example if you are making a custom setter, the compiler will auto-synthesize an ivar that is the name of your property prefixed with an underscore:
- (void)setTest1:(NSString *)test1
{
_test1 = [test1 copy];
}
Note: the copy is because you might set test1 to an instance of NSMutableString, and you probably don’t want its contents getting mutated out from under you. When you override the setter, as above, you have to enforce this copy semantic yourself.
Super class Resource
#interface Resource : CoderObject
#property (strong, nonatomic) NSString *resourceID;
#property (assign, nonatomic) ResourceType resourceType;
#property (assign, nonatomic) DataType dataType;
#end
Subclass ViewResource
#interface ViewResource : Resource
#property (strong, nonatomic) CustomView *view;
#property (strong, nonatomic) UIViewController *viewController;
#end
In subclass ViewResource's init method how to access Resource's variable dataType? Now I'm trying to just use super.dataType = ...
Is there other ways?
You just need to use self.dataType. Your subclass has full visibility of all of the superclass properties defined in the .h file. Using self.xxx also gives you the ability to override the accessor methods if required in the future without coming back to edit all of your usage code.
Looking at your link below, fair enough. Those are all valid points. Accessors shouldn't have side effects but you can't guarantee they won't. If the property is defined the superclass then you have a couple of options:
Use self.xxx to set the property and endeavour to ensure no side effects
Call an init method on super, passing the required parameters, and set them there
Like Wain stated in his answer you have direct access to your super's class members (if they are not private).
And there is no problem calling self.property in the init method as long as your init looks like this
-(id)initAndTheNameYoWantAndMaybeSomeParameters:(NSString *)paramExample {
self = [super initNameOfAnInitMethodFromSuperClass];
//check if the init was with success
if(self != nil) {
self.myStringProp = paramExample;
//or
self.propertyFromSuper = paramExample;
}
}
Yes, you can also do stupid stuff in the initMethods (I did it before :)) ) like calling the same initMethod from inside it which was generating a recursive calling that was crashing my app. (Easy to spot this issue)
Let's consider an application with highly customized or complex views.
We'll have a specific kind of view-controller sending methods to a specific kind of UIView, where the UIView is itself composed of a number of other views.
The view should have a rich, domain-specific interface, allowing the controller to act is a thin "glue" layer between it and a similarly rich model.
So we override our controller's view property as follows:
#interface PlaybackViewController : UIViewController<StageLayoutDelegate, ControlPanelDelegate>
{
NSMutableArray* _sections;
LightingMode _lightingMode;
}
#property (nonatomic, strong) PlaybackView* view; // <------ Specific type of view
#pragma mark - injected
#property (nonatomic, strong) id<OscClient> oscClient;
#property (nonatomic, strong) AbstractStageLayoutView* stageLayoutView;
#end
Ovverriding makes sense over defining another accessor, and I can just send messages to the specific type of UIView without having to cast.
Problem: The only problem is that it results in a compiler warning:
property type 'PlaybackView *' is incompatible with type 'UIView *' inherited from 'UIViewController'
. . and I like to build code that doesn't have any warnings. This way a valid warning doesn't get missed by being buried amongst other warnings.
Question:
Is there a way to suppress this particular warning?
Why is this part of the default settings, when most modern OO languages will happily allow overriding a property or method in a sub-class so that it returns a more specific sub-class of the type declared in the super-class?
The problem here is not not the override of the property, its using a forward declaration of the class type.
So this...
#class PlaybackView;
#interface PlaybackViewController : UIViewController
#property (nonatomic, strong) PlaybackView* view;
#end
will give you the mentioned warning because the compiler cannot know the inheritance hierarchy of PlaybackView. UIViewController has a contract to provide a UIView from its view property
Its telling you that it thinks PlaybackView is not a UIView
The simple solution here is to use a #import instead to give the compiler full knowledge of PlaybackView...
#import "PlaybackView.h"
#interface PlaybackViewController : UIViewController
#property (nonatomic, strong) PlaybackView* view;
#end
alternatively (but really bad form as the PCH is an optimising feature and shouldn't manage dependancies ) is to add #import "PlaybackView.h" to your projects PCH
As suggested in another answer using #import instead of #class will clear the warning but it is advised to import as little as possible in the header, so I would recommend leaving the view unchanged and having an additional PlaybackView * playbackView:
It is perfectly fine to have both view and playbackView pointing to the same view.
Classes that need to have knowledge of your specialized view have to import your controllers header, so they could just use playbackView in the first place.
More important, if you want to embed your specialized view as a subview in the future (which happens often like adding a UIScrollView superview), you won't have to refactor other code and classes!
It's plain cleaner.
I do not think override UIViewControllers view property is a good way .
I think it is better to do like this :
#interface PlaybackViewController : UIViewController<StageLayoutDelegate, ControlPanelDelegate>
{
NSMutableArray* _sections;
LightingMode _lightingMode;
}
//#property (nonatomic, strong) PlaybackView* view; //you do not need this property
#pragma mark - injected
#property (nonatomic, strong) id<OscClient> oscClient;
#property (nonatomic, strong) AbstractStageLayoutView* stageLayoutView;
#end
and in the .m file .
- (void)loadView
{
PlaybackView *mainView = [[PlaybackView alloc] initWithFrame:[UIScreen mainScreen].applicationFrame];
// set the mainView
self.view = mainView;
}
and you can use your PlaybackView like this .
((PlaybackView *)(self.view)).oscClient
or
((PlaybackView *)(xxxViewControler.view)).oscClient
Perhaps you could declare another method that provides the cast for you, in a sense.
#implementation PlaybackViewController
- (void)viewDidLoad {
[super viewDidLoad];
// use view_ property instead of view
self.view_.foo = 1;
}
- (void)loadView {
CGRect frame = [UIScreen mainScreen].applicationFrame;
self.view = [[PlaybackView alloc] initWithFrame:frame];
}
- (PlaybackView *)view_ {
return (PlaybackView *)self.view;
}
Not exactly the cleanest approach, but it does avoid the cast on self.view (by not using self.view, though)
[UPDATE]
Finally I've probably found a solution that suit the problem:
This is a quick and dirty just to suppress the warning, try to wrap your code between these lines
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
//YOUR CODE
#pragma clang diagnostic pop
or -Wall
To see more about compiler warning suppression Clang Manual
[OLD ANSWER]
I'd like to give my 2 cents.
If I understood well you are trying to create a sort of Abstract factory, that gives you a specialized version of a view based on the view controller funcionality. In my opinion storyboards doesn't work well in that kind of design, but I'd like to give you my vision about it.
First I will create an abstract class for your view controller where in the interface you declare all property you need in all your VC sublcasses, such as :
OSClient
AbstractStageLayoutView
PlaybackView as weak
playbackProperty
The PlaybackView class is a class cluster such as NSNumber, you call a factory method on it, that will return an object that could be different from case to case. If you inspect an NSnumber it returns a different object if you create a float or an integer, but they are all subclasses of NSNumber, and NSNumber declares all the property of its subclasses, but it doesn't implement them.
Now what you can do in the -viewDidLoad method of the abstract class is call a method like that
PlaybackView *plbackView = [PlaybackView playbackViewFroProperty:self.playbackProperty];
[self.view addSubview:playbackView];
self.playbackView = plbackView;
The playbackProperty can be valued inside the User defined runtime attibute in the viewcontroller storyboard editor.