Swift UISplitViewController MasterViewController set width not working - ios

I'm working on an app to have a split view and so far it's working fine, but it's not possible to set the width of the master controller using preferredPrimaryColumnWidthFraction. Another screen in the app already contains a split view and there it's working fine to set the width using the preferredPrimaryColumnWidthFraction (this screen has been built some time back) and when comparing both screens I can't find any difference in the storyboards that would explain this behaviour.
The basic setup in the storyboard is the following:
The controller in the top right is the HelpMenuController:
import Foundation
class HelpMenuController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.splitViewController?.preferredPrimaryColumnWidthFraction = 0.3
}
...
}
For the other screen, the call to set the preferredPrimaryColumnWidthFraction happens as well in the viewDidLoad method of the corresponding MasterViewController. Everything seems to be identical, yet for one split view it's working, for the other split view it isn't.
I also tested it by using a customized UISplitViewController and set the preferredPrimaryColumnWidthFraction in it's viewDidLoad method, but this approach didn't work.
Running out of ideas what could cause this issue - did anyone also experience this issue or has an idea about it?
Albert Einstein:
The definition of insanity is doing the same thing over and over and expecting different results.
Sometimes I have the impression for software development it's the other way around: Insanity is doing the same thing over and over again and expecting the same results.
Or in other words: Same same but different.

Okay, so after reading the documentation about UISplitViewController again, I found a solution:
class HelpMenuController : UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.splitViewController?.preferredPrimaryColumnWidthFraction= 0.3
self.splitViewController?.maximumPrimaryColumnWidth = 0.3 * UIScreen.main.bounds.width
}
...
}
For a yet unknown reason to me, the maximum width had to be increased to the desired value for this screen and for the other screen this had not to be done.

Related

Is this a good way to layout my view controllers

People usually get real frame size in viewDidAppear() or viewDidLayoutSubviews() to calculate their views, however I usually got problems with these approaches.
I want my views to be already calculated before they appear on the screen so viewDidAppear() is not suitable, viewWillAppear() sometimes it works sometimes it doesn't. viewDidLayoutSubviews() is called many times so it's not a good choice either.
So below is my way to handle it, I always get the desired results with this approach. Are there any disadvantages with this?
override func viewDidLoad() {
super.viewDidLoad()
self.view.frame = UIScreen.main.bounds
self.view.layoutIfNeeded()
// put everything needs to be calculated here
}
You shouldn't need to lay out your views that way.
The modern Apple recommendation is to avoid making manual changes to frame.
layoutIfNeeded
From document : Lays out the subviews immediately, if layout updates are pending.
This is a synchronous call that tells the system you want a layout and redraw of a view and its subviews, and you want it done immediately without waiting for the update cycle.
https://developer.apple.com/documentation/uikit/uiview/1622507-layoutifneeded
You should also check this WWDC video this year
https://developer.apple.com/videos/play/wwdc2018/220/
Put your code to viewLayoutSubViews dwlwgate method.

Using 2 view controllers in Swift as a way of producing a larger screen area

I'm developing an iOS app which is just for debugging some other work I'm involved in. I've ran out of space on the first view controller (lots of buttons and images) and want to expand into a second view controller. I'm implemented a segue between the views and use the following code in the second viewcontroller to trigger functions in the first view controller:
#IBAction func imagePreset_1_clicked(_ sender: Any) {
firstViewController().functionX()
}
This works but if functionX has the following code:
DispatchQueue.main.async { () -> Void in
self.source.text = "hello"
}
which is a label on firstViewController, then I get the following error:
fatal error: unexpectedly found nil while unwrapping an Optional value
I'm new to Swift. Am I correctly creating a reference to the firstViewController or am I creating a new instance of it? It the problem that the label being updated is not in "scope"?
All I want is extra space for icons. Is there a better way to achieve this?
Thanks
update
So I've tried a scrolling view and this works but can anyone advise how to do what I'm trying to achieve with a second view controller accessing the functions in the first view controller? I think that's a nicer ux experience. Is it any easier using a tab bar?
Have you considered using a single ViewController with scrollable view inside ?
Using this, you'll be able to display as many content as you'd like :)

Swift - A strange UIView instant covering over the whole top most ViewController

I just updated my Xcode to 8.2.1 and migrated my swift codes from 2.2 to 3.0.
After that, I ran into a situation that my top-most view controller was covered by a view (for more detail, please click to see the screenshot of Xcode debug hierarchy view), which never appeared when swift 2.2 was used. The top most VC is a DrawerController from https://cocoapods.org/pods/DrawerController, and is updated to the last version.
Because every touch event was received by the strange view, my app can't
work normally.
Is there any potential reason to make the view there?
Or is there any way to find out where the view come from?
If more information is needed, please let me know.
Thank you in advance.
For lack of reputation, I can't comment.
Have you ever tried to delete this "strange view"? Or just move it on top the UIView that contains your drawer?
I resolved this problem.
In my original codes, I subclassed DrawerController (say, MyDrawerController) and assigned the property centerViewController (the main page shown to the user in DrawerController) in the overrided viewDidLoad() in MyDrawerController. As a result, I ran into the trouble as described in my question above.
What I do to resolve the problem is make a main queue and move the codes which assigning the property centerViewController to the block of the main queue. (Codes of "BEFORE" and "AFTER" like bellow.)
Then, the problem was solved.
Don't know why the "BEFORE" codes worked fine in Swift 2.2 but failed in Swift 3.3. Could anyone tell the difference?
Thanks for your helping.
BEFORE:
class MyDrawerController: DrawerController {
override func viewDidLoad() {
self.centerViewController = aViewControllerInstant
}
}
AFTER:
class MyDrawerController: DrawerController {
override func viewDidLoad() {
DispatchQueue.main.async {
self.centerViewController = aViewControllerInstant
}
}
}

MKMapView using a lot of memory each time i load its view

I have a pretty simple app, with a couple of view controllers. There is a MKMapView in the second view controller. It is set up correctly, and functions fine. The problem is, each time I load its view the Memory usage jumps ~30mb, and never goes back down, so each time i go into the view it keeps jumping and eventually gets super high.
I tried removing the map view when i leave the controller like this:
override func viewWillDisappear(animated: Bool) {
map.removeFromSuperview()
}
but it doesn't have any effect on the memory. The map views delegate is set to its view controller.
I tried checking for leaks using Xcode instruments but didn't find anything.
Does anyone know how to fix this?
Thanks
EDIT:
Adding this seems to work:
func removeNastyMapMemory() {
map.mapType = MKMapType.Hybrid
map.delegate = nil
map.removeFromSuperview()
map = nil
}
override func viewWillDisappear(animated: Bool) {
removeNastyMapMemory()
}
This is not Swift issue, is coming from Objective-C days. The possible ways to handle this issue is depending upon the situation and behavior of the app.
If you're using a Map for multiple times (or places), only create a single (shared) instance of it. Which you can use it whenever you want.
Or If you're only using it for once, then try a solution from here, https://stackoverflow.com/a/25419783/1603234. This may help. Reduce little. But not all.

when to use viewDidLoad

I am new to both iOS development and programming in general. I need some clarification as to what sort of things should be declared in the viewDidLoad function of a UIViewController subclass
Thanks
In order to properly understand what viewDidLoad does, you should understand the View Controller Lifecycle. The best point to start is reading the Apple Documentation, e.g. the learning guides for developing iOS Apps: https://developer.apple.com/library/prerelease/ios/referencelibrary/GettingStarted/DevelopiOSAppsSwift/Lesson4.html
Declare elements that don't need to be refreshed or recreated when the view reloads. For instance, viewDidLoad is called only when it is created while viewDidAppear will be called every time the view is shown.
Read up on some apple docs.
Everything you write inside the viewDidLoad function will run the the View(which can be TableView, ViewController & more..) is loaded.
For example, if you got a label called 'label' and you want to set it's by the code so you type:
override func viewDidLoad() {
super.viewDidLoad()
label.text = String("any text here")
}
and then the text of the label will change when the View will load.

Resources