Which is the best implementation to allege code for all viewXXX selectors? - objective-c

first of all: my question is very theoretical. Even if I post an example, I just want to know which implementation is the best one to solve this kind of problem. Maybe you will laugh when you read this question because it is very fundamentally - but I want to understand how to deal with such a situation.
Imagine the following: You have got an application which communicates with an extern API via XML. As a fact of this the view cannot appear immediately, because the API needs time to react. My idea was to implement a subview which contains a loading animation. When the API sends a response this subview is removed and the main view appears. Here is my example:
- (void)viewWillAppear:(BOOL)animated {
UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
[myView setBackgroundColor:[UIColor whiteColor]];
myView.tag = 1;
UIActivityIndicatorView *loadingView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
loadingView.frame = CGRectMake(145, 160, 25, 25);
[myView addSubview:loadingView];
[self.view addSubview:myView];
[loadingView startAnimating];
}
- (void)viewDidAppear:(BOOL)animated
{
[self loadXMLData];
[self.tableView reloadData];
[[self.view viewWithTag:1] removeFromSuperview];
}
Everthing works fine. My problem is the following: it's not only this view where I have to do that. My applications consists of many views, so what is the best way to avoid repeating this code? I thought about following: I modify the (UIKit UIViewController) viewDidAppear selector and put the code in it. I don't know if Apple allows to change their frameworks. Furthermore it looks very dirty to me ;o) Is someone able to tell me how this is usually done? Thank you!
( hope you understand me, my first language is not English :-( )

Why not just make a subclass of UIViewController which has this code implemented in viewWillAppear and viewDidAppear, and then inherit every other view controller in the application from this "base" subclass rather than UIViewController? That will be much easier than trying to do anything to UIViewController directly.

Related

Admobs sometimes appear twice on different locations

We are adding admobs as a backup ad-system for countries without iAd. But sometimes the ads appear twice, the second ad sometimes in the middle of the screen about 100-200 px above the other ad. It seems like the second ad only appears when visiting a view that already has an ad. It kinda feels like the ad-call is in viewDidAppear instead of viewDidLoad, but we don't. Or didFailToReceiveAdWithError gets called on outside viewDidLoad-call for ad. Anyone know anything about this?
EDIT:
They CAN appear both at once, without having to revisit a view that already has an ad.
EDIT(code)
basically:
-(void) viewDidLoad
{
[self createAdBannerView];
[self.view addSubview:bannerView];
}
-(void) createAdBannerView
{
bannerView = [[AdBannerView alloc] initWithFrame:CGRectZero];
CGRect bannerFrame = bannerView.frame;
bannerView.frame = bannerFrame;
bannerView.delegate = self;
bannerView.requiredContentSizeIdentifiers = [NSSet setWithObjects:ADBannerContentSizeIdentifiersPortrait,AdBannerContentSizeIdentifierLandscape,nil];
}
-(void)bannerView:(AdBannerView*)banner didFailToReceiveAdWithError:(NSError *)error
{
[self.bannerView removeFromSuperview];
GbannerView = [[GADBannerView alloc] initWithFrame:CGRectMake(0.0, self.view.frame.size.height-99, 320,50)];
self.GbannerView.adUnitID=#"xxxxxxx";
self.GbannerView.rootViewController = self;
[self.view addSubview:self.GbannerView];
[self.GbannerView loadRequest:[GADRequest request]];
}
Also, if someone knows: In views containing tableViews, the locations of the admobs is wrong. It gets stuck behind a tabbar, even though the location takes this into account. This does not happen in a normal UIView. whatz..
I'd recommend you pull out the tableView question into its own question. There's an example of how to do this here, but I don't know if that satisfies your specific case).
Is there a reason you're not just using AdMob mediation here? They've got support for iAd and setting it up with client code is pretty easy.
For your specific case, I wonder if bannerView:didFailToReceiveAdWithError: is getting continuously called even after you remove AdBannerView from its superview. Why don't you create one GADBannerView and AdBannerView at the start in viewDidLoad:, then check if it exists before instantiating any new ones?

Add subview to active viewController from AppDelegate

I'm creating a application with an sqlite database. I update the database with information retrieved from a web service. I call the web service from AppDelegate like this:
-(void)applicationDidBecomeActive:(UIApplication *)application{
// get new information from web service
// update sqlite database
}
The web service can take quite a long time so I want to add a UIActivityIndicatorView to whatever viewController that is active. And of course, remove it when then update is done.
Ideas?
- (void)applicationDidBecomeActive:(UIApplication *)application
{
testView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 420, 480)];
testView.backgroundColor = [UIColor redColor];
[self.window.rootViewController.view addSubview:testView];
}
Then whenever you are done do:
[testView removeFromSuperview];
In each of your view controllers (or common super class view controller) listen for UIApplicationDidBecomeActiveNotification notification which is being sent when application becomes active.
This way you can have custom logic for each view controller without coupling app delegate to other parts of your code by using lots of ifs (if you need to distinguish which view controller is active one).
Because your view hierarchy can take any form, tracking the currently visible view controller is something you will have to do yourself. The exception: if everything in your app happens within a UINavigationController, you can always get the current view controller with this.
[navigationController topViewController];
If all you need to do is present an overlay, however, you can just add that view to the root view controller's view; all child view controllers are just presented as subviews anyway.
UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[self.window.rootViewController.view addSubview:activityIndicator];
[activityIndicator startAnimating];
Manually throwing views into the mix like this is not very elegant, though. I would consider posting notifications when various network events occur, and letting each view controller update itself appropriately.

When is it safe to manipulate screen controls through code in iOS/Objective-C

I have a question regarding iOS (or perhaps more accurately Objective-C) and properties. I have a UIView with a UISegmentedControl, by default it has 3 segments. I have a message which accepts a parameter and based on this parameter I may want to remove one of the segments. In UIView A I do this:
MyViewController *myview = [[[MyViewController alloc] initWithNibName:#"MyViewController" nib:nil] autorelease];
[[self navigationController] pushViewController:myview animate:YES];
[myview showItem:item];
In UIView B this happens in showItem:
-(void) showItem:(Item*)item{
if (item.removeSegment){
[segmentControl removeSegmentAtIndex:0 animate:NO];
}
}
I have noticed that the segment only gets removed when I call showItem after I have pushed it on the navigation controller. When I swap those two line, so I first call showItem and then push the view, the UISegmentedControl still has three segments instead of two.
This just feels wrong, it seems like bad practice that my code will break if someone doesn't call two messages in the right order. Is there a better way to do this? I've been looking at some sort of a property lifecyle that I can use, I am very familiar with this from ActionScript 3, but I have been unable to find anything on the subject.
(as an aside: in AS3 I would make a property, in the setter I don't manipulate any screen controls but call InvalideProperties. My overriden methode CommitProperties will be called once the entire object and child controls have been created. In CommitProperties I check if my property value has changed and this is where I would remove the segment.)
A common way of doing something like this is to create an Item *item property in MyViewController and set that when myview is created. So, your code becomes:
MyViewController *myview = [[[MyViewController alloc] initWithNibName:#"MyViewController" nib:nil] autorelease];
myview.item = item;
[[self navigationController] pushViewController:myview animate:YES];
MyViewController would then use that property in its viewWillAppear: method to configure its own segment control.
I think what you are falling prey to is myview->segmentControl doesn't exist until myview.view is referenced because of the lazy load of the view.
-(void) showItem:(Item*)item{
[self view]; // NO OP TO FORCE LOAD!!
if (item.removeSegment){
[segmentControl removeSegmentAtIndex:0 animate:NO];
}
}
Should work for you. Hope this helps!

Is this a correct way to add/remove views?

Lets say that I have 4 view controllers (call them FirstView,SecondView,ThirdView,FourthView) which are created programmatically and all are in separate files:
In AppDelegate.m didFinishLaunchingWithOptions method I have these lines of code
self.rootViewController = [[rootViewController alloc]initWithNibName:#"rootViewController" bundle:nil];
self.window.rootViewController = self.rootViewController;
In rootViewController.m loadview method I have
self.view = [[UIView alloc]initWithFrame:[UIScreen mainScreen].applicationFrame];
self.firstView = [[FirstView alloc]init];
[self.view addSubview:self.firstView.view];
That code works fine - first view is displayed.
Let's continue
In FirstView.m switchViews method
NOTE: Please see the comments in code
self.secondView = [[SecondView alloc] initWithNibName:#"SecondView" bundle:nil];
// I think here secondView is added to rootViewController - right ?
[self.view.superview addSubview:self.secondView.view];
// Here first view is removed from rootViewController - right ?
[self.view removeFromSuperview];
Here is how I add/remove views.
Is this approach correct?
Can you recommend a better solution?
I have read about UINavigationController, but I don't think it could be a solution in this case.
You say:
I have 4 views (call them FirstView ...
Then you say:
[self.view addSubview:self.firstView.view];
Which makes me think that FirstView isn't actually a UIView - as you claim it is. Instead, it's probably a UIViewController - a different beast altogether.
If my suspicion is correct - then you are "off-track" so to speak.
Going beyond that to your sample code snippet:
self.secondView = [[SecondView alloc] initWithNibName:#"SecondView" bundle:nil];
// I think here secondView is added to rootViewController - right ?
[self.view.superview addSubview:self.secondView.view];
// Here first view is removed from rootViewController - right ?
[self.view removeFromSuperview];
This is definitely not a great idea. Here's why:
First: your view controller doesn't explicitly "know" anything about the superview you are so casually inserting and removing subviews to/from - so it shouldn't do that. You may, alternatively, create your own view and insert/remove subviews from that - which would not only be perfectly acceptable but also common practice.
Second: if these are actually UIViewControllers like I think they are - then you are not properly handling hooking them up to the UIViewController event chain - which means methods on these subclasses like viewDidAppear: or viewDidUnload will not fire.
From what I see in your code, UINavigationController seems like it would help. If you don't want a navigation bar, you can definitely hide it, but the methods in UINavigationController should help you with switching views.
If your views only need to display temporarily, you could also use Modal View controllers. An example of Modal View controllers can be found here.
If you haven't already, check out the View Controller Programming Guide from Apple.

Trying to dismiss subview and UIView

I'm still very new to iOS developing. In fact, if there is a super noob, I would be one :p. Currently I am working on creating an IBAction button that accesses a subview. I have 2 ViewControllers, AddClientVC and NewClientVC, both with .nib files. So basically, inside my AddClientVC I implement an IBAction button with the following code:
- (IBAction)buttonPressed:(id)sender
{
UIView *transparentBG = [[UIView alloc] initWithFrame:CGRectMake(-5, -5, 1500, 2500)];
transparentBG.backgroundColor = [UIColor blackColor];
transparentBG.opaque = NO;
transparentBG.alpha = 0.5;
[self.view addSubview:transparentBG];
transparentBG.center = transparentBG.center;
vc = [[NewClientVC alloc] initWithNibName:#"NewClientVC" bundle:nil];
[self.view addSubview:vc.view];
vc.view.center = self.view.center;
}
As you can see I implemented a UIView as a transparent background. Basically AddClientVC --> Transparent Background --> NewClientVC. Now I have created another IBAction button but this time inside NewClientVC as a function to dismiss the accessed subview which looks like this:
- (IBAction)saveDismiss:(id)sender
{
[self.view removeFromSuperview];
}
The problem I'm having right now is when I click the saveDismiss button it only removes the subview that I called previously on AddClientVC but it didn't remove the transparent background I have created as a UIView. So the problem is how do I implement an action which simultaneously removes my subview and the UIView transparent background I created.
I need all the help I can get :)
I'm not too sure I fully understand what you want to happen, but maybe you could try something like this?
- (IBAction)saveDismiss:(id)sender
{
[vc removeFromSuperView];
[self.view removeFromSuperview];
}
I recommend not to manage your screens by adding subviews manually but instead use
- (void)presentModalViewController: (UIViewController *)modalViewController
animated: (BOOL)animated
method on your root viewController.
Or better instantiate a UINavigationController and use push and pop methods to drill down/up your views.
See apple reference here
Do not worry about code execution speed and stay confident in apple's SDK. UIKit is optimized for best user experience. Trying to boost your code by doing inappropriate SDK use is, in my opinion, a risky strategy. ;) – Vincent Zgueb
Sorry Vincent but I don't agree with you. I reached here because I want to implement an gesture that adds a sub-view for my view, which will be the navigation of my app.
[self.view addSubview:ctrl.view];
is faster presenting the view than
[self.navigationController presentModalViewController:ctrl animated:NO]
and by the way, the solution to the topic in my case was:
[self.view sendSubviewToBack:ctrl.view];