I was stumbeling upon a retain cycle in UIKit frequently since the introduction of iOS 13 and I cannot explain myself why this is creating a retain cycleclass TestVC: UIViewController, UIAdaptivePresentationControllerDelegate {
deinit {
print("No leak")
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .red
presentationController?.delegate = self
}
func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
print("dismiss")
}
}
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIViewController()
self.window = window
window.makeKeyAndVisible()
let nav = UINavigationController(rootViewController: TestVC())
window.rootViewController?.present(nav, animated: true)
}
}
}First, the presentationController delegate is never called. Secondly, the VC is never deallocated when swiping it away. When using tthe memory debugger I see the NavigationController still holden a strong reference to the TestVC. How is this creating a retain cycle when the presentationController.delegate is a weak var?So far the only work around I have found was checking if there is a parent view controller in viewWillAppear and not set the presentationController.delegate in that case.
Post
Replies
Boosts
Views
Activity
While trying to build our project with Xcode 12 I ran into multiple build failures while rebuilding our dependencies with Carthage.
I always end up getting this linker error:
Undefined symbols for architecture armv7: "type metadata for Swift.StringObject.Variant", referenced from: outlined init with take of Swift.StringObject.Variant in CountryCodePickerViewController.o ld: symbol(s) not found for architecture armv7 This happened for me for both Alamofire and PhonenumerKit; therefore, this looks like an issue with the new Xcode and not the frameworks themselves. Archiving them with Xcode 11 works without a problem.
As an intermediate workaround I removed the armv7 architecture from the valid architectures.
When using UICollectionViewCompositionalLayout and creating a layout that supports pinned supplementary items and additionally having a section that has orthogonalScrollingBehavior the pinned header will disappear as soon as you scroll over the section with the orthogonalScrollingBehavior. A simple layout that demonstrates how it breaks looks like this
func createLayout() -> UICollectionViewLayout {
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .fractionalHeight(1.0))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .absolute(44))
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
let section = NSCollectionLayoutSection(group: group)
section.interGroupSpacing = 5
section.orthogonalScrollingBehavior = .continuous
section.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10)
let sectionHeader = NSCollectionLayoutBoundarySupplementaryItem(
layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .estimated(44)),
elementKind: PinnedSectionHeaderFooterViewController.sectionHeaderElementKind,
alignment: .top)
let sectionFooter = NSCollectionLayoutBoundarySupplementaryItem(
layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .estimated(44)),
elementKind: PinnedSectionHeaderFooterViewController.sectionFooterElementKind,
alignment: .bottom)
sectionHeader.pinToVisibleBounds = true
sectionHeader.zIndex = 2
section.boundarySupplementaryItems = [sectionHeader, sectionFooter]
let layout = UICollectionViewCompositionalLayout(section: section)
let layoutHeaderHeader = NSCollectionLayoutBoundarySupplementaryItem(
layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .estimated(44)),
elementKind: PinnedSectionHeaderFooterViewController.layoutHeaderElementKind,
alignment: .top)
let configuration = UICollectionViewCompositionalLayoutConfiguration()
layoutHeaderHeader.pinToVisibleBounds = true
configuration.boundarySupplementaryItems = [layoutHeaderHeader]
layout.configuration = configuration
return layout
}
This is an adapted part of the code provided by this example: https://developer.apple.com/documentation/uikit/views_and_controls/collection_views/implementing_modern_collection_views
After watching this years Demystifying SwiftUI session I revisited my project for usage of AnyView. A common pattern that I used was using AnyView at the screen boundary to allow dynamic routing.
Screen boundaries are for me new views that are modally presented or pushed in navigation stacks for example.
So a common pattern in my code base looks like this
class FooPresenter {
@Published var isPresenting = false
@Published var presentedView: AnyView
}
struct FooView {
@StateObject var presenter = FooPresenter()
var body: some View {
Text("hello")
.sheet(isPresented: $presenter.isPresenting) {
presenter.presentedView
}
}
}
Now I understand that SwiftUI uses the type system to diff views, animate and more. And I can fully understand that on a single screen it is advisable to use as few AnyViews as possible. However I am wondering is there a performance difference when using it across screen boundaries? Furthermore, is the SwiftUI system "resetting" its type data at AnyView and then can do it's normal diffing until the next AnyView. Something like this
RootView
Text
Button
SheetPresentation
AnyView
Text
Button