I am getting confuse weither reference to subviews i am creating in a view should be declared with the weak or strong keyword when using ARC in iOS5.
Here is a sample of my header file:
#import <UIKit/UIKit.h>
#import <MessageUI/MessageUI.h>
#class SCLGridView;
#interface MyViewController : UIViewController <UIPopoverControllerDelegate, MFMailComposeViewControllerDelegate>
#property (weak, nonatomic) IBOutlet UIView *hiddenBrowserView;
#property (strong, nonatomic) SCLGridView *gridView;
#property (strong, nonatomic) UIImageView *backgroundView;
#property (strong, nonatomic) UIView *backgroundShadowView;
#property (strong, nonatomic) UIPopoverController* popOverController;
#end
I run under the impression that the views i am creating and want to reference should be declare with the strong keyword because i am owning those views(i create them). However i have declared the hiddenBrowserView as weak because i am referencing a view i have created in the storyboard. Is this apporach correct or i should make all those view reference as weak even for the reference to views i create programmatically? Thanks!
As far as I know the subviews are strongly referenced by the main view of your controller. So there is no purpose of referencing them strong because the'll be useless when your main view goes down.
In other way, you create a subviews programmatically, and add them to your controller's main view.
Your controller's main view references them strongly.
And you point at this views with weak properties.
When your controller's main view is deallocated, so are the subviews.
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
Why outlet to view called second get nil in willRotateToInterfaceOrientation:duration:? There is two top-level views in the xib, and first and second outlet are pointing to them. Is it not allowed to have two top level view in one XIB? I use XIB with UIViewController. second outlet still exist in viewDidLoad method.
I forget to set up property as strong, instead of weak. And because there is no pointer referring to the second view, it get released.
#property (strong, nonatomic) IBOutlet UIView *first;
#property (strong, nonatomic) IBOutlet UIView *second;
I get the famous loaded the "MyController" nib but the view outlet was not set error. However I made sure, that the IBOutlet view is set.
Once the exception is thrown I hit a breakpoint. Below you can see that
All IBOutlets are connected
All IBOutlets are set
When unfolding UIViewController super-class, I can see that _view is 0x00000000 and obviously causes this exception.
Code (header)
#interface InfoDialogViewController : UIViewController
#property (strong, nonatomic) id episode;
#property (strong, nonatomic) NSString *identifier;
#property (strong) IBOutlet UIView *regularSide;
#property (strong) IBOutlet UIView *flippedSide;
#property (weak) IBOutlet UIImageView *episodeCover;
#property (weak) IBOutlet UITextView *episodeTitle;
#property (weak) IBOutlet UITextView *episodeSummary;
- (IBAction)flip:(id)sender;
#end
Some notes
The xib file contains three UIViews on its root level (Flipped, Regular, View)
InfoDialogViewController.m file doesn't contain any methods (I don't do any funky by overriding)
I am using this Controller in combination with addChildViewController.
Anybody has an idea what happens here and how I can fix it? Does ARC play some tricks on me?
Please check:
1. The Class for your View Controller's View should be UIView
2. File owner should be your View Controller
3. Right CLick on File Owner, your view Outlet should be set.
If it is already solved, can u mention what solved your issue?
At least I think it's a basic problem. I just started working with views programmatically.
In RouteCaptureViewController.h:
#property (strong, nonatomic) IBOutlet UIView *routeCaptureSuperView;
#property(nonatomic, weak) IBOutlet UIImageView *captureImageView;
#property(nonatomic, retain) IBOutlet UIImageView *previewImageView;
#property (weak, nonatomic) IBOutlet UIView *captureRouteButtonView;
In my storyboard:
All of the outlets are properly connected, I checked.
I'm implementing addSubview in a method as such and nothing happens:
[self.routeCaptureSuperView addSubview:self.captureRouteButtonView];
[self.routeCaptureSuperView addSubview:self.captureImageView];
The following lines worked previously in the code:
[self.captureImageView removeFromSuperview];
[self.captureRouteButtonView removeFromSuperview];
And I know self.routeCaptureSuperView is not nil from an NSLog.
If I understood you correctly and you removed the views to add them again later I can make an educated guess:
In the moment you send removeFromSuperview to your views they get deallocated because they are declared as weak only.
Weak means that the property will be nil'd if the object is deallocated because the last strong relationship to that object is released.
The parent view is the object that keeps the last strong relationship to those two views.
Try to change weak to strong in the #property declaration of the two subviews.
I have a view controller alertForNeedsClassification as a property in another class, as such:
#interface SCAAppDelegate()
{
HomeScreenViewController * _homeScreenViewController;
NSInteger SCAStatus;
}
#property (strong, nonatomic) PromptClassifyViewController * alertForNeedsClassification;
#end
#implementation SCAAppDelegate
#synthesize alertForNeedsClassification;
#synthesize window = _window;
PromptClassifyViewController's interface looks like this:
#interface PromptClassifyViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *headerTitle;
#property (weak, nonatomic) IBOutlet UITextView *message;
#property (weak, nonatomic) IBOutlet UIButton *notNowButton;
#property (weak, nonatomic) IBOutlet UIButton *classifyButton;
#property (weak, nonatomic) IBOutlet UIImageView *backgroundImageView;
#property (weak, nonatomic) IBOutlet UIView *alertView;
#property NSUInteger tag;
#property (weak, nonatomic) IBOutlet id<PromptClassifyViewControllerDelegate> delegate;
- (void)show;
- (void)showFromView:(UIView *)view;
- (IBAction)show:(id)sender;
- (IBAction)dismiss:(id)sender;
- (IBAction)buttonWasPressed:(id)sender;
- (void)setHeaderTitleWithText:(NSString *)text;
#end
I am trying to change the values of IBOutlets message and headerTitle text, like this:
alertForNeedsClassification = [[PromptClassifyViewController alloc] initWithNibName:#"PromptClassifyViewController" bundle:nil];
//[alertForNeedsClassification setDelegate:self];
self.alertForNeedsClassification.headerTitle.text = #"A title";
alertForNeedsClassification.message.text = #"A message";
Then I show alertForNeedsClassification calling a show method (it's like a custom uialertview, but it doesn't subclass from uialertview).
Thing is, no matter how I change it, the text on alertForNeedsClassification.view is always that which is defined in the nib, ie. I can't change it programmatically.
My custom alert view is based on Jeff LaMarche's design: http://iphonedevelopment.blogspot.com/2010/05/custom-alert-views.html
Any ideas what might be going on?
Please be careful when you allocate and initialize the UIView object, especially if you trying to mix using Nib and dynamically generating objects. The best place is within -(void)awakeFromNib or -(void)viewDidLoad
Also, make sure these methods are called. By using -(id)initWithNibName:bundle: only cannot make sure your view to be loaded. Try -(void)addChildViewController and -(void)addSubview: on parentViewController's view to make sure view is loaded after being initialized.
If the text had to be prepared before being loaded, assign it to separate NSString property within PromptClassifyViewController class. Since this property is independent from view being loaded, you can change it's value BEFORE view is appeared. Make sure this text is used and applied to the headerTitle within -(void)show method.
Since you allocate PromptClassifyViewController and access weak referenced headerTitle from self. alertForNeedsClassification, make sure it's not deallocated right afterward.
Usually, weak option is not used for IBOutlet properties. Though it is used when generating outlet connection code by dragging objects from Interface Builder. Try testing your code using strong.
I was assigning values to the IBOutlets before they were alloc'd/initialized. The solution I implemented was to set the values I needed to non-IBOutlet properties (NSStrings in this case) and assign those where needed, in Prompt...Controller's viewDidLoad;