Initializing a View controller using initWithNibName - ios

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
fetched = NO;
self.title = #"Nearby";
// Custom initialization
liked = NO;
categories = [[NSArray alloc] init];
fundings = [[NSArray alloc] init];
stages = [[NSArray alloc] init];
}
return self;
}
I use the code above. am I during anything wrong by initializing all of my varialbes in the initWithNibName function? Is that the correct place to do so?

You will probably not run into issues, but you can use a ViewController also with the pure init in which case the NIB is not loaded and also your initialization will not be called. Another place to make the init for that is the viewDidLoad which is called only after the init.

You can do it in the init method, that's fine. You could also do it (or some of) in the viewDidLoad method. The difference would (generally) be that viewDidLoad is called when your view is actually getting ready to be shown, so you need everything setup. init on the other hand could be called well in advance. There isn't a hard and fast answer, it depends what the items you're setting up are and if they can be unloaded when the view isn't on display. With newer versions of iOS that concern changes anyway as the view generally isn't unloaded. You really need to read about the view and controller life cycles and decide when to create and destroy your attributes.

Related

View Controllers, Dependency Injection, and init/viewDidLoad

I've read a bunch of answers on SO already, but I'm a little confused.
I have a tab bar controller subclass I created, and in its viewDidLoad, I'm creating each of the view controllers. However, I have a dependency that I'm passing into the parent, and in turn into the view controller for each tab. I'm passing that dependency in with a custom init method (NS_DESIGNATED_INITIALIZER declared for it in the header). However, it looks like [super init] triggers viewDidLoad directly, so the dependency isn't set properly when the other view controllers are created.
Here's my custom init method:
- (instancetype)initWithSession:(T2Session *)session
{
self = [super init];
if (self) {
_session = session;
}
return self;
}
I'd like session to be set by the time I create the view controllers, but I'm sort of confused about what the best way to do this is. Any advice is much appreciated. Thanks in advance!
I've come across this situation before.
You probably sat there (like me) wishing viewDidLoad didn't get called so soon.
Anyway, this is what I settled on:
- (instancetype)initWithSession:(T2Session *)session {
if (self = [super init]) {
self.session = session;
}
return self;
}
- (void)setSession:(T2Session *)session {
_session = session;
... call the setup methods here, instead of viewDidLoad
}
At first I thought this breaks the golden rule of not calling self.xxxx from within an initializer.
However, I think that rule is only really relevant when calling methods on IBOutlets that may not have been wired up yet.
In this case, T2Session *session isn't a nib outlet.
Alternatively, if you prefer not to break that rule you could always remove the custom initializer .. and revert to using regular property-injection rather than constructor-injection. e.g.
T2Session *session = .....
MYTabBarController *tabBarController = [[MYTabBarController alloc] init];
[tabBarController setSession:session];
These are just my thoughts, hope it helps.

App suddenly crashes while processing presentViewController method in iOS 7.1

Today, I upgrade my Xcode to the latest version(Version 5.1 (5B130a)) to support iOS 7.1.
After doing this, I run my project in Xcode as usually. Then app crashes.
I didn't change any code before upgrading the SDK version.
The code is running perfectly in iOS 5.x, 6.x, 7.0.x.
I am simply presenting another view controller in the current view controller.
they are both initialized by storyboard.
While processing presentViewController method, it gets a error message "Thread 1: EXC_BAD_ACCESS (code=2, address=0x60)". I have checked the variables, they are both alive, not a released garbage.
What's the problem with iOS 7.1??
the project is using non-ARC mechanism.
Here is my code:
#property (nonatomic, retain) ArticleViewController *articleView;
....
self.articleView = [[UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil] instantiateViewControllerWithIdentifier:#"ArticleViewController"];
...
[self presentViewController:self.articleView animated:NO completion:^() {
log(#"has shown article page...");
}];
but it works fine if presenting another view by using addSubView function:
[self.view addSubView:self.articleView.view];
I really don't know why this happens.
This happened to my app while presenting a view controller with modalPresentationStyle = UIModalPresentationCustom;
Here's how my code looks like on iOS 7.0:
//Inside my MyPresentedViewController:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
[self setupContent];
}
return self;
}
- (void)setupContent
{
//TransitionManager adopts UIViewControllerTransitioningDelegate and UIViewControllerAnimatedTransitioning
TransitionManager *transitionManager = [[TransitionManager alloc] init];
transitionManager.presenting = YES;
self.modalPresentationStyle = UIModalPresentationCustom;
self.transitioningDelegate = transitionManager;
}
However, the above code crashes on iOS 7.1 so I changed the implementation to:
#interface MyPresentedViewController
#property (nonatomic, strong) TransitionManager *transitionManager;
#end
...
//Inside my MyPresentedViewController:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
[self setupContent];
}
return self;
}
- (void)setupContent
{
//TransitionManager adopts UIViewControllerTransitioningDelegate and UIViewControllerAnimatedTransitioning
self.transitionManager = [[TransitionManager alloc] init];
_transitionManager.presenting = YES;
self.modalPresentationStyle = UIModalPresentationCustom;
self.transitioningDelegate = _transitionManager;
}
Basically, instead of declaring a transitionManager object inside the setupContent method, I created a private property (strong reference) for it.
Hm the only thing I can think of is ensuring that your articleView property is a strong reference.
#property (nonatomic, strong) ArticleViewController *articleView;
I ran into a similar issue with a picker view. In my case the pickerview was set to nil after the selection handler block, although this caused no issues as recently as last night, it was causing the app to crash this morning. Removing that line fixed the issue, however I have converted this project to ARC in the last month so you may have to find a better way to handle clean up.
This may be completely unrelated to the stated problem or answers but I ran into a similar problem when accessing an NSString on an iPhone 5S. The exact same code runs fine on an iPad and iPad at the same time.
To start out with I think it's important to state that I'm running under ARC, and I have been told repeated not to "release" any objects I instantiate in my functions. I've had problems with this before so I use some of my C# background to set almost all of my local variables to nil (null in C#). Yes, I don't trust MS GC either.
Back to the problem at hand; I have an NSString called 'data'. 'data' is read as a result from another method in a different class. Using NSLog I can see the contents of 'data'. On the next line I convert 'data' to an array to use it in scanf. That still works. On the third line I try to NSLog 'data' again, but then I get the EXC_BAD_ACCESS error. Each time it has a different address. I'm even less comfortable with ARC than I am with the Microsoft Garbage Collector so I wrapped the function in a try..catch..finally. 'data' is now sitting outside of the try..catch..finally. I'm setting 'data' to nil in the finally, which seems to fix the problem.
I know this was a bit long winded, but I would really appreciate it someone could explain why this would happen. I'm expecting to see a lot of these problems to popup all over my code now.

Using blocks to pass data back to view controller

I was looking at this question.
One of the answers shows how to use blocks to pass data backwards view the prepareForSegue method. My understanding is this method should really be used to pass data forward, not backwards.
I'm wanting to try blocks out for this purpose - passing data back to another viewController.
My question is: How do I do this, without using prepareForSegue method?
I could use for instance in a UITableView - didselectRowAtIndexPath and dismiss the view - but then how does the receiving view get "notified" there is data to come back, without using a delegate?
sent data backward
declare block in your secondViewController.h file
#property (nonatomic, copy)void(^myBlock)(NSString *);
call block wherever you need to pass data from .m file of secondViewController
myBlock(#"this will displayed in firstViewController");
3.import above .h file in your firstViewController .m file
and define your block as
secondViewController *ref =[[secondViewController alloc ]init];
ref.myBlock =^void(NSString *data)
{
self.labelOffirstviewcontroller=data;
};
In your view controller 1:
MyViewControllerClass2* vc2 = [[MyViewControllerClass2 alloc] initWithNibName:#"UIViewController" bundle:[NSBundle mainBundle] completion:^{
NSLog(#"view2 is closed");
}]];
[self.navigationController pushViewController:vc2 animated:YES];
In MyViewControllerClass2.m:
#interface MarryViewController ()
#property (nonatomic, copy) void(^completion)();
#end
#implementation MarryViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
}
return self;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil completion:(void(^)())completion
{
self = [self initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if( self )
{
//store completion block
_completion = completion;
}
return self;
}
-(void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
//call completion block
_completion();
}
In MyViewControllerClass2.h:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil completion:(void(^)())completion;
Just a few notes on how awesome block are:
MyViewControllerClass2 has no idea what is defined in _completion() which is the main point, as this is not of his concern
You could also call _completion() in -dealloc or even on some place where MyViewControllerClass2 will continue to run
You can pass arguments to block functions
You can pass arguments from block functions
Many more :)
I'm really encouraging people to get good overview on blocks and stat using them as they are pretty cool.
IMPORTANT!
While using block you do not declare delegate, the main idea and abstract result of delegate method and using block are the same. Moreover delegate pattern has it's advantages such as better documenting and more strictly usage. Still blocks are way more flexible and(when get used to) easier to use.
Regards,
hris.to
I know that you asked specifically for a solution that did not involve prepareForSegue but this appears to be based on the assumption that prepareForSegue is for passing data forward only.
There is something called an unwind segue which might be helpful in your situation. There is a detailed discussion on SO here.
If you specifically want to use blocks for this, you can simply add a block property to your child controller and have the parent controller set the block. The child controller would have to invoke the block when it is being dismissed. Beware of retain loops if you do this. It doesn't sound to me like blocks are the best solution in this context but it's difficult to say something like that with authority without having a lot more context.
Yes methods can send data forward as well as backwards for that you can use Blocks or Delegates
For more info about blocks in ios use this link
CLICK HERE
Hope it will help you, thnx

Custom UITextField delegate

I have a uitextfield subclass and in the init method and setDelegate I have this:
- (void) setDelegate:(id<UITextFieldDelegate>)paramDelegate{
[super setDelegate:paramDelegate];
MRAAdvancedTextFieldDelegate *limitedDelegate = [[MRAAdvancedTextFieldDelegate alloc] init];
self.delegate = limitedDelegate;
}
I am using ARC, but this results in a BAD_ACCESS. Any ideas?
You write self.delegate = limitedDelgate within your setDelegate: method. This is exactly the same as calling [self setDelegate:limiatedDelegate]. Since you are within the -setDelegate: method itself, you are causing infitine recursion. Hope this helps!
EDIT: per your comment about your intention, override it like this:
- (void) setDelegate:(id<UITextFieldDelegate>)paramDelegate{
MRAAdvancedTextFieldDelegate *limitedDelegate = [[MRAAdvancedTextFieldDelegate alloc] init];
[super setDelegate:limitedDelegate];
}
But I don't believe it's a good idea to do this - you should have your client code pass in instances of your delegate instead.
self.delegate = limitedDelegate;
is turned into
[self setDelegate:limitedDelegate];
by the compiler, resulting in an infinite loop. Solution: instead of using the property, use the instance variable instead in the custom setter method:
delegate = limitedDelegate;

Subclassing IASKAppSettingsViewController

I'm trying to tweak the behavior of the default IASKAppSettingsViewController so it can provide custom subviewcontrollers (as for type = PSChildPaneSpecifier) for custom views (type = IASKCustomViewSpecifier).
I've tried to subclass IASKAppSettingsViewController without adding any new functionality to the code.
However when I load up my own subclass the settings view is completely empty - even for a bare subclass. When I switch back to the default IASKAppSettingsViewController everything works again as expected.
I've tried setting breakpoints various places in my subclass and everything seems to be working fine - except that nothing is displayed.
I've tried looking for clues in the documentation, but can't seem to find anything that explains why. The documentation for InAppSettingsKit even states that it's designed for subclassing.
What am I missing here? Any clues are appreciated - or even better a small step-by-step guide for dummies.
Updated with code:
Setting up the flipside view. It works with the standard IASKAppSettingsViewController but fails with my empty derived MyCustomSettingsViewController
- (IBAction)showInfo:(id)sender
{
// Setup navigation controller for settings view
MyCustomSettingsViewController *settings = [[MyCustomSettingsViewController alloc] init];
//IASKAppSettingsViewController *settings = [[IASKAppSettingsViewController alloc] init];
settings.delegate = self;
settings.showDoneButton = YES;
UINavigationController *navigation = [[UINavigationController alloc] initWithRootViewController:settings];
navigation.navigationBar.barStyle = UIBarStyleBlack;
[settings release];
// Display the settings
navigation.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:navigation animated:YES];
[navigation release];
}
Try to add this method to your subclass:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
return [super initWithNibName:#"IASKAppSettingsView" bundle:nibBundleOrNil];
}
If you don't do that, the default implementation of IASKAppSettingsViewController kicks in and it tries to find a nib named after your class name, in this case "MyCustomSettingsViewController.nib". This probably doesn't exist.
This happens because the default implementation of -init calls -initWithNibName:nil bundle:nil and nil as the filename means to search for a default nib.
Try setting breakpoint on initialization steps and if you are adding that as a subview/ pushing on navigation controller. Use NSLogs for each method so you can find the issue. If nothing works send me the code (create a demo code using IASKAppSettingsViewController) to recerate the problem then I'll look into the issue.

Resources