I have uploaded a full demo app here: https://github.com/Manc/GhostAnnotations
@robnotyou: Thanks for your feedback. I don't think I do anything unusual that could cause an issue. I try to keep things as minimal as possible. At the moment I don't to anything in prepareForReuse and I tried to unset the image, but it doesn't make a difference. It seems prepareForReuse is only called shortly before it is required, so as far as I understand it should not interfere with other annotation views.
Post
Replies
Boosts
Views
Activity
@robnotyou, thanks for taking a look, but unfortunately it didn't help. From what I can gather by looking at my print statements, the lifecycle of an annotation view goes a bit like this:
A new (in my example) image annotation is being added to the map.
mapView(_:viewFor:) is called, because the map wants a view for that annotation.
I know what kind of view that image annotation wants, so I call mapView.dequeueReusableAnnotationView(withIdentifier:for:).
Because this is the first time this kind of "image annotation view" is requested, a new instance will automatically be created and returned. I return this instance without further modification here.
Method prepareForDisplay of that "image annotation view" is being called, just before being displayed. Here, I set the view's properties, including the concrete UIImage.
Now the user removes all annotations from the map – mapView.removeAnnotations(…).
Nothing significant happens, except for the map removing the views, but apparently not properly clearing the collision frames (or whatever). Note: prepareForDisplay of the image views is not being called at this point, so setting the frame to .zero or anything else is not even possible, unless there is some other method that I don't know of that would be responsible for clearing up the map, but it would not make any sense that collision frames had to be cleared manually by the developer when annotations are being removed from the map.
Now the user adds marker annotations to the map.
mapView(_:viewFor:)
This time we return marker views after calling mapView.dequeueReusableAnnotationView(withIdentifier:for:).
Method prepareForDisplay of the marker views is being called.
Bug: Markers are displayed, but now they would falsely detect a collision at the screen positions where the image annotations were previously.
Only when the user switches back to image annotations, and we call mapView.dequeueReusableAnnotationView(withIdentifier:for:) to get those views, this time prepareForReuse() of the "image annotation views" will be called, so it's too late and resetting the frame to .zero has no effect, since we will indirectly set the frame to the same value again anyway, only in nanoseconds when prepareForDisplay is being called.
I think I found a workaround. I tried my best to solve this properly, but for now I assume that this is a bug in MapKit. I also assume that MKMarkerAnnotationViews get special treatment by MKMapView that enables them to auto-hide and do other things related to collisions (including clustering etc.), align marker titles etc.
My workaround (and it's only just that, not a clean solution) goes like this:
I use mapView(_ mapView:didAdd views:) to keep track of annotation views added to the map. Then, just before I call mapView.removeAnnotations(…), I iterate over all annotation views and set isHidden = true. This seems to be enough to remove collision frames from the map.
Similar situation here: When I first developed a sign-up form less than one week ago, auto-suggested passwords worked as expected. I even tried different password rules. Now, a few days later when I was ready to test my new app version, I realised that strong password suggestions no longer work and I'm getting the same message in the console.
[AutoFill] Cannot show Automatic Strong Passwords for app bundleID: … due to error: Cannot identify the calling app's process. Check teamID and bundleID in your app's application-identifier entitlement
Auto-filling on the login screen still works.
Same happens to me with a LazyVGrid, when I add and remove array items repeatedly (doesn't have to be fast), but only when using withAnimation. My use case is a "See All" / "Show Less" toggle.
In the button action:
withAnimation(.easeInOut(duration: 0.3)) { showAll.toggle() }
Without withAnimation I can toggle 100 times and still no crash.
Update: The issue exists also in the simulator. On the first run it updates the app icon in the simulator, but then, when I replace the icon image afterwards, it will keep displaying the old icon the the simulator. The only solution I found so far is to reset the simulator and run again.
Added thought: It may have to do with the auto-disappearing background and divider line in some circumstances like when scrolled to the bottom or, in case of a List view, the content fits into one screen without scrolling. This should not happen in my opinion. No other (Apple) app in iOS 15 has this behaviour.
I finally found out, this is a (unfortunately buggy) new "feature", which is enabled by default, can be disabled by manually calling UITabBar.appearance().scrollEdgeAppearance = UITabBarAppearance.init(idiom: .unspecified) before the TabView gets initialised.
Also, I'm unable to style the label text. Only .accentColor() can be set, but not custom fonts/sizes… Worked in iOS 14.
You must not use In-App Purchases for selling physical goods. Quote:
In-app purchase and Apple Pay are different technologies that support different use cases. Use in-app purchase to sell virtual goods in your app, such as premium content for your app and subscriptions for digital content. Use Apple Pay in your app to sell physical goods like groceries, clothing, and appliances; for services such as club memberships, hotel reservations, and event tickets; and for donations.
https://developer.apple.com/design/human-interface-guidelines/in-app-purchase/overview/introduction/
Personally, I don't think this would be a big issue, but it's best to read the guidelines (https://developer.apple.com/app-store/review/guidelines/), e.g. paragraph 1.1.4.