MainViewController init - iphone

I have set up a utility application and I found that the init method of MainViewController is not called automatically. Is there some other method that is set up automatically by XCode for initialization? Or if I have to add it, where would I add it? I was just going to call init manually from an IBOutlet method but I would prefer that the initializations be done when the view is first initialized.

Not sure where you'r going but (generated) .xib files are called using the withCoder init.
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self)
{
//self implementation
}
return self;
}

See the Utility Template in Xcode.
And check this method called..
- (IBAction)done:(id)sender
{
[self.delegate flipsideViewControllerDidFinish:self];
}
check it..

Related

Where to put the UIAlert? [duplicate]

I want to check the pasteboard and show an alert if it contains specific values when the view appears. I can place the code into viewDidLoad to ensure it's only invoked once, but the problem is that the alert view shows too quickly. I know I can set a timer to defer the alert's appearance, but it's not a good work-around I think.
I checked the question iOS 7 - Difference between viewDidLoad and viewDidAppear and found that there is one step for checking whether the view exists. So I wonder if there's any api for doing this?
Update: The "only once" means the lifetime of the view controller instance.
There is a standard, built-in method you can use for this.
Objective-C:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if ([self isBeingPresented] || [self isMovingToParentViewController]) {
// Perform an action that will only be done once
}
}
Swift 3:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if self.isBeingPresented || self.isMovingToParentViewController {
// Perform an action that will only be done once
}
}
The call to isBeingPresented is true when a view controller is first being shown as a result of being shown modally. isMovingToParentViewController is true when a view controller is first being pushed onto the navigation stack. One of the two will be true the first time the view controller appears.
No need to deal with BOOL ivars or any other trick to track the first call.
rmaddy's answers is really good but it does not solve the problem when the view controller is the root view controller of a navigation controller and all other containers that do not pass these flags to its child view controller.
So such situations i find best to use a flag and consume it later on.
#interface SomeViewController()
{
BOOL isfirstAppeareanceExecutionDone;
}
#end
#implementation SomeViewController
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if(isfirstAppeareanceExecutionDone == NO) {
// Do your stuff
isfirstAppeareanceExecutionDone = YES;
}
}
#end
If I understand your question correctly, you can simply set a BOOL variable to recognize that viewDidAppear has already been called, ex:
- (void)viewDidAppear {
if (!self.viewHasBeenSet) { // <-- BOOL default value equals NO
// Perform whatever code you'd like to perform
// the first time viewDidAppear is called
self.viewHasBeenSet = YES;
}
}
This solution will call viewDidAppear only once throughout the life cycle of the app even if you create the multiple object of the view controller this won't be called after one time. Please refer to the rmaddy's answer above
You can either perform selector in viewDidLoad or you can use dispatch_once_t in you viewDidAppear. If you find a better solution then please do share with me. This is how I do the stuff.
- (void)viewDidLoad {
[super viewDidLoad];
[self performSelector:#selector(myMethod) withObject:nil afterDelay:2.0];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
static dispatch_once_t once;
dispatch_once(&once, ^{
//your stuff
[self myMethod];
});
}
By reading other comments (and based on #rmaddy 's answer), I know this is not what OP asked for, but for those who come here because of title of the question:
extension UIViewController {
var isPresentingForFirstTime: Bool {
return isBeingPresented() || isMovingToParentViewController()
}
}
UPDATE
You should use this method in viewDidAppear and viewWillAppear. (thanks to #rmaddy)
UPDATE 2
This method only works with modally presented view controllers and pushed view controllers. it's not working with a childViewController. using didMoveToParentViewController would be better with childViewControllers.
You shouldn't have issues in nested view controllers with this check
extension UIViewController {
var isPresentingForFirstTime: Bool {
if let parent = parent {
return parent.isPresentingForFirstTime
}
return isBeingPresented || isMovingFromParent
}
}
Try to set a BOOL value, when the situation happens call it.
#interface AViewController : UIViewController
#property(nonatomic) BOOL doSomeStuff;
#end
#implementation AViewController
- (void) viewWillAppear:(BOOL)animated
{
if(doSomeStuff)
{
[self doSomeStuff];
doSomeStuff = NO;
}
}
in somewhere you init AViewController instance:
AddEventViewController *ad = [AddEventViewController new];
ad.doSomeStuff = YES;
Not sure why you do this in ViewDidAppear? But if you want doSomeStuff is private and soSomeStuff was called only once, here is another solution by notification:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(doSomeStuff) name:#"do_some_stuff" object:nil];
- (void) doSomeStuff
{}
Then post when somewhere:
[[NSNotificationCenter defaultCenter] postNotificationName:#"do_some_stuff" object:nil];
swift 5
I've tried isBeingPresented() or isMovingToParent.
But It doesn't work.
So I tried below code. and It's work for me!
override func viewDidAppear(_ animated: Bool) {
if (self.isViewLoaded) {
// run only once
}
}
You can use this function in ViewDidLoad method
performSelector:withObject:afterDelay:
it will call that function after delay. so you don't have to use any custom timer object.
and For once you can use
dispatch_once DCD block.Just performSelector in the dispatch_once block it will call performSelector only once when ViewDidLoad is called
Hope it helps

how to change WebView with buttons in separate View Controller

I need to change the URL of a WebView (located in WebViewViewController) using buttons in View Controller 1 (called PracticeViewController). I totally understand how to change the web View when it is in the same View Controller as the buttons, but I don't understand how to get the buttons to affect the WebView when the WebView is in a different ViewController than the buttons. Below is the code I currently have:
PracticeViewController.h
#import <UIKit/UIKit.h>
#interface PracticeViewController : UIViewController
- (IBAction)passGoogleButton:(id)sender;
- (IBAction)passYahooButton:(id)sender;
- (IBAction)passBingButton:(id)sender;
/* ok I tried to make this as clear as possible, and you can look at the other files if you don't understand what I mean, but at its core I want to change the web site loaded by the Web View by clicking on the buttons in the other View Controller */
#end
space (BTW is there an easier way to post on StackOverFlow Besides pressing space 4 times for every line of code? am I missing something?)
PracticeViewController.m
#import "PracticeViewController.h"
#import "WebViewViewController.h"
#interface PracticeViewController ()
#end
#implementation PracticeViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)passGoogleButton:(id)sender {
WebViewViewController.webSiteURL = #"http://www.google.com";
/* This supposedly works on a tutorial I saw, but Xcode flags it with the error 'Property webSiteURL not found on object of type 'WebViewViewController'' */
}
- (IBAction)passYahooButton:(id)sender {
WebViewViewController.webSiteURL = #"http://www.yahoo.com";
//same error as above
}
- (IBAction)passBingButton:(id)sender {
WebViewViewController.webSiteURL = #"http://www.bing.com";
//same error as above
}
#end
space
WebViewViewController.h
#import <UIKit/UIKit.h>
#interface WebViewViewController : UIViewController
{
UIWebView *myWebView;
NSString *webSiteURL;
}
#property (weak, nonatomic) IBOutlet UIWebView *myWebView;
#property (strong, nonatomic) NSString *webSiteURL;
/* I don't entirely understand what 'strong' means but I know it has to do with memory retention and that it (supposedly) should be used when I wan to transfer the value of the string 'webSiteURL' to the other ViewController */
#end
space
WebViewViewController.m
#import "WebViewViewController.h"
#interface WebViewViewController ()
#end
#implementation WebViewViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
[myWebView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:webSiteURL]]];
/* As you can see above, the WebView loads from the string 'webSiteURL' but I can't figure out how to assign different values to it based on what button is clicked in the other View Controller so that it will run in ' - (void)viewDidLoad.' I already know how to transfer the value of the string to other things within another view controller (like into a label or a text field) but what I really need to know is how to get the string 'webSiteURL' to change before the view is loaded */
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
You have the right idea but you are missing a step here. You are never creating an instance of webViewController.
What you need somewhere is...
webViewcontroller *MyWebController = [[webViewController alloc] init];
It depends on how you are presenting the WebViewController. If you simply want the button to pop up the WebViewController modally you could use the following:
- (IBAction)passGoogleButton:(id)sender {
webViewController *myWebVC = [[webViewController alloc] init];
[myWebVC setWebSiteURL:#"http://www.google.com"];
[self presentViewController:myWebVC animated:YES completion:nil];
}
So, you can see here. You create the instance of the webViewController called myWebVC. Then you pass the string to it. So when myWebVC loads and it hits viewDidLoad, it will use the string that you passed in already and load the web view with that content. Hope that helps.
Also, Make sure you #synthesize your properties in your .m files.
You can use nsnotificationcenter to accomplish this task.
First register to notificationcenter in WebViewController, then send notification from another controller.
Here's a sample for registering to notificationcenter in WebViewController
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(nMessageOpenURL:) name:#"nMessageOpenURL" object:nil];
This is the code to run the logic when you receive the notification. (in WebViewController)
- (void)nMessageOpenURL:(NSNotification *)note {
//run the logic in here.
}
And finally this is the code where you trigger the notification.
[[NSNotificationCenter defaultCenter] postNotificationName:#"nMessageOpenURL" object:nil];
Here's the Apple documentation.
I got to know that you are trying to pass the value of the string of url between two view controllers but you are not getting it right!!
So if you are using storyboard you can try out passing this value using Segue. For Eg: you can use prepareForSegue to set the different values using if-else construct.
And if you are not using segue the best practice to pass those values will be using delegate.
Just create a delegate method and pass the url string as an argument.
Hope this works :)

subclassing initWithFileURL of an UIDocument

I'm trying to overwrite the initWithFileURL of an UIDocument as I need to call some custom methods once an UIDocument is initialised.
I thought this may be a good idea:
-(id)initWithFileURL:(NSURL *)url {
self = [super initWithFileURL:url];
// do some custom stuff
return self;
}
Is there anything else I need to do if I overwrite this? I have the feeling that I need to check for NIL or something. Where do you usually look if you need to overwrite a method with something custom? I was only able (via jump to definition when right clicking UIDocument) to see this:
#pragma mark *** Initialization ***
// The designated initializer. Passing an empty URL will cause this method to throw an NSInvalidArgumentException.
- (id)initWithFileURL:(NSURL *)url;
You should probably be doing this.
-(id)initWithFileURL:(NSURL *)url {
self = [super initWithFileURL:url];
if(self) {
// Your custom stuff here
}
return self;
}

Creating constructors in Objective-C

Why do we always do this when creating constructors in Objective C?
self = [super init];
if ( self ) {
//Initialization code here
}
you can create constructor and destructor in objective-c with
-(id) init
{
self = [super init];
if(self)
{
//do something
}
return self;
}
-(void) dealloc
{
[super dealloc];
}
We reassign to self because [super init] is allowed to return a different object than the one it was called on. We if (self) because [super init] is allowed to return nil.
self is a class based on some superclass (e.g. UIViewController, NSObject - see your interface file to be sure which one). The superclass might need some form of initialization in order for the subclass to work as expected. So by first initializing the superclass we make sure default properties and the like are set. Without initializing the superclass first, we might experience some very unexpected behavior, especially in more complex objects like ViewControllers and the like.
Read this apple document on initialization
http://developer.apple.com/library/mac/#documentation/cocoa/Conceptual/ObjectiveC/Chapters/ocAllocInit.html

initWithCoder: getting called by nib & NSCoding!

Ok, I'm having a lot of problems right now trying to get initWithCoder: to work right. I have a nib file that gets loaded, and in my app delegate, I call unarchiveWithFile: for the view controller that is associated with that nib, and now my app crashes. I can see that initWithCoder: is being called twice, presumably once from when awakeFromNib: is called, and then from when I call unarchiveWithFile: since the view controller conforms to NSCoding. But now either it crashes as soon as the view loads or when I press an IBOutlet. Any suggestions??
Edit: Here's the code for initWithCoder:
- (id)initWithCoder:(NSCoder *)coder {
[super initWithCoder:coder];
[[self mapView] addAnnotations:[[coder decodeObjectForKey:#"Annotations"] retain]];
return self;
}
All I'm doing is decoding an array of annotations for a map view, but somewhere along the line this method is being called twice and then it crashes.
Don't forget to put the nil check in your init methods. E.g. the method you posted would be more correct if you wrote it as:
- (id)initWithCoder:(NSCoder *)coder {
if (self = [super initWithCoder:coder]) {
[[self mapView] addAnnotations:[[coder decodeObjectForKey:#"Annotations"] retain]];
}
return self;
}
That's not the cause of your problem, however.
Is there are good reason for you unarchiving your view controller yourself? If you're not doing anything special, you can rely on the existing mechanisms to do it. The default implementation of init for a UIViewController looks for a nib with the same name as your view controller, and if it exists, it loads the nib (via initWithNibName).
If there is data which you need to archive in and out, it may be that it shouldn't be actually part of the UIViewController. Factor it out elsewhere perhaps?
you can try
- (id)initWithCoder:(NSCoder *)coder {
if(self == nil)
{
[super initWithCoder:coder];
[[self mapView] addAnnotations:[[coder decodeObjectForKey:#"Annotations"] retain]];
}
return self;
}