slow loading of nib in swift2 by instantiateWithOwner - swift

i try to load a custom uiview from a nib by calling instantiateWithOwner
func loadViewFromNib() -> UIView {
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: "myCustomView", bundle: bundle)
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
return view
}
the view is loading successfully but it long time to load (5 seconds).
when i traced the code i found that the reason of delaying in this line :
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
i removed all autolayout constraints but it still delay in calling

I have the same problem, and I found that it's due to the font from the UILabel or other views need font. Change the font to "System Font" solved the problem.
If you remove all subviews from nib you will notice that the loading time is very fast. Then add subview back one by one to check which view slow the time.

Related

UIView created from XIB file is not showing

I have created a xib file in my project which looks like this
I'm initializing it with this code
class MainItem: UIView {
class func instanceFromNib() -> UIView {
let view = UINib(nibName: "MainItem", bundle: nil).instantiate(withOwner: nil, options: nil).first as! UIView
return view
}
}
stackView.addArrangedSubview(MainItem.instanceFromNib())
and I'm adding it to a UIStackView which already has some views like UILabel or UIScrollView. but the added view is not showing when I'm running the app and here is the result
what is the problem?
One possible reason is that you did not specify the height of the view, so the height of it becomes to 0 during the rendering process. There are two ways to do it:
Set the alignment of you stackView to .fillEqually. You can do this because the label has non 0 intrinsic heigh.
stackView.distribution = .fillEqually
Tell iOS how to calculate the height of your view. For example override intrinsicContentSize of your view

Programmatically adding views to Vertical Stack View breaks constraints of vertical stack view

So I have a vertical stack view in a simple layout. When I add a view through Interface Builder I see the view in the stack view no issues.
When I then add views programmatically to the UIStackView it breaks the constraints and the added views appear at the top of the window. I'm confused as to why it would break the constraints of the stack view.
func buildCats(theJson:JSON){
//self.verticalStack.subviews.forEach({ $0.removeFromSuperview() })
print(theJson)
if let infos = self.swiftyJsonvar["info"].array{
for info in infos{
guard let v = UINib(nibName: "ticketOrderView", bundle: nil).instantiate(withOwner: nil, options: nil)[0] as? UIView else { return }
v.translatesAutoresizingMaskIntoConstraints = false
self.verticalStack.addArrangedSubview(v)
}
}
}
The added subviews need constraints, as they have no intrinsic size. Try:
v.heightAnchor.constraint(greaterThanOrEqualToConstant: 30).isActive = true
v.widthAnchor.constraint(greaterThanOrEqualToConstant: 200).isActive = true
Hmmm.... I'm doubting this now... I suspect the issue may be related to adding the views on a background thread. Maybe run the loop on the main thread?
Edit 2: Ah... the problem I'm betting now is related to what you're doing with the view / subviews inside your "ticketOrderView"
For an example, see: https://github.com/DonMag/ScratchPad

loading a custom UIView from a nib either causes an infinite loop or throws a nil exception

I have created a custom view (ImageAndToolBarContainerView) with a corresponding XIB file that I would like to load into multiple UIViewControllers in my app.
I have been hunting for a proper tutorial of how to do this, but almost every one I've come across either is too old or causes major exceptions.
When I try loading it through the story board / NIB, (I create a view in the UIViewController on the storyboard and I set the "Class" attribute to ImageAndToolBarContainerView. I Set the outlets, including the View, but none of them seem to load when the class is called, and I get the error :
fatal error: unexpectedly found nil while unwrapping an Optional value
when I try to access the view:
required init?(coder aDecoder: NSCoder)
{
super.init(coder: aDecoder)
//setup()
self.view.frame = self.bounds
self.addSubview(view)
}
Then, I try using the following code to load the NIB instead (by uncommenting the setup() function above. The code of setup is this:
func setup()
{
self.loadViewFromNIB()
self.view.frame = self.bounds
self.addSubview(view)
}
func loadViewFromNIB() -> UIView
{
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: "ImageAndToolBarContainer", bundle: bundle)
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
return view
}
That of course leads to an infinite loop.
I also have the following function declares:
override func awakeFromNib()
{
super.awakeFromNib()
self.view.frame = self.bounds
self.addSubview(view)
}
What am I missing here? Where did I go wrong? Is there a definitive tutorial in how to do this properly?
The infinite loop is probably caused because you set the File's Owner and also subclassed the View's class to your View's class name.
For anyone having this issue, if you register a Nib for a table or collection view, you are telling that parent view to go and load a nib named 'x' whenever it needs to dequeue a cell.
Normally with Nib code, you'll want a method to go and load the actual XML that makes your layout to tie it to the Nib class, but when you register a reusable view, your registration means that the parent view is responsible for doing this. It will literally go and load an XML file for you and try and tie that to a class when you cast it. By adding another loadViewFromNIB call inside of this will then cause an infinite loop to happen.
All you need to do is set the cell Nib's class to your custom class, register it and it will do the rest for you with reusable cells - remove the loadViewFromNIB method from any initialisers inside your cell and add registration code on the collection or table view class.

Howto Size the Modal View programmatically (SWIFT)

I simply want to present a small option dialog over an existing main UIViewController/UIView , so that on an IPad I would see a small Dialog and in the Background I will see the Main View.
I managed to show a UIViewController/UIView in a modal view style as follow:
func showoptions(){
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let controller = storyboard.instantiateViewControllerWithIdentifier("Options") as! UIViewController
controller.modalPresentationStyle = UIModalPresentationStyle.Popover
let popoverPresentationController = controller.popoverPresentationController
// result is an optional (but should not be nil if modalPresentationStyle is popover)
if let _popoverPresentationController = popoverPresentationController {
// set the view from which to pop up
_popoverPresentationController.sourceView = self.view;
//_popoverPresentationController.sourceRect = CGRectMake(60, 100, 500, 500)
//_popoverPresentationController. .setPopoverContentSize(CGSizeMake(550, 600), animated: true)
//_popoverPresentationController.sourceView.sizeToFit();
// present (id iPhone it is a modal automatic full screen)
self.presentViewController(controller, animated: true, completion: nil)
}
}
But I have still some issues:
1. Howto get rid of the arrow shown at the border.
2. Howto size this modal view. It is shown to small and I would like to fit it to the largest controls in the UIControllerView/UIView.
any help ?
Try changing _popoverPresentationController.permittedArrowDirections to empty option set
Change controller.preferredContentSize to match your desired size
I needed something similar and ended up presenting a view controller as a modal with a transparent background over the current context. There I made a smaller opaque UIView with what I wanted.

Present viewcontroller from appdelegate over the current view in swift

I am trying to present a view programmatically from the appdelegate. The basic idea it's to present a view so that the user must enter a code to unlock the app. This code works
func applicationWillResignActive(application: UIApplication) {
var storyboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
var vc : PasswordViewController = storyboard.instantiateViewControllerWithIdentifier("PasswordViewController") as PasswordViewController
let navigationController = UINavigationController(rootViewController: vc)
self.window?.rootViewController?.presentViewController(navigationController, animated: true, completion: nil)
}
But have a problem. If the user press home inside another view (like the one shown on the picture) the password viewcontroller does not shows and I get a warning
Warning: Attempt to present UINavigationController: 0x7f8c2263c480 on UITabBarController: 0x7f8c2256ad60 whose view is not in the window hierarchy!
left view presents ok the view, right one not, note that right one is accessed with the + button and it's modal
Any help will be much welcome!
I wrote an app that did something like this - upon resuming the application the user would be prompted for a PIN or return to the login screen.
I think the trick for this is not to try to present a viewController modally - I just overlaid the entire window with a UIView that intercepts all touches and blocks everything behind it.
Ordinarily I just program every subview into a UIView manually. For example:
class PasswordView:UIView{
override init(frame: CGRect) {
super.init(frame: frame)
var disabler = UIView(frame: frame)
disabler.backgroundColor = UIColor(white: 1.0, alpha: 0.2)
self.addSubview(disabler)
var redBar = UIView(frame: CGRectMake(0,22,frame.width,44))
redBar.backgroundColor = UIColor.redColor()
self.addSubview(redBar)
//etc... and add other elements using code
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
This is my preferred means to manage all my views because I maintain the most amount of control, but you might also look into loading from an .xib
At any rate... in my app I created this view in this manner:
var passCode = PasswordView(frame: GCRectZero)
func applicationDidBecomeActive(application: UIApplication) {
passCode.removeFromSuperview()
passCode = PasswordView(frame: self.window!.bounds)
self.window!.addSubview(passCode)
}
I would recommend you give the appDelegate a dedicated var passCode = PasswordView(frame: GCRectZero) so that you can remove it from the superview before adding another. This way you don't stack up a ton of views.