Change View background in iPhone app based on property - iphone

I need to change the background of one of my Views based on a property that will be set when the View is initialized.
Is this possible?
I've got the background set as a UIImageView and if I set it to an Image in Interface Builder it works, but I can't change the background programatically.
Here is the code I'm using (I based it off a tutorial that loaded an image into a UITableCell):
+ (void) initialize {
/* The threat level images are cached as part of the class,
so they need to be explicitly retained.
*/
redLevel = [[UIImage imageNamed:#"red.png"] retain];
yellowLevel = [[UIImage imageNamed:#"yellow.png"] retain];
greenLevel = [[UIImage imageNamed:#"green.png"] retain];
}
-(id) initWithThreatLevel:(NSInteger) threatLevel {
if (self = [super initWithNibName:#"DetailView" bundle:[NSBundle mainBundle]]) {
switch (threatLevel) {
case 1:
self.threat_levelImageView.image = greenLevel;
break;
case 2:
self.threat_levelImageView.image = yellowLevel;
break;
case 3:
self.threat_levelImageView.image = redLevel;
break;
default:
self.threat_levelImageView.image = greenLevel;
break;
}
}
return self;
}

You should move these assignments to your awakeFromNib method. At initXXX time, NIB connections are usually not yet set up. In awakeFromNib, you're guaranteed that all your connections have been set up.

Make sure threat_levelImageView is an IBOutlet that is connected in Interface Builder. And yes, don't use +initialize for loading the images.

Related

How to set NSString before calling a method objective c

It might be a simple question yet I could not figure out what I am missing.
In ViewControl.h I declared UIColor
#property (nonatomic, strong) UIColor * myColor;
In ViewControl.m I have a method that do something and return new UIColor
#synthesize myColor = _myColor;
In ViewDidLoad Method
- (void)viewDidLoad
{
myColor = [UIColor RedColor];
}
-(void) ShowColorPopUpView
{
if (!self.wePopoverController)
{
ColorViewController *contentViewController = [[ColorViewController alloc] init];
contentViewController.delegate = self;
self.wePopoverController = [[WEPopoverController alloc] initWithContentViewController:contentViewController];
self.wePopoverController.delegate = self;
self.wePopoverController.passthroughViews = [NSArray arrayWithObject:self.navigationController.navigationBar];
[self.wePopoverController presentPopoverFromRect:self.tvTweetDetails.frame
inView:self.view
permittedArrowDirections:(UIPopoverArrowDirectionUp|UIPopoverArrowDirectionDown)
animated:YES];
} else
{
[self.wePopoverController dismissPopoverAnimated:YES];
self.wePopoverController = nil;
}
}
-(void) colorPopoverControllerDidSelectColor:(NSString *)hexColor
{
_myColor = [GzColors colorFromHex:hexColor];
[self.view setNeedsDisplay];
[self.wePopoverController dismissPopoverAnimated:YES];
self.wePopoverController = nil;
}
- (UIColor *) returnColor
{
return _myColor;
}
My Question starts here: I have two methods to change a textview font and background color
- (IBAction)btnFontColorPopUpMenu:(id)sender
{
[self ShowColorPopUpView];
tvTweetDetails.textColor = [self returnColor];
}
- (IBAction)btnTextViewBackGroundColor:(id)sender
{
[self ShowColorPopUpView];
tvTweetDetails.backgroundColor = [self returnColor];
}
The issue now is when I call the method it return it returns RED and if I call it again it returns the the BlackColor.
How Can I call the method and change the Color to the new one and then return it. I want to get the Black color directly.
I want to execute the method first then return the color but what happens is assign the color before execute the method.
I hope I made it the Question Clear.
Okay, I'll take a whack at this.
I suspect you are doing some kind of presentViewController:... method in your color changer method. That's great, but it has implications. The method you call that in continues to execute during that presentation. That means it may return, etc.
This is where the concept of delegates comes in. You may benefit from restructuring the data flows here a bit.
What I suggest (if I am correct about the presentation of a color picker UI) is that you make the following changes:
Create a #protocol ColorPickerDelegate with one method: -(void) userChoseColor:(UIColor *) color
Add a #property (weak) id<ColorPickerDelegate> delegate to your color picker view controller
make your VC here implement that protocol
Inside the delegate method, set your local property
Implement a custom setter for the local propert, and update the background color whenever the color changes.

in -init method won't change subviews

I have a object derived from UIView, it is AIItem, this item have UIImageView *status_view, now I need another object AIAnotherItem derived from AIItem, problem is in status_view.
For Example :
AIItem init method
-(id)initWithName:(NSString *)name {
self = [super init];
if (self) {
status_view = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,50,50)];
status_view.image = [UIImage imageNamed:#"item_image.png"];
[self addSubview:status_view];
}
}
AIAnotherItem init method
-(id)initWithName:(NSString *)name {
self = [super initWithName:name];
if (self) {
status_view.image = [UIImage imageNamed:#"another_item_image.png"];
}
return self;
}
in AIAnotherItem I set another image to status_view but it won't changed.
Question is why ? and how do this ?
Regardless what the mechanics are of this not working (I am sure you will figure it out), I believe that you are perhaps not going about this the right way.
Would it not be more logical to have class AIItem.h that has an empty property statusView? And then two derived classes (or instances of the same subclass) that inherit the same statusView but fill it with different images?
I think this would correspond more closely to the philosophy behind inheritance.

Memory Management, ARC - what to nil?

Background -
I am using automatic reference counting on a project. The root view is a Table View (Master / Detail setup) showing a list of "slide shows". Click on a table cell and you are taken to the detail view which consists of a Scroll view with views (viewController.view) in it (this is the "slide show"). Each slide show has a front cover and back cover (same view controller formatted differently) that sandwich an variable number of pages. Here is the code to load the slide show:
- (void)loadScrollView
{
// The front and back cover are set in Interface Builder because they
// are reused for every slide show, just labels are changed.
[self.scrollView addSubview:self.frontCoverViewController.view];
[self.frontCoverViewController setCoverTitle:_data.name creationDate:_data.creationDate isFrontCover:YES];
[self.pagesArray addObject:self.frontCoverViewController];
for (int i = 0; i < [self getTotalNumberOfComps]; i++)
{
PageViewController *pageView = [[PageViewController alloc] init];
pageView.data = [_compsArray objectAtIndex:i];
[_scrollView addSubview:pageView.view];
pageView.data.imgView = pageView.imageView;
pageView.slideShowViewController = self;
[_pagesArray addObject:pageView];
}
[self.scrollView addSubview:self.backCoverViewController.view];
[self.backCoverViewController setCoverTitle:_data.name creationDate:_data.creationDate isFrontCover:NO];
[self.pagesArray addObject:self.backCoverViewController];
[self.scrollView bringSubviewToFront:_frontCoverViewController.view];
[self setCurrentPage:0];
}
Problem -
So Im trying to reuse this slide show view controller so I need to nil and recreate the pages in the middle because each slide show has a different number of slides. Note a slide [PageViewController] is just a view with an ImageView in it. It has more functionality so we need the controller however the main display of the V.C. is the ImageView. I have created the following method to "empty" the slide show before running loadScrollView again with new data. Here is the empty method:
- (void)saflyEmptyScrollView
{
for (int i = 0; i < [self.pagesArray count]; i++)
{
if (i == 0 && i == ([self.pagesArray count]-1)) {
CoverViewController *cover = (CoverViewController*)[self.pagesArray objectAtIndex:i];
[cover.view removeFromSuperview];
} else {
PageViewController *page = (PageViewController*)[self.pagesArray objectAtIndex:i];
[page.view removeFromSuperview];
page = nil;
}
}
self.pagesArray = nil;
self.pagesArray = [[NSMutableArray alloc] init];
}
Big Question -
My main question is do I need to set the ImageView of each of these pages to nil? Or does setting the page itself to nil also free up the memory used by the ImageView/Labels/etc that are used in that view controller?
I tried adding self.imageView = nil; to the PageViewController's viewDidUnload and viewWillUnload methods (one at a time not in both) and I realized that setting page = nil does not call the pages Unload methods. Am I freeing up memory correctly.
I've read a lot of articles but Im still not sure if Im managing memory in the best way possible. Thanks so much for the help!
Generally, you shouldn't have to set things to nil. And in this specific case, the setting things to nil is doing nothing.
The line page = nil; is redundant, because the variable page goes out of scope immediately afterwards anyway. ARC knows this and doesn't need you to set it to nil.
And self.pagesArray = nil; is redundant because you follow it with self.pagesArray = [[NSMutableArray alloc] init];. The second line on its own will suffice.

UIImageView weird image property issue

I'm dealing with a super easy task that somehow introducing some difficulties...
All I'm trying to do is to create a view controller and set its UIImageView's image property to some image.
When I try to that, I get nil =\
GenericViewController *genericViewController = [[GenericViewController alloc] init];
UIImage *image = [UIImage imageNamed:#"Camera.png"];
genericViewController.genericImageView.image = image;
NSLog(#"%#", genericViewController.genericImageView.image);
Output: (null)
I imagine genericImageView is set up either in a nib or in the -loadView method. However, at the point in which you're trying to access the image view, the view for the VC hasn't been loaded yet. The quick fix is to call
(void)genericViewController.view;
before accessing genericImageView. This will force the view to load. The "better" approach would be to give genericViewController an image property that you assign to, then in its setter you can say
- (void)setGenericImage:(UIImage *)image {
if (_genericImage != image) {
[_genericImage release];
_genericImage = [image retain];
if ([self isViewLoaded]) {
self.genericImageView.image = image;
}
}
}
and in -viewDidLoad you can say
- (void)viewDidLoad {
[super viewDidLoad];
self.genericImageView.image = self.genericImage;
}
This method, besides being more modular and architecturally-sound, also has the advantage where if the view controller's view is unloaded (say, another view is pushed onto the nav stack and a memory warning comes along), when it gets re-loaded it will still have the image.

initializing UIView subclass with parameters in iphone sdk?

Iam a newbiew to iPhone development. Version of my SDK is 2.2
In my code, UIViewController is used to change view dynamically once the app is launched, a method in the UIViewController is called to know which view should be initialized along with parameters, which goes to a 'switch-case' and assign a view to current view according to the parameter, like this:
case 1:
currentView = [[View01 alloc] init];
break;
case 2:
currentView = [[View02 alloc] init];
break;
and outside the switch-case:
[self.view addSubview:currentView.view];
I wonder f can pass a parameter along with initialization, like iniWithNibName or so? I need this because have to manipulate in the leaded view, according to the view from which its called.
Thanks.
One way to approach this is to modify your View01 and View02 classes to include an initWithParam: initialiser.
i.e. add
- (id) initWithParam:(NSString *)myParam;
to the #interface section and add
- (id) initWithParam:(NSString *)myParam {
if (self = [self init]) {
// handle or store 'myParam' somewhere for use later
}
return self;
}
to the #implementation section. Notice how the initWithParam: message internally calls the existing init. Obviously you could change the type, or number of parameters passed in as required.
Another approach would be to provide a property on your view class, so you could do something like the following:
currentView = [[View01 alloc] init];
currentView.myParam = #"SomeValue";
Which approach works the best will depend somewhat on your particular application needs.