I have my ViewController, MyWebViewController where I use a webView, created in xib. .h file has
#interface MyWebViewController : UIViewController
#property (nonatomic,strong) IBOutlet UIWebView* webView;
in .m file,
- (void)viewDidLoad {
[super viewDidLoad];
[self.webView loadRequest:[NSURLRequest requestWithURL:[[NSURL alloc] initWithString:#"http://www.google.com"]]];
}
Here is my xib
It works perfect for me.
Later I create another ViewController, RootViewController of type MyWebViewController.
#import "MyWebViewController.h"
#interface RootViewController : MyWebViewController
The xib of MyViewViewController is loaded as expected, but the webView is not loaded to the xib. I spent more time in debugging.
Later, I removed the webView from xib and created it programmatically.
self.webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 441)];
self.webView.delegate = self;
[self.webView loadRequest:[NSURLRequest requestWithURL:[[NSURL alloc] initWithString:#"http://www.google.com"]]];
[self.view addSubview:self.webView];
Creating the webView programmatically gives the expected output.
I need a little clarification that, why was my webView not loaded, when it was created in xib, and, works fine when it was created programmatically?
In your RootViewController, did you call:
- (void)viewDidLoad {
[super viewDidLoad];
}
This way it will trigger the base class function and webView will load expectedly. You forget to put this in MyWebViewController as well.
EDIT :
The reason self.webView is not getting load in derived class is because it is marked IBOutlet so it needs a reference of pre-allocated element from UIView or xib and in the derived class we are not instatiating base view file e.g., MyWebViewController.xib. So self.webView appears nil and function call on nil getting ignored silently. So, once you do it by code it is independent of xib file and works.
Hope it helps!
This was due to change in iOS9 view loading behavior. Developer is supposed to update the UI elements in -viewWillLayoutSubviews or -viewDidAppear.
Related
I'm hitting an iOS assertion when dismissing a UIViewController. The UIViewController has a UIView, to which I've added a WKWebView. Into that WKWebView I've loaded a PDF file. The PDF displays and functions fine. When I dismiss the window, Xcode reports an assertion:
-[PDFExtensionTopView _accessibilityUnregisterRemoteView]: unrecognized selector sent to instance
If I have my All Objective-C Exceptions breakpoint on, execution is stopped. I can continue, but this is rather disruptive. Users never see any issue, so this is purely a development-time problem. I work around the issue by disabling breakpoints when using this view, but would prefer to find a real fix. I'm on Xcode 11.3.1, using ObjC in this class.
I've created a simplified dummy project. The entire UIViewController's code is below. It is presented from a simple UIButton that passes nothing to this UIViewController.
Moving the displayPDF method call is in viewWillAppear, but no change if in DidAppear, DidLoad, etc. It isn't related to the specific PDF (I've tried files from multiple sources).
If I use displayHTML (which puts dummy HTML into the webView), I do not experience the problem.
I might just be rusty in ObjC and missing something obvious. Any thoughts?
#import "MyPDFViewController.h"
#import <WebKit/WebKit.h>
#interface MyPDFViewController ()
#property (strong, nonatomic) IBOutlet UIView *pdfContainerView;
- (IBAction)closeButtonPressed:(id)sender;
#property (nonatomic, strong) WKWebView *webView;
#end
#implementation MyPDFViewController
-(void)viewWillAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self displayPDF];
}
-(void)displayPDF {
NSString *path = [[NSBundle mainBundle] pathForResource:#"MyPDFFile" ofType:#"pdf"];
NSData *data = [NSData dataWithContentsOfFile:path];
self.webView = [[WKWebView alloc] initWithFrame:self.pdfContainerView.frame configuration:[[WKWebViewConfiguration alloc] init]];
[self.webView loadData:data MIMEType:#"application/pdf" characterEncodingName:#"utf-8" baseURL:[NSURL URLWithString:#""]];
[self.pdfContainerView addSubview:self.webView];
}
-(void)displayHTML {
[self.webView loadHTMLString:#"<html><body>Hi.</body></html>" baseURL:nil];
}
- (IBAction)closeButtonPressed:(id)sender {
[self dismissViewControllerAnimated:YES completion:^{
//
}];
}
#end
Hello StackOverflow.
I am trying to setup a UIView such that it loads itself from XIB
file in Xcode.
To do this, I went through the following initial steps:
Created empty UIView subclass.
Added a blank XIB file.
Then, I added all the subviews I wanted into the XIB file, and made corresponding IBOutlet Properties inside the UIView Subclass.
I watched this video to show me how to properly connect the outlets and set the files owner. The video instructs me to do the following things:
Do not set the UIView class to your subclass in XIB. Time link
Set the File's Owner to your UIView subclass in XIB:Time Link
Insert a IBOutlet into your UIView class of type UIView so your XIB file can load into that.Time link
Override initWithCoder like (image) if you intend to initialize the custom UIView within another XIB file.
Override initWithFrame like (image) if you intend to initialize the custom UIView programatically within another class file.
Cool, I have done all of these things, and am choosing to initialize my UIView programatically.
See my UIView subclass implementation file:
#import "CXHostsTableViewCellContentView.h"
#implementation CXHostsTableViewCellContentView
#pragma mark Custom Initializers
-(instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
[[NSBundle mainBundle]loadNibNamed:#"CXHostsTableViewCellContentView" owner:self options:nil];
[self setBounds:self.view.bounds];
[self addSubview:self.view];
}
return self;
}
-(instancetype)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self)
{
[[NSBundle mainBundle]loadNibNamed:#"CXHostsTableViewCellContentView" owner:self options:nil];
[self addSubview:self.view];
}
return self;
}
And of course, my header file:
#import <UIKit/UIKit.h>
#import "CXStyleView.h"
#interface CXHostsTableViewCellContentView : UIView
#pragma mark UIView Properties
#property (strong, nonatomic) IBOutlet UIView *view;
#property (nonatomic,weak)IBOutlet UIView *standardView;
#end
I also have an image here of the XIB file's owner and another of the IBOutlet link from the base UIView to the outlet on file's owner.
Right, so everything's looking pretty good, should be no problem running this right?
Nope, whenever I initialize this subview and present it, I get a crash:
CXHostsTableViewCellContentView *scrollContentView = [[CXHostsTableViewCellContentView alloc]init];
I've really got no idea how to solve this, as I'm sure I'm following all of these steps right. I've googled and come across this question which has the same symptoms, but the answer has identical code to what I'm using, and this question with a contradictory reply.
I'm not sure what to do at this point, or what is causing the crash. I know that if I have NO outlets linked at all, it works. But then again, nothing displays either.
I think that You will face Problem When You Allocate Memory to Your scrollContentView object.
so,Try To allocate Memory With Frame.
i.e
Write this in .m file
- (void)myAllocation {
//do your stuff
}
- (id)initWithFrame:(CGRect)aRect {
self = [super initWithFrame:aRect];
if (self) {
[self myAllocation];
}
return self;
}
- (id)initWithCoder:(NSCoder*)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
[self myAllocation];
}
return self;
}
...
CXHostsTableViewCellContentView *scrollContentView = [[CXHostsTableViewCellContentView alloc] initWithFrame:CGRectMake(0, 10, 0, 20)];
I recently converted my .xib file to Storyboards and decided to programmatically add a UITableView to my ViewController in the storyboard.
I used this code to accomplish this:
// ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> {
UITableView *table;
}
// ViewController.m
#import "ViewController.h"
#interface ViewController (PrivateStuff)
// unimportant code...
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
table = [[UITableView alloc] initWithFrame:self.view.bounds];
table.delegate = self;
table.dataSource = self;
[self.view addSubview:table];
}
Unfortunately, whenever I try to run it, Xcode is giving me this message...
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[UITableViewController loadView] loaded the "ViewController" nib but didn't get a UITableView.'
... which doesn't make any sense. I have everything that needs to be hooked up on its correct order and all of my other views with UITableViews have no problem, in spite that the code is the same.
What could I do to solve this problem? Thanks in advance.
I agree with #rdelmar-Xcode is saying that a nib was loaded during a [tableviewcontroller loadView] call-so that means there is a tableviewcontroller somewhere in your code...but it also means that somehow the nib you created is still linked to your view controller. You may need to look at the connections inspector under utilities in Xcode and see if your nib still has any persistent links present and delete them. Otherwise, as long as you are providing a TableViewCell, either custom or generic, in the cellForRowAtIndexPath method, the above code should work
I have create a UIVeiw class and a .xib. Within this .xib view I have its set to freeform with the dimensions of 400x200 and I have assigned it to my custom class with the same name:
Storyboard: blogView
Class Files: blogView.h & blogView.m
Within in the .xib i have added a label and a text field and linked them up to variable within the .h files etc (See code below).
blogCont.h
#import <UIKit/UIKit.h>
#interface blogCont : UIView
#property (strong, nonatomic) IBOutlet UILabel *lbBlogDate;
#property (strong, nonatomic) IBOutlet UITextView *txtBlogTitle;
#end
blogCont.m
#import "newsStoryView.h"
#implementation blogCont
#synthesize lbBlogDate;
#synthesize txtBlogTitle;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code place a log to see if it loads
NSLog(#"View Loaded");
}
return self;
}
#end
Now with in my main viewController.m file i have added the following code to init this view class, and I have added a background colour to see if this loads in.
viewController.m
UIView *blogCont = [[blogView alloc] init];
blogCont.backgroundColor = [UIColor purpleColor];
[subview addSubview:blogCont];
Now when I run this it all works well but as I do not see the purple background it looks as if the view does not load, but within the log I do see the NSLog message I have within this view NSLog(#"View Loaded"); so it seems it initiating this, but I cannot for the life of me get this to display?
Now if I change the code slightly to my main View Controller.m fiel to:
CGRect blogFrame;
blogFrame.origin.x = 20;
blogFrame.origin.y = 20;
blogFrame.size = CGRectMake(400,200);;
newsStoryView *blogCont = [[blogView alloc] blogFrame];
blogCont.backgroundColor = [UIColor purpleColor];
[subview addSubview:blogCont];
Then I get my view display a nice purple box, so this shows up when I set a frame size and the init the view with it 'blogFrame', bu tI thought that all this would be set within the .xib settings so no need to do this?
SO how can I create this external view class and assign it into another view and then manipulate its data, as accessing the label in the .xib using blogCont.lbBlogDate.text does not seem to work that is it probably does but as I cannot view it i cannot confirm it.
What am i doing wrong?
Thanks
Seems I nearly answered my own question then did:
I was not setting the size within my separate class view I was asking for a size when init it:
- (id)initWithFrame:(CGRect)frame
this is asking for a size
so I could do the following to the above:
- (id)init
{
self = [super initWithFrame:CGRectMake(0, 0, 478, 220)];
.... rest of code
Setting the size within the view load.
But I could also set it when I init it in my main view controller as below:
newsStoryView *blogCont = [[blogView alloc] initWithFrame:CGRectMake(0, 0, 400, 200)];
This is better as I can control the position of each one. Hope this helps anyone
I have a UIView called baseViewand in that I have initWithFramewhere I add some other views and do some custom stuff. The same view also has a NIB file.
Now I have a UIViewController class named AppController in which I want to add the baseView view to the view of the AppController view so I am doing this:
self.view = baseView; but the problem is that the NIB file does not get loaded. How do I make sure the customized stuff AND the NIB file get´s loaded/run?
You have many options, depending on how your "baseView" class is meant to be used and integrated in to your application. It's not clear just how you intend to use this class -- as the view in a UIViewController subclass, or as a reusable modular component mean to be instantiated multiple times throughout your application, for use in many different view controllers.
If your view is meant to be the only view in a UIViewController subclass, then Phonitive is correct -- bundle it together with the UIViewController subclass .xib file and use the UIViewController's viewDidLoad to do final initialization.
But if you want your View class to be a subcomponent reused multiple times in different view controllers, integrated either via code or via inclusion in a .xib file for another controller, then you need to implement both the initWithFrame: init method, and awakeFromNib, to handle both cases. If your internal initialization always includes some objects from .xib, then in your initWithFrame you'll need to load your .xib manually in order to support "customer" classes that want to create your widget via code. And likewise, if a .xib file contains your object then you'll need to make sure you call any code-required finalization from awakeFromNib.
Here's an example of how to create a UIView subclass component with the UI design in a nib.
MyView.h:
#interface MyView : UIView
{
UIView *view;
UILabel *l;
}
#property (nonatomic, retain) IBOutlet UIView *view;
#property (nonatomic, retain) IBOutlet UILabel *l;
MyView.m:
#import "MyView.h"
#implementation MyView
#synthesize l, view;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
// Initialization code.
//
[[NSBundle mainBundle] loadNibNamed:#"MyView" owner:self options:nil];
[self addSubview:self.view];
}
return self;
}
- (void) awakeFromNib
{
[super awakeFromNib];
// commenters report the next line causes infinite recursion, so removing it
// [[NSBundle mainBundle] loadNibNamed:#"MyView" owner:self options:nil];
[self addSubview:self.view];
}
- (void) dealloc
{
[l release];
[view release];
[super dealloc];
}
Here's what the nib file looks like (except that file's owner needs to be changed to MyView class).
be sure to hook up both the view and label outlets to File's Owner. That's it! A template for creating re-usable UIView widgets.
The really neat thing about this structure is that you can place instances of your MyView object in other nib files, just place a UIView at the location/size you want, then change the class in the identity inspector (CMD-4) to MyView, and boom, you've got an instance of your widget in whatever views you want! Just like UIKit objects you can implement delegate protocols so that objects using your widget can be notified of interesting events, and can provide data to display in the widget to customize it.
I found this post after having a problem trying to do this in my app. I was trying to instantiate the view from a NIB in the ViewDidLoad method, but the controls acted as if they were disabled. I struggled with this trying to directly set the userInteractionEnabled property and programmatically set the touch event selector for a button in this view. Nothing worked. I stumbled upon another post and discovered that viewDidLoad was probably too soon to be loading this NIB. I moved the load to the ViewWillAppear method and everything worked. Hope this helps someone else struggling with this. The main response was great and works well for me now that I have it being called from the proper place.
if you want to use a NIB, it's better for your UIView to be linked with a UIViewController, in this case you can use
UIViewController *vc=[[UIViewController alloc] initWithNibName:#"YourNIBWihtOUTEXTENSION" bundle:nil]
[self.view addSubView:vc.view ];
becareful of memory leaks, you have to release vc
If you have a custom UIView with a xib file.
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
id mainView;
if (self)
{
NSArray *subviewArray = [[NSBundle mainBundle] loadNibNamed:#"HomeAllAdsView" owner:self options:nil];
mainView = [subviewArray objectAtIndex:0];
}
return mainView;
}
- (void) awakeFromNib
{
[super awakeFromNib];
}
This post helped me Building Reusable Views With Interface Builder and Auto Layout. The trick had to do with setting the IBOutlets to the FileOwner and then adding the content view to itself after loading the nib