No need for the duplicate post. All you did was change the tag.
Marking this as a duplicate. Please don't clutter the forums.
Post
Replies
Boosts
Views
Activity
I'm not sure you should try to do this, for a couple of reasons. Look at some simple code that's written for iOS 17 and 18:
if #available(iOS 18, *) {
TabView(selection: $selectedTab) {
Tab("Watch Now", systemImage: "play", value: .watchNow) {
WatchNowView()
}
}
} else {
TabView(selection: $selectedTab) {
MenuView()
.tabItem {
Label("Menu", systemImage: "list.dash")
}
OrderView()
.tabItem {
Label("Order", systemImage: "square.and.pencil")
}
}
}
First reason: The iOS 18 format has a specific Tab object which has its own title and image in the Tab item itself, whereas iOS 17's tabItems force you to create a Label instead. That would be difficult to work around.
Second reason: Tab contains a View, whereas tabItem is a modifier on a View (just as .bold() is a modifier on a Text view). It's the opposite way round, making it difficult again.
It might be cleaner to simply do something like this, and you can remove the unnecessary code when you no longer support iOS 17:
if #available(iOS 18, *) {
MyTabs(selectedTab: $selectedTab)
} else {
MyTabs_iOS17(selectedTab: $selectedTab)
}
...
struct MyTabs: View {
@Binding var selectedTab: Tabs
var body: some View {
if #available(iOS 18, *) {
TabView(selection: $selectedTab) {
Tab("Watch Now", systemImage: "play", value: .watchNow) {
WatchNowView()
}
}
}
}
}
struct MyTabs_iOS17: View {
@Binding var selectedTab: Tabs
var body: some View {
TabView(selection: $selectedTab) {
MenuView()
.tabItem {
Label("Menu", systemImage: "list.dash")
}
OrderView()
.tabItem {
Label("Order", systemImage: "square.and.pencil")
}
}
}
}
There are ways to do this, but as I've mentioned, you'll be trying to fit A into B and C into D, and will have to write a chunk of code that makes that happen. It will likely be easier to bite the bullet and write the two separate sections.
Topic:
UI Frameworks
SubTopic:
SwiftUI
Tags:
No need for the second thread. You have an hour to edit your original post.
Anyway, is this an app you're developing? (I'm guessing not as that looks like the Santander logo.)
If it's not for an app you're developing then this is a consumer issue. These are the Developer Forums, where developers of apps for Apple's platforms ask each other for hints and tips on coding.
Your question is more of a product support one, so I'd suggest you ask it over at the Apple Support Forums. Thanks.
Topic:
App & System Services
SubTopic:
Widgets & Live Activities
Tags:
I've since moved onto Swift and SwiftUI, but when one of my apps was written in Objective-C this is what I used, and it worked every time. Perhaps it's because I'm using a UIImageView?:
- (void)applicationWillResignActive:(UIApplication *)app
{
NSLog(@"AD: applicationWillResignActive");
[self showBlurView:YES];
}
- (void)applicationWillEnterForeground:(UIApplication *)app
{
NSLog(@"AD: applicationWillEnterForeground");
[self showBlurView:NO];
}
- (void)applicationDidBecomeActive:(UIApplication *)app
{
NSLog(@"AD: applicationDidBecomeActive");
[self showBlurView:NO];
}
- (void)showBlurView:(BOOL)show
{
NSLog(@"AD: showBlurView: %@", show ? @"YES" : @"NO");
if(show) {
blurView = [[UIImageView alloc] initWithFrame:self.window.frame];
blurView.image = [UIImage imageNamed:@"blurViewImage"];
[self.window addSubview:blurView];
} else {
if(blurView != nil) {
[blurView removeFromSuperview];
}
}
}
Topic:
UI Frameworks
SubTopic:
UIKit
You've shown the time the cover view is added, but not the time it was removed.
How long did a user take between putting the app into the app switcher (or background), and bringing it back to active? How long between those NSLogs?
You're giving us piecemeal information here, making it difficult to help you.
Also, note that I added an else to where you're checking for a nil. That's important, because if coverView isn't nil at that time, then it's not going to create the view.
Add logging to every bit that's relevant.
Topic:
UI Frameworks
SubTopic:
UIKit
// Add the view to the window
-(void)applicationWillResignActive:(UIApplication *)application
{
NSLog(@"applicationWillResignActive"); // Confirm this method is being called
NSLog(@"[self.window frame] = %@", NSStringFromCGRext([self.window frame])); // Confirm the frame is valid
_coverView = [[UIView alloc]initWithFrame:[self.window frame]];
NSLog(@"applicationWillResignActive: Created view");
_coverView.backgroundColor =[UIColor blackColor];
[self.window addSubview:_coverView];
window.bringSubviewToFront(blurView);
NSLog(@"applicationWillResignActive: View added and brought to the front");
}
// Remove the view from the window
- (void)applicationDidBecomeActive:(UIApplication *)application
{
NSLog(@"applicationDidBecomeActive"); // Confirm this method is being called
if(_coverView != nil) {
NSLog(@"applicationDidBecomeActive: _coverView is not nil, so removing it, and setting it to nil");
[_coverView removeFromSuperview];
_coverView = nil;
} else {
NSLog(@"applicationDidBecomeActive: _coverView is already nil");
}
}
You haven't provided us any evidence so far that you've added the logging to these methods, and so we can't tell exactly what the sequence of events is, so it's extremely difficult for us to debuig this from afar with little info.
Put the comments in as I have above, and run it through until you see the problem occur, then copy the relevant text from the console and paste it here.
Topic:
UI Frameworks
SubTopic:
UIKit
That's nice. How can we help? You need to show us your code, and tell us where the error is.
From what you've put so far, my guess is you're sending the wrong thing to a method, but I can't be any clearer than that because you didn't post any code...
Topic:
UI Frameworks
SubTopic:
SwiftUI
Tags:
Does it work when using the iOS Simulator on 18.4.1? How about a Simulator on 18.5? And one on 17?
It might be your real device that has an issue, since you've said:
It doesn't work on your device on iOS 18.5.
It doesn't work on your device on iOS 18.4.1.
It works on a different device on iOS 17.
You haven't proven that it's not your device causing it, so try the other options, and see what happens.
Topic:
Developer Tools & Services
SubTopic:
Xcode
Tags:
Probably not. If it's asking for a bank account, you have to give it a bank account. Why would you want proceeds from your individual account to go to a corporate account?
Topic:
Business & Education
SubTopic:
General
Tags:
I moved onto using AppIntents instead. All the Siri Intents problems just went away.
Here's what I have now:
Main App target:
Supported Intents is just WidgetEventIntent.
Widgets target:
No supported intents (and no section for them anyway)
Watch App target:
No supported intents (there is a section for them)
Complications target:
No supported intents (and no section for them anyway)
Embedding:
The Watch App and Widgets are embedded in the Main App.
Complications is embedded in the Watch App.
I also re-wrote the main app in Swift/SwiftUI and got rid of the old Objective-C version as it was so difficult to make things work with it.
That's it.
Topic:
Developer Tools & Services
SubTopic:
Xcode
Tags:
Since you haven't responded, other than a comment, and you haven't accepted anything as an answer, here's a little more clarification in case you're still misunderstanding how to do this:
Move the fetchRecords method into the DataManager class.
Use a predicate to sort the data rather than sorting it after you've retrieved the records. It's faster.
Change your ViewModel to something like this:
class ViewModel: ObservableObject {
let manager = DataManager()
@Published var records: [Little] = []
init() {
records = manager.fetchRecords()
WidgetCenter.shared.reloadAllTimelines()
}
}
DataManager can be shared between both your iOS target (where ViewModel resides) and your widget target, so change the target membership so it's shared.
In your widget target, your getTimeline method would be something like this:
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
let manager = DataManager()
var items: [Item] = []
for record in manager.fetchRecords() {
let item = Item(trashDate: record.trashDate ?? Date.now, imageSelection: Int(record.imageSelection))
items.append(item)
}
let entry = Timeline(entries: [SimpleEntry(date: Date(), items: items)], policy: .atEnd)
completion(entry)
}
That should show you how to get data from Core Data into your widget.
And, just to answer your other question, no you can't use your ViewModel as it isn't in the widget target, and you cannot call reloadTimelines() from the widget.
If you're still having issues, then I'm sorry, but I've given you all the help I can. You haven't said whether you've attempted anything I've given you.
Topic:
UI Frameworks
SubTopic:
SwiftUI
Tags:
These are the Developer Forums, where developers of apps for Apple's platforms ask each other for hints and tips on coding.
Is this a question about an app you're developing on visionOS 2.5, or are you a consumer experiencing this general issue?
If it's a general issue, please raise a bug at: https://feedbackassistant.apple.com/ and post the FB number here.
Or, you can ask your question over at the Apple Support Forums. Thanks.
Topic:
Community
SubTopic:
Apple Developers
No need for the duplicate post. Apple have already responded to you.
Topic:
App & System Services
SubTopic:
StoreKit
What you shouldn't do is create a duplicate post with just a few minor changes. You have one hour to edit your original port. If you're outside of that one-hour window and your edits are necessary, just respond to your original post. No need to clog up the forums with duplicate posts.
Topic:
App Store Distribution & Marketing
SubTopic:
App Store Connect
Tags:
Well, I'm terribly sorry if I misunderstood your question, but it's quite difficult to make sense of what your question actually was given you posted:
A DataManager class that just creates a connection to Core Data.
A ViewModel class with a fetchRecords method that uses an instance of your DataManager class.
Your TimelineProvider showing the same code from your fetchRecords method inside your getTimeline method. (As in, why the duplication?)
If your question was the underlined question, "how should my widget get data from CoreData?" then I already answered it by explaing how I do it in my working widgets.
You can use any method you want to get data into your widget, whether you pull it directly from the DataManager (via Core Data) or your ViewModel (which has already pulled it from Core Data).
Have you tried both methods? Did one or both of them work? Which one has the simpler code? Go with that one.
Remember, widgets shouldn't be considered actively running code. You tell the timeline provider what data the widget should use and what it should look like at a snapshot in time. The widget isn't sitting there reading your data from Core Data, so how you want to provide the data to it isn't 100% relevant. You only have to be performant in the getSnapshot method because that's used in transient situations like the preview gallery.
Topic:
UI Frameworks
SubTopic:
SwiftUI
Tags:
No need for the duplicate post. All you did was change the tag.
Marking this as a duplicate. Please don't clutter the forums.
- Replies
- Boosts
- Views
- Activity
I'm not sure you should try to do this, for a couple of reasons. Look at some simple code that's written for iOS 17 and 18:
if #available(iOS 18, *) {
TabView(selection: $selectedTab) {
Tab("Watch Now", systemImage: "play", value: .watchNow) {
WatchNowView()
}
}
} else {
TabView(selection: $selectedTab) {
MenuView()
.tabItem {
Label("Menu", systemImage: "list.dash")
}
OrderView()
.tabItem {
Label("Order", systemImage: "square.and.pencil")
}
}
}
First reason: The iOS 18 format has a specific Tab object which has its own title and image in the Tab item itself, whereas iOS 17's tabItems force you to create a Label instead. That would be difficult to work around.
Second reason: Tab contains a View, whereas tabItem is a modifier on a View (just as .bold() is a modifier on a Text view). It's the opposite way round, making it difficult again.
It might be cleaner to simply do something like this, and you can remove the unnecessary code when you no longer support iOS 17:
if #available(iOS 18, *) {
MyTabs(selectedTab: $selectedTab)
} else {
MyTabs_iOS17(selectedTab: $selectedTab)
}
...
struct MyTabs: View {
@Binding var selectedTab: Tabs
var body: some View {
if #available(iOS 18, *) {
TabView(selection: $selectedTab) {
Tab("Watch Now", systemImage: "play", value: .watchNow) {
WatchNowView()
}
}
}
}
}
struct MyTabs_iOS17: View {
@Binding var selectedTab: Tabs
var body: some View {
TabView(selection: $selectedTab) {
MenuView()
.tabItem {
Label("Menu", systemImage: "list.dash")
}
OrderView()
.tabItem {
Label("Order", systemImage: "square.and.pencil")
}
}
}
}
There are ways to do this, but as I've mentioned, you'll be trying to fit A into B and C into D, and will have to write a chunk of code that makes that happen. It will likely be easier to bite the bullet and write the two separate sections.
Topic:
UI Frameworks
SubTopic:
SwiftUI
Tags:
- Replies
- Boosts
- Views
- Activity
No need for the second thread. You have an hour to edit your original post.
Anyway, is this an app you're developing? (I'm guessing not as that looks like the Santander logo.)
If it's not for an app you're developing then this is a consumer issue. These are the Developer Forums, where developers of apps for Apple's platforms ask each other for hints and tips on coding.
Your question is more of a product support one, so I'd suggest you ask it over at the Apple Support Forums. Thanks.
Topic:
App & System Services
SubTopic:
Widgets & Live Activities
Tags:
- Replies
- Boosts
- Views
- Activity
I've since moved onto Swift and SwiftUI, but when one of my apps was written in Objective-C this is what I used, and it worked every time. Perhaps it's because I'm using a UIImageView?:
- (void)applicationWillResignActive:(UIApplication *)app
{
NSLog(@"AD: applicationWillResignActive");
[self showBlurView:YES];
}
- (void)applicationWillEnterForeground:(UIApplication *)app
{
NSLog(@"AD: applicationWillEnterForeground");
[self showBlurView:NO];
}
- (void)applicationDidBecomeActive:(UIApplication *)app
{
NSLog(@"AD: applicationDidBecomeActive");
[self showBlurView:NO];
}
- (void)showBlurView:(BOOL)show
{
NSLog(@"AD: showBlurView: %@", show ? @"YES" : @"NO");
if(show) {
blurView = [[UIImageView alloc] initWithFrame:self.window.frame];
blurView.image = [UIImage imageNamed:@"blurViewImage"];
[self.window addSubview:blurView];
} else {
if(blurView != nil) {
[blurView removeFromSuperview];
}
}
}
Topic:
UI Frameworks
SubTopic:
UIKit
- Replies
- Boosts
- Views
- Activity
You've shown the time the cover view is added, but not the time it was removed.
How long did a user take between putting the app into the app switcher (or background), and bringing it back to active? How long between those NSLogs?
You're giving us piecemeal information here, making it difficult to help you.
Also, note that I added an else to where you're checking for a nil. That's important, because if coverView isn't nil at that time, then it's not going to create the view.
Add logging to every bit that's relevant.
Topic:
UI Frameworks
SubTopic:
UIKit
- Replies
- Boosts
- Views
- Activity
// Add the view to the window
-(void)applicationWillResignActive:(UIApplication *)application
{
NSLog(@"applicationWillResignActive"); // Confirm this method is being called
NSLog(@"[self.window frame] = %@", NSStringFromCGRext([self.window frame])); // Confirm the frame is valid
_coverView = [[UIView alloc]initWithFrame:[self.window frame]];
NSLog(@"applicationWillResignActive: Created view");
_coverView.backgroundColor =[UIColor blackColor];
[self.window addSubview:_coverView];
window.bringSubviewToFront(blurView);
NSLog(@"applicationWillResignActive: View added and brought to the front");
}
// Remove the view from the window
- (void)applicationDidBecomeActive:(UIApplication *)application
{
NSLog(@"applicationDidBecomeActive"); // Confirm this method is being called
if(_coverView != nil) {
NSLog(@"applicationDidBecomeActive: _coverView is not nil, so removing it, and setting it to nil");
[_coverView removeFromSuperview];
_coverView = nil;
} else {
NSLog(@"applicationDidBecomeActive: _coverView is already nil");
}
}
You haven't provided us any evidence so far that you've added the logging to these methods, and so we can't tell exactly what the sequence of events is, so it's extremely difficult for us to debuig this from afar with little info.
Put the comments in as I have above, and run it through until you see the problem occur, then copy the relevant text from the console and paste it here.
Topic:
UI Frameworks
SubTopic:
UIKit
- Replies
- Boosts
- Views
- Activity
That's nice. How can we help? You need to show us your code, and tell us where the error is.
From what you've put so far, my guess is you're sending the wrong thing to a method, but I can't be any clearer than that because you didn't post any code...
Topic:
UI Frameworks
SubTopic:
SwiftUI
Tags:
- Replies
- Boosts
- Views
- Activity
Does it work when using the iOS Simulator on 18.4.1? How about a Simulator on 18.5? And one on 17?
It might be your real device that has an issue, since you've said:
It doesn't work on your device on iOS 18.5.
It doesn't work on your device on iOS 18.4.1.
It works on a different device on iOS 17.
You haven't proven that it's not your device causing it, so try the other options, and see what happens.
Topic:
Developer Tools & Services
SubTopic:
Xcode
Tags:
- Replies
- Boosts
- Views
- Activity
Probably not. If it's asking for a bank account, you have to give it a bank account. Why would you want proceeds from your individual account to go to a corporate account?
Topic:
Business & Education
SubTopic:
General
Tags:
- Replies
- Boosts
- Views
- Activity
I moved onto using AppIntents instead. All the Siri Intents problems just went away.
Here's what I have now:
Main App target:
Supported Intents is just WidgetEventIntent.
Widgets target:
No supported intents (and no section for them anyway)
Watch App target:
No supported intents (there is a section for them)
Complications target:
No supported intents (and no section for them anyway)
Embedding:
The Watch App and Widgets are embedded in the Main App.
Complications is embedded in the Watch App.
I also re-wrote the main app in Swift/SwiftUI and got rid of the old Objective-C version as it was so difficult to make things work with it.
That's it.
Topic:
Developer Tools & Services
SubTopic:
Xcode
Tags:
- Replies
- Boosts
- Views
- Activity
Since you haven't responded, other than a comment, and you haven't accepted anything as an answer, here's a little more clarification in case you're still misunderstanding how to do this:
Move the fetchRecords method into the DataManager class.
Use a predicate to sort the data rather than sorting it after you've retrieved the records. It's faster.
Change your ViewModel to something like this:
class ViewModel: ObservableObject {
let manager = DataManager()
@Published var records: [Little] = []
init() {
records = manager.fetchRecords()
WidgetCenter.shared.reloadAllTimelines()
}
}
DataManager can be shared between both your iOS target (where ViewModel resides) and your widget target, so change the target membership so it's shared.
In your widget target, your getTimeline method would be something like this:
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
let manager = DataManager()
var items: [Item] = []
for record in manager.fetchRecords() {
let item = Item(trashDate: record.trashDate ?? Date.now, imageSelection: Int(record.imageSelection))
items.append(item)
}
let entry = Timeline(entries: [SimpleEntry(date: Date(), items: items)], policy: .atEnd)
completion(entry)
}
That should show you how to get data from Core Data into your widget.
And, just to answer your other question, no you can't use your ViewModel as it isn't in the widget target, and you cannot call reloadTimelines() from the widget.
If you're still having issues, then I'm sorry, but I've given you all the help I can. You haven't said whether you've attempted anything I've given you.
Topic:
UI Frameworks
SubTopic:
SwiftUI
Tags:
- Replies
- Boosts
- Views
- Activity
These are the Developer Forums, where developers of apps for Apple's platforms ask each other for hints and tips on coding.
Is this a question about an app you're developing on visionOS 2.5, or are you a consumer experiencing this general issue?
If it's a general issue, please raise a bug at: https://feedbackassistant.apple.com/ and post the FB number here.
Or, you can ask your question over at the Apple Support Forums. Thanks.
Topic:
Community
SubTopic:
Apple Developers
- Replies
- Boosts
- Views
- Activity
No need for the duplicate post. Apple have already responded to you.
Topic:
App & System Services
SubTopic:
StoreKit
- Replies
- Boosts
- Views
- Activity
What you shouldn't do is create a duplicate post with just a few minor changes. You have one hour to edit your original port. If you're outside of that one-hour window and your edits are necessary, just respond to your original post. No need to clog up the forums with duplicate posts.
Topic:
App Store Distribution & Marketing
SubTopic:
App Store Connect
Tags:
- Replies
- Boosts
- Views
- Activity
Well, I'm terribly sorry if I misunderstood your question, but it's quite difficult to make sense of what your question actually was given you posted:
A DataManager class that just creates a connection to Core Data.
A ViewModel class with a fetchRecords method that uses an instance of your DataManager class.
Your TimelineProvider showing the same code from your fetchRecords method inside your getTimeline method. (As in, why the duplication?)
If your question was the underlined question, "how should my widget get data from CoreData?" then I already answered it by explaing how I do it in my working widgets.
You can use any method you want to get data into your widget, whether you pull it directly from the DataManager (via Core Data) or your ViewModel (which has already pulled it from Core Data).
Have you tried both methods? Did one or both of them work? Which one has the simpler code? Go with that one.
Remember, widgets shouldn't be considered actively running code. You tell the timeline provider what data the widget should use and what it should look like at a snapshot in time. The widget isn't sitting there reading your data from Core Data, so how you want to provide the data to it isn't 100% relevant. You only have to be performant in the getSnapshot method because that's used in transient situations like the preview gallery.
Topic:
UI Frameworks
SubTopic:
SwiftUI
Tags:
- Replies
- Boosts
- Views
- Activity