After some research I found out (thanks to the following post) that in iOS 16 UITextView use Text Kit 2.
Unfortunately the new implementation has the issue described above, but it's possibile to force an UITextView to fallback to Text Kit 1 by accessing the layoutManager property (thanks to winshy for this solution).
So, in order to fix the issue you just need to add the following line:
_ = textView.layoutManager
The full code of the original example will become:
class ViewController: UIViewController {
@IBOutlet weak var textView: UITextView! {
didSet {
_ = textView.layoutManager
var attributes = [NSAttributedString.Key: Any]()
let paragraphStyle: NSMutableParagraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 50
attributes[NSAttributedString.Key.paragraphStyle] = paragraphStyle
attributes[NSAttributedString.Key.font] = UIFont.preferredFont(forTextStyle: .body)
textView.typingAttributes = attributes
}
}
}
Post
Replies
Boosts
Views
Activity
Just want to add some new information.
I'm using the same exact code on two different apps and on the same device.
With the exact same search term in one app I successfully receive an MKLocalSearch.Response but in the other one I receive an MKError.placemarkNotFound error.
Why the same code, on the same device with the same search term but on different apps give a different result?
The only notable difference between the apps is that the one that give the error is targeting iOS 15.
The one that works is targeting iOS 13.
Please also note that I receive the error only for some particular search terms.
These particular search terms always fails.
Other search terms successufly return a valid MKLocalSearch.Response.
I receive the error on both physical device and simulator.
Someone on Stack Overflow advised me to use a lazy var. It works great!
lazy var doSomething: Bool = {
#if targetEnvironment(macCatalyst)
return true
#else
return false
#endif
}()
if doSomething {
print("Execute!")
}
Thank you for the answer.
I’m developing a CoreData application that allow the user to store data and pictures. The app is doing some local backups of the CoreData store. Since pictures can make the store very large I just backup the data of the store without the pictures (I keep only the assetIdentifier).
If for some reason the user need to restore the data from a backup, the app will try to look for the original pictures in the user library using the asset identifiers. This is working fine if the user is restoring the data on the same device, but if the backup is restored on another device the local identifiers become useless.
The idea was to also store the cloud identifier so that the restore procedure has a chance to find the original pictures also on a different device.
Now, I really don’t want to ask user to grant library access during the normal use of the app. Access will be requested only in the rare case that a restore is required.
Personally, I would love to receive the cloud identifier directly inside the PHPickerResult like the assetIdentifier.
What do you think about it?
Frameworks Engineer's answer put me on the right track to find a fix.
The problem actually appears to be the value returned by layoutMargins.
On an iPhone 12 and on an iPhone 8 the distance between the edge of the device and the large title is the same (16px).
The problem is that the value returned by layoutMargins.left is different on the two devices.
On the iPhone 8 is 16px (the correct value to align the cells with the title) while on the iPhone 12 is 20px (4 pixels too much, causing the misalignment).
I tried to manually set the layoutMargins property and discovered that for some reason if you set the layoutMargins to zero then the issue disappears.
After settings layoutMargins to zero then layoutMargins.left will return 16px on both devices, making a perfect alignment.
override func viewDidLoad() {
super.viewDidLoad()
tableView.layoutMargins = .zero
}
Please note that this problem seems to exist only on iPhones with the notch (iPhone 12, iPhone 13).
On iPads and for example on iPhone 8 the problem is not there.
Thank you Frameworks Engineer for the clarification. Just one last question for you if I can.
Diffable data source with fetched result controller is using NSManagedObjectID's to check which items need to be added / removed / updated.
When we are creating a new entitiy, for example:
let newEntry = Entry(context: managedObjectContext)
the object has a temporary id's until the store is saved.
If we create a new object, we save the store and then we create another object (and we save the store) the diffable data source will see the new created item BUT also an edit on the previous object (because the NSManagedObjectID after the save has been transformed to permanent). This is causing weird animations on a table view controller (insert + update animation instead of just an insert animation).
Please note that this behaviour is only present if you save the store right after you created the new entity.
The only way I found to fix this is to call obtainPermanentIDs right after I created the new Core Data object, like so:
let newEntry = Entry(context: managedObjectContext)
try? managedObjectContext.obtainPermanentIDs(for: [newEntry])
try? managedObjectContext.save()
This is forcing Core Data to set the permanent id on the just created object.
Is this the correct thing to do?
When using diffable data sources in combination with a fetched result controller we always need to manually call obtainPermanentIDs after creating a new entity?
Thank you
Thank you for the answer andyl_. This are bad news for anyone want to develop an app with a global white tint. At this point, unfortunately, I think the only way is to revert to the old wheels type. That’s sad, I really love the new date picker style.
Did someone found an alternative way to fix this issue?
In this case is all good because if you select a day that is not today then the badge background color is dark gray, not white.
Yes, with a non white tint color the problem does not appear. The problem is only when the tint color is white and dark mode is enabled. The today badge background color becomes the same as the text color making it unreadable.
I'm starting to have this problem too with some users of my app.
As in the case of reported by cybergen, users told me that the app remains stuck forever on the launch screen (the main storyboard is never displayed) and the entire operating system becomes difficult to use, as if the app were taking over the entire cpu. Things like displaying control center or go to home become very difficult to perform. The app is never killed by iOS and stay on the launch screen forever.
Unfortunately I cannot debug this situation because I'm unable to reproduce this issue.
cybergen, did you find out what the problem was?
Thank you
Happy to report this issue has been fixed on iOS 15 beta 3.
I tried to add a gif and also a zip file but it seems that we are not allowed to add this kind of files (they are grayed out and you cannot selected them).
Please note that this is causing issues also if you have a controller with a large title and you push a controller that does not have a large title (navigationItem.largeTitleDisplayMode = .never).
In this case, during the transition, the top part of the pushed controller view is covered by the background color of the large navigation bar. When the transition ends, the top part suddenly become visible again (see below image).
I think that the problem is that during the transition the navigation bar height is not animated between the two states (the large title height and the compact height). On iOS 13 and iOS 14 there is a smooth animation between the two heights.
I filled the bug report number FB9290717 and included a sample project that show this issue.
Seems that this issue is only present when using a NavigationLink inside a navigation bar.
If we use a NavigationLink that's inside the body then everything work correctly.
In my case I need to have the button inside the navigation bar so I created an hidden NavigationLink in the body which will be activated by a button located in the navigation bar.
This works:
struct FirstView: View {
		var body: some View {
				NavigationView {
						Text("First view")
								.navigationBarTitle(Text("First view"), displayMode: .inline)
								.navigationBarItems(trailing:
										NavigationLink("To second", destination: SecondView())
								)
				}
		}
}
struct SecondView: View {
		@State var isNavigationLinkActive = false
		var body: some View {
				VStack {
						Text("Second view")
						NavigationLink("To third", destination: ThirdView(), isActive: $isNavigationLinkActive)
								.hidden()
				}
				.navigationBarTitle(Text("Second view"), displayMode: .inline)
				.navigationBarItems(trailing:
						Button("To third", action: {
								isNavigationLinkActive = true
						})
				)
		}
}
struct ThirdView: View {
		@State var isNavigationLinkActive = false
		var body: some View {
				VStack {
						Text("Third view")
						NavigationLink("To fourth", destination: FourthView(), isActive: $isNavigationLinkActive)
								.hidden()
				}
				.navigationBarTitle(Text("Third view"), displayMode: .inline)
				.navigationBarItems(trailing:
						Button("To fourth", action: {
								isNavigationLinkActive = true
						})
				)
		}
}
struct FourthView: View {
		var body: some View {
				Text("Fourth view")
						.navigationBarTitle(Text("Fourth view"), displayMode: .inline)
		}
}