App crashes strangely regarding MKMapView memory issues - ios

I've been developing an app which was working perfectly fine until I added an MKMapView. If I navigate in the map for a broader area, dismiss the view controller with the map and add a new view controller, the app will crash with Xcode saying "Lost connection to iPhone".
I have searched online and I found it should be a memory issue. So I have used a lot of ways to clean the memory of MKMapView, including only storing one instance of the MKMapView in AppDelegate and cleaning it after ViewDidDisappear like this:
if let annotations = self.mapView?.annotations {
self.mapView?.removeAnnotations(annotations)
}
if self.mapView?.mapType == MKMapType.standard {
self.mapView?.mapType = MKMapType.hybrid
} else if self.mapView?.mapType == MKMapType.hybrid {
self.mapView?.mapType = MKMapType.standard
}
self.mapView?.delegate = nil
self.mapView?.removeFromSuperview()
self.mapView = nil
Even more strange is that when I was tracking the memory usage, while in the map, the memory usage can go up to 300+mb and it seems to clean itself while exploring more. However, there will be around 200mb left after I dismiss that view controller and when I'm adding another simple VC with just one UIIMageView, it crashes with the "Lost Connection" thing.
I'm new to memory management but I do have a screenshot here for instrument profile:
Just like here in the image. Generation A is the point where I presented the view controller with the MKMapView and Generation B is the point where I dismissed that view. The memory usage was apparently dropping, which is good. But as soon as I click on presenting a different view controller, it disconnects just like in Xcode.
I have done a lot of research on this and I really don't know what to do at this point. Thanks if you guys can help me out here!!!!

Problem fixed after I switched to Google Map...

Related

How to fix/debug a VoiceOver bug?

What's my problem with the VO?
It gets stuck. It focuses only on the status bar (so it doesn't see the app at all) or it focuses temporarily on a header bar in the app (so I can change the focus between about 3 element in that field). Neither switching the VO off and on nor standard gestures can help a user in such a situation.
When exactly does it happen?
The app is quite big so the exact reason is hard to determine. That's why I want to know how you would debug it. But generally the app has login screens and inside screens. When the app starts and immediately goes to one of inside screens, the VO works perfectly. When the app starts and goes through login screens, the VO gets stuck after logging in.
Any code?
To change between the login screens and the inside screens I use UIApplicationDelegate
let storyboard = UIStoryboard(name: "StoryboardName", bundle: nil)
let vc: WantedViewController = storyboard.instantiateViewController(withIdentifier: "WantedViewControllerId") as! WantedViewController
self.window?.rootViewController = vc
self.window?.makeKeyAndVisible()
Maybe it's too big change for the VO. The app uses also JGProgressHUD but I think I checked quite well that it couldn't be a reason.
Any suggestions and questions are welcome!
If you are using native UIKit widgets, then accessibility should be built in and Voiceover should find the widget. If you have a custom widget, you'll need to set isAccessibilityElement.
The presented code caused the issue indeed. I advise people with a similar problem to perform sergue instead:
performSegue(withIdentifier: "SegueToWantedViewControllerId", sender: nil)
Define it in storyboard for example with Kind as Present Modally and Presentation as Full Screen to get the same result but with VoiceOver working.

Crash when instantiating ARSCNView for the second time

I have a problem in my iPhone app when trying to instantiate an ARSCNView again, after destroying it.
In my ViewController I programmatically create an ARSCNView for motion capture interaction:
func addARSceneView() {
arSceneView = ARSCNView(frame: self.view.frame)
arSceneView.loops = true
arSceneView.session.delegate = self
self.view.addSubview(arSceneView)
arSceneView.session.run(ARBodyTrackingConfiguration())
}
When the user leaves this part of the app, I tear it down like this:
func removeARSceneView() {
arSceneView.session.pause()
arSceneView.pause(self)
arSceneView.session.delegate = nil
arSceneView.removeFromSuperview()
arSceneView = nil
}
Later, when I try to instantiate an ARSCNView for the second time using the first function above, it crashes with an EXC_BAD_ACCESS in the constructor:
I also tried to use a view from a xib which contains an ARSCNView but the same problem occurs, in that case in the init(coder) function of that view.
I found nothing on this problem, I guess usually developers only create an ARSCNView once.
TLDR: Turn "Metal API Validation" on in your scheme.
I found the culprit, after creating a sample project with only the ARSCNView, which did not have this problem. I started by stripping everything away from my original project until it was as barebones as the sample. That did not solve it, so I compared every little setting of the two, and behold: in the "Run" scheme of the original project, under "Diagnostics", I had "Metal – API Validation" ticked off. I don't remember when and why I did that; I assume it was some attempt to improve performance at one point. However, enabling this checkbox solved the problem completely.

How to minimise(Memory leak) the app memory in ARKit Scene Click on back button?

How to minimize the app memory consumption in ARKit Scene after clicking on the back button?
Because every time when I open an ARview in my App, the memory usage is increasing.
When I go back then it does not free the memory and after opening an ARview again, the memory usages increases even further.
class ARViewController: UIViewController, ARSCNViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
setupScene()
setupFocusSquare()
}
func setupScene() {
sceneView.delegate = self
sceneView.session = session
sceneView.antialiasingMode = .multisampling4X
sceneView.automaticallyUpdatesLighting = false
sceneView.preferredFramesPerSecond = 60
sceneView.contentScaleFactor = 1.3
enableEnvironmentMapWithIntensity(25.0)
if let camera = sceneView.pointOfView?.camera {
camera.wantsHDR = true
camera.wantsExposureAdaptation = true
camera.exposureOffset = -1
camera.minimumExposure = -1
camera.maximumExposure = 3
}
}
func setupFocusSquare() {
focusSquare?.isHidden = true
focusSquare?.removeFromParentNode()
focusSquare = FocusSquare()
sceneView.scene.rootNode.addChildNode(focusSquare!)
textManager.scheduleMessage("TRY MOVING LEFT OR RIGHT", inSeconds: 5.0, messageType: .focusSquare)
}
}
The attached source code is not enough to answer how exactly resolve memory leak. I will describe steps how to detect leaks. So, you can add such information to question or maybe resolve an issue by yourself.
Xcode has several instrument to detect memory leaks:
Debug Memory Graph. Launch the app in debug mode. Navigate to the screen and back several times so memory growth. Then tap "Debug Memory Graph" button at debug toolbar.
So, you will see current memory graph of your app. Try to detect some anomaly at left bar:
Maybe you will see few View Controllers or Scene Views. Try to understand what retain this objects and use weak attribute if needed.
Use instruments by click Product -> Profile:
2.1. Select Leaks instrument:
Run the app by tap Record button (red circle) and make several navigations to screen with issue and back. At the bottom you will see some leaks if any. Sort them by size and make attention at Responsible Library. There should be your app name.
If you find something interesting you can select the row and see responsible stack trace.
2.2 Use Allocations instrument:
Run the app by tap Record button (red circle). Navigate to the screen with issue and tap back once. Then click Mark Generation button:
Navigate to the screen with issue and back once more. And click "Mark Generation" once more. Repeat this steps once more and you should see three generations at the bottom:
So you will see which objects are stay alive between back and forward. You can expand for example Generation B and see which object is retained. By click to some row your will see responsible code.
Depending on results at previous steps you may understand where problem is and add some code to resolve retain cycle or unnecessary retain of some object.

Buttons in iOS app don't respond to touches around the edge of the screen

I'm relatively new to iOS development, but I'm having a go at working on some open source code for an old game that used to be pretty popular (Eden World Builder)
I've made quite a lot of progress in cleaning up the codebase, making small changes. But there's an issue I can't seem to fix. Every button in the game will not respond to taps around the edges of the screen. If a button is in the corner of the screen, you will have to tap towards the bottom of the button.
I've tried to move the buttons away from the edges, and they work, but that isn't practical for use. So there's something preventing the edges of the screen from registering button taps for some reason, and it doesn't seem to be anything to do with the button target areas themselves.
One thing I've noticed: This game is currently on the App Store, even though it hasn't been updated since 2015. In the App Store version (Which is built from the same code that I have) the issue doesn't occur. It must be something to do with building it in a newer version of Xcode, right?
Any assistance would be very helpful, this has been frustrating me for weeks now. Thanks
The answer to your first question is most likely either that your button is outside its parent view, or a gesture recognizer is interfering.
If a button extends beyond its parent views boundaries (or any of its higher parents' boundaries), it will still be visible as long as the parent doesn't have clipping enabled. The result is that you will still see the button, but it will only respond when touching the parts that are inside the parent view. You can find this visually by using Xcode View UI Hierarchy found in the Debug Navigator.
If it is gesture recognizers that interfere with your button, there are several solutions that might work. Several are described in the link you got from #Anbu in the comment.
The answer to your second question is that old apps are linked against old frameworks. Even if they run on the latest iOS version, they still pull in older versions of the framework, causing them to (mostly) continue work as before. This is done to keep compatibility with legacy code.
Try adding this to viewDidAppear
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if let window = view.window,
let recognizers = window.gestureRecognizers {
recognizers.forEach { r in
r.delaysTouchesBegan = false
r.cancelsTouchesInView = false
r.isEnabled = false
}
}
}

Today Widget uses more memory each time it refreshes, then eventually crashes

I’m working on a Today Widget, and running into memory issues.
When I run the widget and monitor memory usage Xcode, the widget uses about 15MB when it first starts up. Then, when I swipe away from the widget screen and back, it goes up to about 16MB.
Every time I swipe away and back it memory usage goes up by about 0.5–1.5MB. As I do it more I get memory warnings (didReceiveMemoryWarning() is called) and eventually, with more swiping, the widget crashes.
All these symptoms are happening while testing on an iPhone X. On the simulator, the widget starts off using around 50 megabytes, which seems kind of odd, but it has the same behavior where memory usage goes up each time I swipe away and swipe back.
I've tried analyzing this with Instruments, but I'm only able to get Instruments to show what happens at the beginning (when I first launch the Widget) and it doesn't keep running as I swipe away and back.
Through the process of elimination (commenting out the actual functionality of my widget) the issue still happens when just the UI code remains. This makes me think it’s a problem with my UI approach.
I’ve built Today Widgets in the past, but always used Interface Builder. This time I decided to build the interface programmatically instead. I don’t see this same behavior of increasing memory usage with each refresh when I look at other Today Widgets I’ve built with Interface Builder.
First, I set up all my UI elements as private lazy variables, like this:
private lazy var mainStackView: UIStackView = {
let stackView = UIStackView()
stackView.distribution = .fillEqually
stackView.translatesAutoresizingMaskIntoConstraints = false
return stackView
}()
Then, in viewDidLoad(), I add my views to the TodayViewController's view with some constraints, like this:
view.addSubview(mainStackView)
let stackViewLeadingConstraint = mainStackView.leadingAnchor.constraintEqualToSystemSpacingAfter(view.leadingAnchor, multiplier: 1)
let stackViewTopConstraint = mainStackView.topAnchor.constraintEqualToSystemSpacingBelow(view.topAnchor, multiplier: 1)
let stackViewTrailingConstraint = view.trailingAnchor.constraintEqualToSystemSpacingAfter(mainStackView.trailingAnchor, multiplier: 1)
let stackViewBottomConstraint = view.bottomAnchor.constraintEqualToSystemSpacingBelow(mainStackView.bottomAnchor, multiplier: 1)
view.addConstraints([stackViewLeadingConstraint, stackViewTopConstraint, stackViewTrailingConstraint, stackViewBottomConstraint])
Since I'm new to building UI programmatically, is there anything with this approach that seems blatantly incorrect and looks like it could cause a memory leak?
I've even tried commenting out all of my code and running it with a basic blank UIViewController, where the view lifecycle functions don't even do anything, and I still experience the memory leak. That makes me think there's something I should be doing when I build the interface programmatically that I'm not doing.
It seems like something's not being released and being duplicated in memory each time the Today Widget appears. I'd appreciate any suggestions for how I could find what's not being released and force the system to release it. Thanks!
SOLVED
Thanks to the troubleshooting tip provided by Christopher Pickslay, I was able to track down the issue. It turned out to be my fault. To troubleshoot a previous unrelated issue, I had turned on the Zombie Objects in the scheme, and I still had it enabled. Once I turned that off the issue went away. This is the setting I'm talking about:
I don't see any problem with how you're building the UI (from what you've shared so far). Instead of Instruments, try using the Memory Graph Debugger to find your leak.
It will pause the debugger and you can use the top bar to browse through all the alocations and what points to each instance. Open the memory graph debugger, look at your graph, then un-pause and scroll the extension off and back on screen a few times, and open the memory graph debugger again. That should give you a better idea what's leaking and what's holding on to it.

Resources