Using AppDelegate method in ViewController - objective-c

NOTE: Problem Solved. Thanks
I'm simply a high school student on a brand new app developer program. So, please excuse me seeming like I know very little, as, I really don't know as much as I will yet. Bear with me XD
I need to use the following startup from AppDelegate to display a start screen for the webView in my application, rather than a blank white screen:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// THIS SECTION IS WHAT I NEED
NSURL *url = [NSURL URLWithString:#"http://www.earlham.k12.ia.us"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[webView loadRequest:request];
return YES;
}
To use that, however, I need access to webView, which is my WebView object that I declared in ViewController.h. However, that doesn't work, because I can't declare it twice, nor use it from the other header file, to my knowledge. I know it's possible, but at this basic level, I don't know how. Please include code examples.
Many thanks!

Why would you put this in the application delegate? This looks like something the actual ViewController should be able to handle.

The instance of UIWebView should only be managed by its containing UIViewController. The app delegate is responsible for getting the view controller on screen as a subview of the window. From there, it is the view controllers responsibility to manage the web view appropriately.

I agree with the other answers that this code should belong in the view controller, not in the app delegate.
If you do want to access code in your app delegate, you'll have to create a method containing the code you want and call that from your view controller (since you don't want to be calling didFinishLaunchingWithOptions yourself, it gets called for you at the right time).
In general though, it's better to separate out responsibility in your code and not put general code in your app delegate.

Related

How to use NSWindowController class

I am sorry if this seems trivial, but I am sure its a reasonable question to ask here.
I worked a lot around the NSWindowController class, and it seems the only way to get it
to work fully (for my purpose), is by creating a new xib-file along with it.
My question is, would it be somehow feasible to work with MainMenu.xib and the NSWindowController class and an instantiated object controller, to get interaction with the windows' content. So far without xib the only code segments getting executed are within awakeFromNib. The purpose being, I want to save xib-file space, complexity and have it easily integrate with a bigger project. Just fyi this is not a document-based project.
Should I choose a different subclass of NSObject other than NSWindowController? Or is it not possible?
The code required to run for the class to be working fully is as follows:
- (void) tableViewSelectionDidChange:(NSNotification *)notification
{
NSInteger selectedRow = [logsTableView selectedRow];
if ([directoryList containsObject:[directoryList objectAtIndex:selectedRow]])
{
NSString *logContent = [NSString stringWithContentsOfFile:[directoryList objectAtIndex:selectedRow]
encoding:NSUTF8StringEncoding
error:NULL];
if (logContent != NULL)
{
[logsTextView setString:logContent];
} else
{
[logsTextView setString:#"No permission to read log"];
}
}
}
NSWindowController usually wants to create the window it controls, which means you either need to give it a XIB file that contains the window to create or override the various window creation methods to customize the window in code. So it's probably not feasible to use an already-instantiated window from a different XIB with your NSWindowController.
That said, I almost always create a a XIB and an NSWindowController subclass for every window in my apps. Even the preferences window gets its own window controller class. The only exception would be extremely simple windows, but even now I'm struggling to think of a good example.
Your method isn't being called because window controller instance isn't set as the table view's delegate. The typical pattern here is to create your window in a XIB, set your window controller as the custom class of the File's Owner object, and then hook up the table view's delegate and dataSource outlets to File's Owner. This makes your window controller the table view's data source and delegate, and the connections will be established automatically when the XIB is loaded.

UIViewController visible callback

I am developing an iOS application where need to do some stuff when I have Internet connection and other, when I haven't. If I haven't at some point I will show a message to the user to give me internet and come back. The question it is how to detect the following situation:
the user press the Home button twice, goes to multitasking , Settings and will connect to internet
the user comes back with multitasking to my app, but doesn't press anything
I know I will get callbacks to the AppDelegate:
- (void)applicationDidEnterBackground:(UIApplication *)application
- (void) applicationDidBecomeActive:(UIApplication *)application
but the code ( it is not started by me) it is very big, and I don't want to handle there the UIViewController needs, if there is any alternative.
My UIViewController's - (void)viewDidAppear:(BOOL)animated it isn't called when the user came back.
The breakpoint it is not hited for sure!
Any usable ideas, except in AppDelegate?
You can use the notification center to listen to applicationDidEnterBackground within the view controller:
[[NSNotificationCenter defaultCenter] addObserver: self
selector: #selector(handleEnteredBackground:)
name: UIApplicationDidEnterBackgroundNotification
object: nil];
Do this in viewDidLoad. Similarily for applicationDidBecomeActive.
Don't forget to remove yourself as an observer in viewDidUnload.
The application delegate is the correct place to be handling application state changes, but just because that is the case, it doesn't mean you must put all the logic that is triggered by the application state change in there.
Put the logic where it belongs. If it's networking code, that's not in the application delegate and it's not in the view controller, it's in a separate class. Then look into ways of tying the different parts of your application together. In most cases, notifications, KVO and the shared instance pattern are good approaches to take.

Communication between UIViewControllers

I am new with Objective-C so apologies for a dumb question.
I am opening an "options" view controller from my main view controller. Both are built in the storyboard. Before and after presenting the options controller I need to stop and start a timer on my main view controller. After the options controller is closed (a button calls dismiss) I need to send some info back to my main controller or at least let my main controller know that it needs to refresh some values.
MAIN QUESTION
What's the best way of presenting a view controller and executing some presenter's methods before and after opening?
WHAT I'VE TRIED
I found a few ways to do it, but they are all cumbersome and I assume that there must be some plausible way of doing it.
Ideally I'd like to use the segue I set up in the storyboard between the two controllers.
I managed to call the options controller programmatically by accessing the storyboard and calling instantiateViewControllerWithIdentifier. It worked but looks a bit complex.
I was not able to find a delegate method on the UIViewController to handle the dismiss event
When I was trying to access the main controller in the options controller via presentingViewController and downcasting it, I got a linkage error by including my .h file twice (not sure what are the Obj-C standards of using #define).
Appreciate your help...
For communication between ViewControllers that are weakly linked, you could use the NSNotificationCenter:
https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSNotificationCenter_Class/Reference/Reference.html
Here you can send a message to all ViewControllers listening, which need to process some changes (for example an option to change the font size).
It's really easy to implement and it keeps certain ViewControllers less dependent on each other.
All of this can be done quite easily with storyboard and NSNotificationCenter, and NSCoding. In the viewDidLoad method of your main controller, put this code:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receiveNotification:)
name:#"Update"
object:nil];
Then create this method in the same controller:
(void)receiveNotification:(NSNotification*)notification
{
//...
}
When you want to make the main controller update from the options controller:
[[NSNotificationCenter defaultCenter] postNotificationName:#"Update" object:self];
Also, I would suggest using NSArchiving for Basic Data Persistence. Just found this tutorial, looks pretty good.
http://samsoff.es/posts/archiving-objective-c-objects-with-nscoding
Basically, create an object that can store information, code it using nscoding, and then uncode it whenever you need it. It has worked great for me.
Hope that helps!
MAIN QUESTION What's the best way of presenting a view controller and executing some presenter's methods before and after opening?
Just in case the answers above are a bit more involved than you'd like, I'll suggest that the easiest way to execute a presenter's methods before opening is to do so in the presenter's prepareForSegue method. If you need to send data to the destination view controller, you can access its properties this way:
ViewController *destinationVC = [segue destinationViewController];
An easy way to execute the presenter's methods after opening would be:
ViewControllerSubclass *previousVC = [self presentingViewController];
And then use the class or instance to execute your class or instance methods. You could do this in the destination's viewWillAppear.
Sorry if you already knew all this; it's often difficult to surmise what level of complexity is needed.
I have run into this with almost every app I have on the market. Difference is I have never decided to go down the storyboard path.
The way I have always been able to accomplish this is to provide accessor functions between the controllers. You get past the linker issue by defining the cross defined controller as simply a UIViewController type within your options view header, then including the main view controller' header only in the .m file. Now when you call a main view controller routine from your options view, you will have to cast it to the type of your main view controller!
You will also have to provide a routine in your options view that will allow you to set the variable that will hold a pointer to your main view controller to self.
Example for your optionsView
#interface optionsViewController : UIViewController{
UIViewController * myReactiveMainViewController;
}
-(void)setMyReactiveMainViewController:(UIViewController *)controller;
No in the .m file for the optionsView
#import "myMainViewController.h"
-(void)setMyReactiveMainViewController:(UIViewController *)controller{
myReactiveMainViewController = controller;
}
In any other call back to the main view controller you will have to do this:
-(void)returnToMain{
[(myMainViewController *)myReactiveMainViewController someCall:variable];
}
This example would of course assume that your myMainViewController implements a method called "someCall" that take on input parameter.
Thanks for replies.
I ended up with
Calling prepareForSegue to execute pre-transition code
Calling performSelector on presentingViewController when releasing presented view controller.
I am sure other suggestions would work too.

I added a WebView to my Cocoa app and it's generating an error

I added a WebView to my app and I'm loading a page into it using this code:
-(void)awakeFromNib{
NSString *resourcesPath = [[NSBundle mainBundle] resourcePath];
NSString *htmlPath = [resourcesPath stringByAppendingString:#"/calendarHTML/test.html"];
[[webView mainFrame] loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:htmlPath]]];
}
However, when I run the app I receive the following error:
Layout still needs update after calling -[WebHTMLView layout].
WebHTMLView or one of its superclasses may have overridden
-layout without calling super. Or, something may have dirtied
layout in the middle of updating it. Both are programming errors in
Cocoa Autolayout. The former is pretty likely to arise if some
pre-Cocoa Autolayout class had a method called layout, but it should be fixed.!
What is causing this problem?
This is caused by the fact that the nib containing the window that you have placed the WebView into is using the new Auto Layout feature, introduced in Lion.
When a nib file has auto layout enabled, the window will call the -layout method on all NSView objects in the window.
This causes a problem with WebView because it had a method named -layout before it the method was added to the NSView API in Lion, and WebView's layout method does not understand auto layout.
Probably the best fix for the time being is to use the old autoresizing mask method of laying out the views in your window. As Xcode now creates nib files with autolayout enabled, you need to disable it yourself.
You can do that in the File inspector for your nib file, by disabling the Use Auto Layout checkbox.
After you do this, you'll need to make sure that all the views in the nib have the correct autoresizing settings in the Size tab of the view inspector.
Note that you can safely ignore that log message for WebViews.
I am not sure about the case of WebView but If you are using any custom class (like subclass of UILabel) and you are using the method :
- (void)updateConstraints
{
}
then definitely It will crash your app. Best solution is to remove this method and write your required changes in 'awakeFromNib' method. Hope this help someone else who is getting this crash in custom class.

What is the use of the line [super loadView]

I just wanted to know whether i am write or not
I have been working with iPhone technology for about 4 months and the only piece of code that i write in the loadView method is to add some views like the buttons,labels etc to the current instance of the viewController class so that when i use its view property all those views are added to the window.
But the piece of line that really bugs me is
[super loadView];
what is the use of this method all i came to know from diff sites is that "if i don't use this method my app will crash" that's not a reason i am looking for, so i made a virtual concept that this line might give us a black instance of UIView and then we add all the views [self.view addSubView:btn]; to the view provided to us by this line.
So all i wanted to know is that am i right or wrong, i think the [super loadView]; line does more than that can anyone give me a detailed explanation or provide me a link from where i can refer this concept.
-loadView is called by your view controller when the view is actually needed. Implement it if you are creating your view manually and not in IB. You are responsible for making sure the view property has a view assigned to it by the time this method is finished. Do not call [super loadView] or [self loadView] by yourself!
Official docs: "Your custom implementation of this method should not call super."
http://developer.apple.com/library/ios/documentation/uikit/reference/UIViewController_Class/Reference/Reference.html#//apple_ref/occ/instm/UIViewController/loadView
The super keyword calls the superclass' implementation of this method. So you probably are right on the money (I don't do objective-c) and this call initializes all the stuff you need to display your app.