Object addSubview only works in viewDidLoad - uiview

I'm new to iPhone dev and need some help with adding subViews.
I have a reusable object that I made that is stored in a separate .h .m and xib file.
I would like to use this object in my main project's view controller. I have included the header and the assignment of the object generates no errors. I am able to load the object into my main project but can only do things with it inside my viewDidLoad method. I intend to have a few of these objects on my screen and am looking fora solution that is more robust then just hard wiring up multiple copies of the shape object.
As soon as I try to access the object outside of the viewDidLoad it produces a variable unknown error - first use in this function.
Here is my viewDidLoad method:
shapeViewController *shapeView = [[shapeViewController alloc] initWithNibName:#"shapeViewController" bundle:nil];
[self.view addSubview: shapeView.view];
// This is the problem line
// This code works changes the display on the shape object
[shapeView updateDisplay:#"123456"];
---- but the same code outside of the viewDidLoad generates the error.
So to sum up, everything works except when I try to access the shapeView object in the rest of the methods.
Thanks in advance

You need to declare the shapeView instance in your interface, not just inside one function. Then the code in the function becomes just an initialization.
So, in your .h file, inside the #interface you write the declaration:
shapeViewController *shapeView;
And in your viewDidLoad, you will initialize what you declared before:
shapeView = [[shapeViewController alloc] initWithNibName:#"shapeViewController" bundle:nil];
[self.view addSubview:shapeView.view];
Now you can use shapeView in your entire class.

Related

MapController Alloc Init & ViewController alloc init Resulting in loop

I Have a very long view controller.m which I'm trying to split into separate files to keep it organised.
I know I can create separate .m .h files and separate them but in doing so I am ending up in loops (which I Understand since the MapController.m is initialising the viewcontroller again causing viewDidLoad to be triggered and repeat.
I have a Map I want to create in my MapController.m
-(void)setMapSettings{
NSLog(#"test");
viewController = [[ViewController alloc] init];
SKMapView *mapView = [[SKMapView alloc] initWithFrame:CGRectMake( 0.0f, 0.0f, CGRectGetWidth(viewController.view.frame), CGRectGetHeight(viewController.view.frame) )];
}
I want to add the above SKMapView to a UIView called mapViewContainer in my viewController.h
ViewController.m:
- (void)viewDidLoad {
mapsViewController = [[MapController alloc] init];
[mapsViewController setMapSettings];
}
Doing this creates a loop resulting in a crash. I know the answer is probably dead simple and I'm just being stupid, but I've spent hours finding a solution and I can't figure it out. Any idea's how I'm suppose to be able to do the above without looping, and without initialising the map views I require all in the ViewController.m?
You say that you are splitting the view controller by taking out code from it, but as far as I understand this has resulted in creating a second viewcontroller (either this, or "MapController" isn't the right naming).
Anyways, as you already mentioned the crash is definitely caused by that alloc/init loop: you should reengineer your code to have just one of the two objects instantiating the other.
(please bear in mind that if you are doing that to access one object from the other, you're doing it wrong: alloc/init creates a new instance of that class every time it is called, it does not give you a pointer to an existing one)

Can the same ViewController.view be added as subview to different views as a Singleton?

My app has a search view(search bar) which is used all over the app. I don't want to create duplicated code so I created a view controller called MySearchViewController to handle the search job, then I created a singleton object in AppDelegate. In every view controller, I added my search view like this:
- (void)viewDidLoad
{
MySearchViewController* search = [AppDelegate searchViewController];
[self.view addSubView:search.view];
}
My questions, Is it a good way? It's a singleton so it can be added to many views. Do I need to remove the view from last view before adding to current view?
Understand that you are mixing some concepts that are not necessarily related: avoid duplicated code and Singletons.
Wikipedia says this about singletons:
In software engineering, the singleton pattern is a design pattern that restricts the instantiation of a class to one object. This is useful when exactly one object is needed to coordinate actions across the system. The concept is sometimes generalized to systems that operate more efficiently when only one object exists, or that restrict the instantiation to a certain number of objects. The term comes from the mathematical concept of a singleton.
The most important characteristic of a singleton (in my humble opinion) is that the object is instantiated only once and every single place in your application will use the same instance. Well, to use your search feature everywhere and avoid duplicated code you don't need the search view to be instantiated only once, maybe the data that comes with it, but not the view itself.
Two better ways of achieving this:
1 - You can create a ViewController with your search and just embed this on the other views using a Container View, you can use blocks or a delegate protocol to communicate between your controller and the view that is embedding it.
2 - You can create a Parent class of the ViewController that will include the search bar, like a SearchViewController and all the other viewControllers that needs the same feature will inherit from it.
The singleton could be useful if you are planing to share the same search data and text between all the ViewControllers of the application, but it would be a singleton only with these information, the UISearchBar and all other view elements should not be part of the singleton.
Ideally, you should instantiate a fresh instance of MySearchViewController every time when you want to add it to another view to avoid problems.
Do I need to remove the view from last view before adding to current view?
Its not required to remove it from previous super view because whenever you add this singleton MySearchViewController's view to some other view, it will automatically gets removed from last super view and now its super view is your new view where you have added it.
If you want to add a view from a different view controller, your view controller has to be that view controller's parent view controller:
- (void)viewDidLoad
{
MySearchViewController* search = [AppDelegate searchViewController];
[self addChildViewController:search];
[self.view addSubView:search.view];
}
also, make sure that when the search.view is added, it is already initialised.
Why you do not use NSObject class ?, i do not know your requirement , but if you want to store latest updated value in whole project(in execution) then you should use the singleton, but if you do not want to store value (i mean one result for whole project) then you should use NSObject derived Class. advantage is singleton consumes memory so memory will be wasted. NSObject class will be reusable and only allocated when it is required and then ARC will take care of all things. If you want to know how to create NSObject and use of it then you can give me reply.
Here is some code to load a XIB as part of a custom object with the object gets initialized.
Why are you not creating custom search component for search?
you can use this component all over the app.
also this is not creating duplicat code.
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// Initialization code
[[[NSBundle mainBundle] loadNibNamed:#"SearchView" owner:self options:nil] objectAtIndex:0];
[self addSubview:self.view];
self.frame = self.view.frame;
}
return self;
}
Please check below code. Hope this is work for you.
- (void)viewDidLoad
{
if ([self.view viewWithTag:123456]) {
[[self.view viewWithTag:123456] removeFromSuperview];
}
MySearchViewController* search = [AppDelegate searchViewController];
search.view.tag = 123456; // give a any random tag to view
[self.view addSubView:search.view];
[self addChildViewController:search];
}
Please make sure given tag is not assign to other object except search.view in self.view.
Thanks

using category to split up work in a UIViewController - how to reference parent?

I read somewhere recently that if you have an exceptionally large view controller class, you might consider splitting it up into multiple categories based on the work being performed. I'm attempting to do that, but I can't for the life of me figure out how to do it properly. And, on top of that, I can't find any online sources on the practice.
So I have this view controller that has 5+ UIViews laid out in a UIScrollView. I'm trying to create a private category for each UIView and put any work for those views within the category, i.e. any programmatic visual work, button presses, etc. However, I need a reference to the parent object to change the visual values because all labels and buttons are defined on the parent object. I can't define them within the category, Xcode won't let me. It will only let me define button presses. I've already tried sending a weak copy of self to the category upon initialization, but using it didn't change the visual values of any of the labels or anything.
It's pretty imperative that I have access to other objects within the parent. If I don't, this is kind of a lost cause. So, is it a lost cause? or am i doing it wrong?
within main class
__weak __typeof(self)weakSelf = self;
[_diaryViewController setupDietDiaryViewForController:weakSelf];
within category
- (void)setupDietDiaryViewForController:(PADashboardViewController *)mainDashboard {
mainDashboard.chooseHungerView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.4f];
mainDashboard.chooseHungerView.layer.borderWidth = 0.4f;
mainDashboard.chooseHungerView.layer.borderColor = [UIColor whiteColor].CGColor;
A category is nothing more than an extension of the base class. In essence, you could place any code within a category at the bottom of the main file and it would work exactly the same. Commonly, programmers prefer to split functionality up into categories in an attempt to make the code more readable.
Since it's nothing more than an extension of the main functionality, there is no need to create a reference to the parent class. If you want to make variables available to the category, all you need to do is place the variables in the header file of the main file. When you call a category function, you'll want to do it as if the function was within the base file itself.
[self setupProgressView];
Make sure the function setupProgressView is not static (it should be defined with a - instead of a +).
and within the category itself, you access variables like so:
[self.chooseHungerButton changeTitle:#"New Title"];
[self.deviationButton changeTitle:#"New Title"];
If you're trying to shift IB functionality over to a category, you'll need to define the buttons/views/objects within the base file's header. After defining the variables, you can access them from the category. If you want to create a method call for the button, you can control-drag the button straight into the category's .m file.
Make sure you include the category's .h file in the base file before attempting to use any functions within.

Can I connect xib object to any viewController?

I know it is possible to connect an object in a XiB file (i.e button) and connect it to any viewController. I am also able to go to that viewController and programmatically set properties to that object(everything autocompletes fine, it recognizes the object properties) However, when I run the app, the button is unchanged, what gives?
Is there something I'm missing? Is there an additional step that I need to do when using a ViewController that is not the .m file related to the XIB?
Here's part of the code... I don't get any errors!
user.default_sales_rep_id = 2;
if (user.default_sales_rep_id > 0) {
buttonMask.backgroundColor = [UIColor blackColor];
}
You are most likely setting the properties on the button too early. Since you don't specify in your question where this code is located, it's hard to say but I'd guess if you put your code in awakeFromNib it would work.
- (void)awakeFromNib {
[super awakeFromNib];
//code here
}
Any changes to your view that differ from your XIB should be done in this method as it is called after the view is set up from the XIB.
Are you certain you are calling [[UIButton alloc] init] before you attempt manipulating it? I assume you have the button already as an IBOutlet, but if I recall, if you wish to make custom changes to the button, you must still do this.

iOS - Getting information from the View Controller to drawRect in the View

My question relates to Assignment 3 in CS193p.
Im having a terrible time getting drawRect in my View to receive information passed from my View Controller. Basically, my goal is to pass view-specific information (like self.view.size.width) to the controller, have it make some modifications (like result = self.view.size.width * 2), and pass result back to drawRect so that it could take the new info and draw it. Im pretty sure I have my delegation set up correctly, and really have tried a list of potential work-arounds:
make a public View #property, which I access in my controller.m via
View *newView
someResult = newView.variable
which I would then try to access from my view.m via
self.variable
use methods set in my View's #protocal, which I try to pass data via myView.dataSource someMethod:someData
But so far none of these are currently working (i.e. my self.variable would always come out to be 0, which shows that no data was passed to it). Your help much appreciated!
UPDATE:
The culprit was that, in the storyboard, I didn't control-drag the View Controller to the View, and hence the Controller was never connected... but at least now it works. ^_^
View *newView someResult = newView.variable is not valid syntax.
If newView.variable is not of type View then that is a problem.
If newView is already declared, you would access variable using int myValue = newView.variable (that is, asuming it is of int type).
An example would be:
// Somewhere in your code, you declare your object
UIView *otherView = [[UIView alloc] init];
// Somewhere else, you set a variable of your object
otherView.backgroundColor = [UIColor blackColor];
// Again, somewhere else you want to access that value
UIColor *thatColor = otherView.backgroundColor;
I hope this explains it well enough.
Is this the correct description of what you want to do? You have a view controller (presumably the calculator type view controller from the course) and you want to communicate between that view controller (whose view has the calculator buttons) and a view other than it's own?
If so, here are the steps you should take:
In your view that you want to receive information from a delegate:
Declare an #protocol with the method you want the delegate to implement. Declare a property in the header file of the view that conforms to the aforementioned delegate: #property (nonatomic, weak) delegate<NameOfTheProtocol> delegate;
In the view controller you want to act as the delegate, declare it conforms to the protocol: MyClass: UIViewController <NameOfTheProtocol>. In the implementation file of that view controller, implement the methods of the protocol. Where ever you create the view that you want to receive information, set it's delegate property to your view controller.
To pass information between them (I have no idea what information you want to pass), your protocol method might be something like: -(CGPoint)pointToDrawAtGivenPosition:(CGPoint)point
In your view that has the delegate property, you could in drawRect do something like:
CGPoint pointToDrawAt = [self.delegate pointToDrawAtGivenPosition:CGPointMake(100, 100)];
//Now draw that point or whatever.
Basically, the view is asking its delegate to make a decision about where to draw something. It passes some information to the delegate, and the delegate responds with the correct position for the view to draw at.

Resources