my didAddSubview is not being called.
This is what I am doing.
In my viewController
- (void)viewDidLoad {
[super viewDidLoad];
SomeView *view = [[SomeView alloc] initWithFrame:CGRectMake(0.0, 0.0, CGRectGetWidth(self.view.frame), CGRectGetHeight(self.view.frame))];
[self.view addSubview:view];
}
Where my SomeView is a UI view (.h file)
#import <UIKit/UIKit.h>
#interface DyteMeetingView : UIView
#end
in which I have didAddSubview like this
- (void)didAddSubview:(UIView *)subview{
[super didAddSubview:subview];
[self someFunc];
}
I placed debugger in didAddSubview but the debugger never reaches here and hence [self someFunc]; is also not called.
Since didAddSubview is a lifecycle method for UI view, I am also not calling it from anywhere.
Can someone help me in figure out the concept I missed out on/what I could be doing wrong?
PS: I don't have any xib file for UIView.
PS: Intentionally added swift tag as well since there isn't large chunk of code and I am confident that swift developers would be able to understand the question/code and might be able to help me out.
didAddSubview in SomeView will be called when a sub view is added to an instance of SomeView, but that isn't what you are doing here. You are adding a SomeView as a subview of another view.
You want didMoveToSuperview; in this method you can use the superview property of self to identify the view that it moved to.
The didAddSubview will be called in viewController.view, instead of your SomeView, because you using viewController.view.addSubview(subview)
I am pretty stuck trying to create a IOS module for Titanium/Appc i am trying to intergrate https://github.com/antiguab/BAFluidView so i can use it in titanium.
I have followed the module tutorials have it working fine with just the standard view but when i try to add BAFluidView it doesnt work.
I have included the classes in xcode and have the code below.
#import "ComExampleFluidView.h"
#import "TiUtils.h"
#import "BAFluidView.h"
#import "UIColor+ColorWithHex.h"
#implementation ComExampleFluidView
- (void)initializeState
{
// Creates and keeps a reference to the view upon initialization
square = [[UIView alloc] initWithFrame:[self frame]];
BAFluidView *view = [[BAFluidView alloc] initWithFrame:view.frame];
[view fillTo:#1.0];
view.fillColor = [UIColor colorWithHex:0x397ebe];
[view startAnimation];
[square addSubview:view];
[self addSubview:square];
[super initializeState];
}
-(void)dealloc
{
// Deallocates the view
RELEASE_TO_NIL(square);
[super dealloc];
}
-(void)frameSizeChanged:(CGRect)frame bounds:(CGRect)bounds
{
// Sets the size and position of the view
[TiUtils setView:square positionRect:bounds];
}
-(void)setColor_:(id)color
{
// Assigns the view's background color
square.backgroundColor = [[TiUtils colorValue:color] _color];
}
#end
header file is
#import "TiUIView.h"
#interface ComExampleFluidView: TiUIView {
UIView *square;
}
#end
Can anyone give some suggestions on this?
since you are trying to bridge a native view, you need some layout helpers that are required to handle the Titanium-layout-system properly. Please check modules like ti.googlemaps, especially the initialization of views. In addition, your custom setters like setColor need to apply the color to your BAFluidView, not to your UIView, so you need to keep a reference of that inside your header. I guess the ti.googlemaps example should explain all concepts you are looking for. Good luck!
Novice iOS programmer here, so sorry if I'm missing something easy, but...
I have a UIViewController class called LVSTSPMasterViewController whose view was built in IB. The view contains a UIScrollView (added in IB) and that scroll view has a subview of type LVSTSPView. LVSTSPView has a controller of type LVSTSPViewController.
I want to respond to touches in the LVSTSPView, so I added gesture recognizers to LVSTSPViewController.m. When I execute the gesture (e.g., do a long press), the code crashes with message "EXC_BAD_ACCESS (code=1, address=...)" in main.m.
Relevant code:
In LVSAppDelegate.m:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
// Get pointer to app bundle
NSBundle *appBundle = [NSBundle mainBundle];
// Get xib file
LVSTSPMasterViewController *tspmvc = [[LVSTSPMasterViewController alloc] initWithNibName:#"LVSTSPMasterViewController" bundle:appBundle];
self.window.rootViewController = tspmvc;
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
In LVSMasterViewController.m:
#interface LVSTSPMasterViewController () <UIScrollViewDelegate>
// IBOutlet declarations
#property (nonatomic, weak) IBOutlet UIScrollView *TSPScrollView;
// Pointers for convenience
#property (strong, nonatomic) LVSTSPView *TSPView;
#end
#implementation LVSTSPMasterViewController
- (void)viewDidLoad
{
// Create LVSTSPViewController
LVSTSPViewController *tspvc = [[LVSTSPViewController alloc] init];
// Set up pointer to LVSTSPView
self.TSPView = (LVSTSPView *)tspvc.view;
// Set frame of LVSTSPView
self.TSPView.frame = self.TSPScrollView.bounds;
// Set tspvc's view as subview of TSPScrollView
[self.TSPScrollView addSubview:tspvc.view];
// Set up scroll view
self.TSPScrollView.pagingEnabled = NO;
self.TSPScrollView.contentSize = self.TSPView.frame.size;
self.TSPScrollView.minimumZoomScale = 1.0;
self.TSPScrollView.maximumZoomScale = 3.0;
// Set scroll view's delegate property
self.TSPScrollView.delegate = self;
}
In LVSTSPViewController.m:
- (void)loadView
{
// Create view
LVSTSPView *view = [[LVSTSPView alloc] initWithFrame:CGRectZero];
self.view = view;
// Long-press recognizer
UILongPressGestureRecognizer *pressRecognizer =
[[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(longPress:)];
[self.view addGestureRecognizer:pressRecognizer];
}
- (void)longPress:(UIGestureRecognizer *)gr
{
NSLog(#"longPress:");
}
One other note: If I set up the gesture recognizer in viewDidLoad: in LVSTSPMasterViewController.m, like so --
UILongPressGestureRecognizer *pressRecognizer =
[[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(longPress:)];
[self.TSPView addGestureRecognizer:pressRecognizer];
-- (and of course add longPress: to LVSTSPMasterViewController.m), then it works. But this doesn't seem like the right approach since the LVSTSPMasterViewController is not the view controller for LVSTSPView.
Any help will be appreciated!
Your view controller LVSTSPViewController is not retained anywhere or in other words your master view controller needs to retain it.
In LVSMasterViewController.m, change your code to
#implementation LVSTSPMasterViewController
{
LVSTSPViewController *tspvc;//creates strong reference to self(LVSTSPMasterViewController)
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
tspvc = [[LVSTSPViewController alloc] init];
// Set up pointer to LVSTSPView
self.TSPView = (LVSTSPView *)tspvc.view;
// Set frame of LVSTSPView
self.TSPView.frame = self.TSPScrollView.bounds;
// Set tspvc's view as subview of TSPScrollView
[self.TSPScrollView addSubview:tspvc.view];
// Set up scroll view
self.TSPScrollView.pagingEnabled = NO;
self.TSPScrollView.contentSize = self.TSPView.frame.size;
self.TSPScrollView.minimumZoomScale = 1.0;
self.TSPScrollView.maximumZoomScale = 3.0;
// Set scroll view's delegate property
self.TSPScrollView.delegate = self;
}
Also always call [super viewDidLoad] first in your viewDidLoad method. I would suggest to read more about view and view controller in the apple documentation. You necessarily do not need a view controller with every view. It all depends on your specific case. One view controller can manage multiple views.
I am trying to reload content from local file of UIWebView in viewDidDisappear of UIViewController. Badaccess is caught. But if I write the same code in viewWillDisappear, it works.
What might be the reason?
Once I've heard that UIWebView can't reload its content when it is not visible (not sure about it).
My code (hope it'll be enough):
#interface WebViewController : UIViewController <UIWebViewDelegate> {
ExtendedWebView * webView;
}
#property (nonatomic, retain) ExtendedWebView * webView;
#end
//WebViewController implementation
- (void)loadView
{
[super loadView];
WebViewCachingSingleton * webViewSingleton = [WebViewCachingSingleton sharedService];
ExtendedWebView * newWebView = [webViewSingleton getAvailableWebViewResource];//here I get ExtendedWebView. it works =)
newWebView.frame = CGRectMake(0, 0, 320, 400);
newWebView.delegate = self;
[self.view addSubview:newWebView];
self.webView = newWebView;
}
- (void)viewDidDisappear:(BOOL)animated
{
[[WebViewCachingSingleton sharedService] makeWebViewUnused:self.webView];
}
//WebViewCachingSingleton:
- (void) makeWebViewUnused : (ExtendedWebView *) aWebView
{
aWebView.isFree = YES;
[aWebView reload];
}
It will not work because viewDidDisappear is called when the view is disappeared, so all the subviews are released. The viewWillDisappear is called just before releasing all the objects associated with that view.
So you are trying to call the reload method of a UIWebView that has been already released. That is basically the reason why it crashes.
Hope it helps
The reload can be performed even if not displayed.
I tried to make an example of code to put in your state and have not had any problems.
Try to debug and enable NSZombieEnabled to see what actually happens to your application.
Try to post on any piece of code that might help us give you more details.
So I have a subclass of UITableViewController that loads some data from the internet and uses MBProgressHUD during the loading process. I use the standard MBProgressHUD initialization.
HUD = [[MBProgressHUD alloc] initWithView:self.view];
[self.view addSubview:HUD];
HUD.delegate = self;
HUD.labelText = #"Loading";
[HUD show:YES];
This is the result:
.
Is there any way to resolve this issue, or should I just abandon MBProgressHUD?
Thanks!
My solution was pretty simple. Instead of using self's view, I used self's navigationController's view.
HUD = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
[self.navigationController.view addSubview:HUD];
This should work for the OP because his picture shows he's using a UINavigationController. If you don't have a UINavigationController, you might add another view on top of your UITableView, and add the HUD to that. You'll have to write a little extra code to hide/show this extra view.
An unfortunate thing with this simple solution (not counting my idea adding another view mentioned above) means the user can't use the navigation controls while the HUD is showing. For my app, it's not a problem. But if you have a long running operation and the user might want to press Cancel, this will not be a good solution.
It's probably because self.view is a UITableView, which may dynamically add/remove subviews including the headers, which could end up on top of the HUD after you add it as a subview. You should either add the HUD directly to the window, or (for a little more work but perhaps a better result) you could implement a UIViewController subclass which has a plain view containing both the table view and the HUD view. That way you could put the HUD completely on top of the table view.
My solution was:
self.appDelegate = (kmAppDelegate *)[[UIApplication sharedApplication] delegate];
.
.
_progressHUD = [[MBProgressHUD alloc] initWithView:self.appDelegate.window];
.
[self.appDelegate.window addSubview:_progressHUD];
Works like a charm for all scenarios involving the UITableViewController. I hope this helps someone else. Happy Programming :)
Create a category on UITableView that will take your MBProgressHUD and bring it to the front, by doing so it will always appear "on top" and let the user use other controls in your app like a back button if the action is taking to long (for example)
#import "UITableView+MBProgressView.h"
#implementation UITableView (MBProgressView)
- (void)didAddSubview:(UIView *)subview{
for (UIView *view in self.subviews){
if([view isKindOfClass:[MBProgressHUD class]]){
[self bringSubviewToFront:view];
break;
}
}
}
#end
A simple fix would be to give the z-index of the HUD view a large value, ensuring it is placed in front of all the other subviews.
Check out this answer for information on how to edit a UIView's z-index: https://stackoverflow.com/a/4631895/1766720.
I've stepped into a similar problem a few minutes ago and was able to solve it after being pointed to the right direction in a different (and IMHO more elegant) way:
Add the following line at the beginning of your UITableViewController subclass implementation:
#synthesize tableView;
Add the following code to the beginning of your init method of your UITableViewController subclass, like initWithNibName:bundle: (the beginning of viewDidLoad might work as well, although I recommend an init method):
if (!tableView &&
[self.view isKindOfClass:[UITableView class]]) {
tableView = (UITableView *)self.view;
}
self.view = [[UIView alloc] initWithFrame:[UIScreen mainScreen].applicationFrame];
self.tableView.frame = self.view.bounds;
self.tableView.contentInset = UIEdgeInsetsMake(0.0, 0.0, 0.0, 0.0);
[self.view addSubview:self.tableView];
Then you don't need to change your code you posted in your question any more. What the above code does is basically seperating the self.tableView from self.view (which was a reference to the same object as self.tableView before, but now is a UIView containing the table view as one might expect).
I've Just solved that issue manually , it has been 2 years since Chris Ballinger asked but maybe someone get used of what is going on here.
In UITableViewController i execute an HTTP method in viewDidLoad , which is running in background so the table view is loaded while the progress is shown causing that miss.
i added a false flag which is changed to yes in viewDidLoad, And in viewDidAppear something like that can solve that problem.
-(void) viewDidAppear:(BOOL)animated{
if (flag) {
[self requestSomeData];
}
flag = YES;
[super viewDidAppear:animated];
}
I had the same problem and decided to solve this by changing my UITableViewController to a plain UIViewController that has a UITableView as a subview (similar to what jtbandes proposed as an alternative approach in his accepted answer). The advantage of this solution is that the UI of the navigation controller isn't blocked, i.e. users can simply leave the ViewController in case they don't want to waiting any longer for your timely operation to finish.
You need to do the following changes:
Header file:
#interface YourViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
- (id)initWithStyle:(UITableViewStyle)style;
#end
Implementation file:
#interface YourViewController ()
#property (nonatomic, retain) UITableView *tableView;
#property (nonatomic, retain) MBProgressHUD *hud;
#end
#implementation YourViewController
#pragma mark -
#pragma mark Initialization & Memory Management
- (id)initWithStyle:(UITableViewStyle)style;
{
self = [super init];
if (self) {
// create and configure the table view
_tableView = [[UITableView alloc] initWithFrame:CGRectNull style:style];
_tableView.delegate = self;
_tableView.dataSource = self;
}
return self;
}
- (void)dealloc
{
self.tableView = nil;
self.hud = nil;
[super dealloc];
}
#pragma mark -
#pragma mark View lifecycle
- (void)loadView {
CGRect frame = [self boundsFittingAvailableScreenSpace];
self.view = [[[UIView alloc] initWithFrame:frame] autorelease];
// add UI elements
self.tableView.frame = self.view.bounds;
[self.view addSubview:self.tableView];
}
- (void)viewWillDisappear:(BOOL)animated
{
// optionally
[self cancelWhateverYouWereWaitingFor];
[self.hud hide:animated];
}
The method -(CGRect)boundsFittingAvailableScreenSpace is part of my UIViewController+FittingBounds category. You can find its implementation here: https://gist.github.com/Tafkadasoh/5206130.
In .h
#import "AppDelegate.h"
#interface ViewController : UITableViewController
{
MBProgressHUD *progressHUD;
ASAppDelegate *appDelegate;
}
In .m
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
appDelegate = (ASAppDelegate *) [UIApplication sharedApplication].delegate;
progressHUD = [MBProgressHUD showHUDAddedTo:appDelegate.window animated:YES];
progressHUD.labelText = #"Syncing To Sever";
[appDelegate.window addSubview:progressHUD];
This should work.
[MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];
And to remove you can try
[MBProgressHUD hideHUDForView:self.navigationController.view animated:YES];