Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
pokeyman
Nov 26, 2006

That elephant ate my entire platoon.
Yeah I'm a good 15 pages behind the Awful.app thread, gotta catch up. Ditching Imgur is on my list, and I appreciate the GitHub issue!

Adbot
ADBOT LOVES YOU

Data Graham
Dec 28, 2009

📈📊🍪😋



Phew, yeah I knew pokeyman was around, but it's good to have confirmation. Sucks that everything must rest on one person's shoulders though.

I would help but I am barely competent with iOS dev. Like "can follow a tutorial" at best

Hadlock
Nov 9, 2004

Data Graham posted:

Phew, yeah I knew pokeyman was around, but it's good to have confirmation. Sucks that everything must rest on one person's shoulders though.

An alarming amount of the electric and financial infrastructure works this way too :tif:

Presumably a single person has the ability to push new app versions to the app store, so uh, don't get hit by a bus any time soon :ohdear:

KidDynamite
Feb 11, 2005

do you all have a way of handling strong password suggestion for uitests? i keep running into issues when i try to disable it via settings.

KidDynamite
Feb 11, 2005

viewIsAppearing, xcode test recordings, and push notifications console are my wwdc mvps

fankey
Aug 31, 2001

My iOS app continuously communicates with a server via TCP using CocoaAsyncSockets. I have customer reports where the app dies after 25+ hours running. I haven't be able to reproduce this issue but I do see printouts like this in the console
code:
[tcp] tcp_input [C6.1.1:3] flags=[R] seq=4114417561, ack=0, win=0 state=LAST_ACK rcv_nxt=4114417561, snd_una=1144821964
[tcp] tcp_input [C6.1.1:3] flags=[R] seq=4114417561, ack=0, win=0 state=CLOSED rcv_nxt=4114417561, snd_una=1144821964
I don't have any proof those messages are actually a problem but I can't determine the source or what they mean. I do understand TCP to some degree so I can infer what those messages mean but I'm trying to understand why these messages are being printed out.

fankey fucked around with this message at 23:24 on Jun 8, 2023

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.
That sequence number is approaching 2^32 but I have no idea how suspicious to be of that.

Is anything in https://developer.apple.com/documentation/network/debugging_https_problems_with_cfnetwork_diagnostic_logging helpful?

fankey
Aug 31, 2001

Thanks. That appears to mostly deal with HTTP communications so it might not apply, but I'll take a look.

When my app crashes it's basically receiving data over a TCP socket and creating a UIImage using [UIImage imageWithData:data]. Every time I call that function
code:
CGImageCopyImageSource:4692: *** CGImageGetImageSource: cannot get CGImageSourceRef from CGImageRef (CGImageSourceRef was already released)
is printed in the console ( not in Xcode, I need to stream the Console from the device to see that ). The data is valid and the image is created and displayed. If I put a symbolic breakpoint at ERROR_CGImageCopyImageSource_WAS_CALLED_WITH_INVALID_CGIMAGE it's hit. I don't see how I could cause that error since all I'm doing is passing in an NSData. I've verified I'm making this call on the UIApplicationMain thread so I don't think this is a threading issue. Once again, not sure this is a problem but it definitely spams the console.

This is also showing up in the console. Not sure what it means but seems like it could be related to my problem
code:
default    09:05:50.068157-0600    symptomsd    SymptomAnalytics ServiceImpl: FAE perform query for powerlogHelperd (pid 953) on LiveUsage predicate hasProcess.procName == $targetname sort (null) actions {
    "hasProcess.procName" = copyRelationship;
    nameChain = "XXXX";
    refreshUsage = refreshUsage;
    "hasProcess.firstTimeStamp" = copyRelationship;
    "hasProcess.bundleName" = copyRelationship;
    "<null>" = "<null>";
} properties (null)
default    09:05:50.088391-0600    symptomsd    Data Usage for XXXX on flow 9072 - WiFi in/out: 202060073/18371739, WiFi delta_in/delta_out: 42934/1378, Cell in/out: 0/0, Cell delta_in/delta_out: 0/0, RNF: 0, subscriber tag: 0
default    09:05:50.094079-0600    symptomsd    Data Usage for XXXXX on flow 9049 - WiFi in/out: 202060281/18371739, WiFi delta_in/delta_out: 208/0, Cell in/out: 0/0, Cell delta_in/delta_out: 0/0, RNF: 0, subscriber tag: 0
default    09:05:50.096467-0600    symptomsd    Data Usage for XXXXX on flow 9047 - WiFi in/out: 202062179/18371739, WiFi delta_in/delta_out: 1898/0, Cell in/out: 0/0, Cell delta_in/delta_out: 0/0, RNF: 0, subscriber tag: 0
default    09:05:50.099216-0600    symptomsd    Data Usage for XXXXX on flow 9045 - WiFi in/out: 202064313/18372147, WiFi delta_in/delta_out: 2134/408, Cell in/out: 0/0, Cell delta_in/delta_out: 0/0, RNF: 0, subscriber tag: 0
default    09:05:50.101309-0600    symptomsd    Data Usage for XXXXX on flow 9043 - WiFi in/out: 202068581/18372555, WiFi delta_in/delta_out: 4268/408, Cell in/out: 0/0, Cell delta_in/delta_out: 0/0, RNF: 0, subscriber tag: 0
error    09:05:50.101838-0600    symptomsd    Suspicious packet count 590 when bytes 1607 for flow 7693
error    09:05:50.102420-0600    symptomsd    Flow details for excess packet count <private>
error    09:05:50.102649-0600    symptomsd    Suspicious packet count 590 when bytes 1607 for flow 7693
error    09:05:50.102946-0600    symptomsd    Flow details for excess packet count <private>
error    09:05:50.103132-0600    symptomsd    Suspicious packet count 589 when bytes 1607 for flow 7693
error    09:05:50.103395-0600    symptomsd    Flow details for excess packet count <private>
error    09:05:50.103786-0600    symptomsd    Suspicious packet count 590 when bytes 1607 for flow 7693
error    09:05:50.104167-0600    symptomsd    Flow details for excess packet count <private>
error    09:05:50.104243-0600    symptomsd    Suspicious packet count 590 when bytes 1607 for flow 7693
error    09:05:50.104312-0600    symptomsd    Flow details for excess packet count <private>
error    09:05:50.104389-0600    symptomsd    Suspicious packet count 589 when bytes 1607 for flow 7693
error    09:05:50.104831-0600    symptomsd    Flow details for excess packet count <private>
error    09:05:50.105762-0600    symptomsd    Suspicious packet count 590 when bytes 1607 for flow 7693
error    09:05:50.106044-0600    symptomsd    Flow details for excess packet count <private>
error    09:05:50.106245-0600    symptomsd    Suspicious packet count 592 when bytes 2113 for flow 7675
error    09:05:50.106515-0600    symptomsd    Flow details for excess packet count <private>
error    09:05:50.106686-0600    symptomsd    Suspicious packet count 592 when bytes 2113 for flow 7675
error    09:05:50.106945-0600    symptomsd    Flow details for excess packet count <private>
error    09:05:50.107218-0600    symptomsd    Suspicious packet count 591 when bytes 2113 for flow 7675
error    09:05:50.107256-0600    symptomsd    Flow details for excess packet count <private>
error    09:05:50.107724-0600    symptomsd    Suspicious packet count 592 when bytes 2113 for flow 7675
error    09:05:50.108436-0600    symptomsd    Flow details for excess packet count <private>
error    09:05:50.108835-0600    symptomsd    Suspicious packet count 592 when bytes 2113 for flow 7675
error    09:05:50.109174-0600    symptomsd    Flow details for excess packet count <private>
error    09:05:50.109361-0600    symptomsd    Suspicious packet count 591 when bytes 2113 for flow 7675
error    09:05:50.109636-0600    symptomsd    Flow details for excess packet count <private>
error    09:05:50.110357-0600    symptomsd    Suspicious packet count 592 when bytes 2113 for flow 7675
error    09:05:50.110397-0600    symptomsd    Flow details for excess packet count <private>
default    09:05:50.116364-0600    symptomsd    SymptomAnalytics ServiceImpl: FAE performQueryOnEntity outcome array after refresh:
default    09:05:50.116647-0600    symptomsd    entry:                                                               Name    Type         WiFiIn      WiFiOut       CellIn      CellOut Tag Kind
default    09:05:50.116727-0600    symptomsd    entry: Tue Aug 18 12:34:05 2020                     XXXXX (bundle)    5051487176    554749260            0            0   0   0
default    09:05:50.116794-0600    symptomsd    entry: Fri Apr 28 14:26:56 2023                     XXXXX (bundle)     225899657      7383960            0            0   0   1
default    09:05:50.116957-0600    symptomsd    entry: Tue Jun  6 14:49:11 2023                     XXXXX (bundle)     202068581     18372555            0            0   0   1
default    09:05:50.117408-0600    symptomsd    entry: Tue May 23 13:14:08 2023                     XXXXX (bundle)    1334633913    157561717            0            0   0   1
default    09:05:50.117851-0600    symptomsd    SymptomAnalytics ServiceImpl: FAE end of outcome array
default    09:05:50.119602-0600    powerlogHelperd    NetworkUsage outcome has payload size: 1

awesomeolion
Nov 5, 2007

"Hi, I'm awesomeolion."

I'm getting this bug and the only relevant thing I've found online is this https://www.reddit.com/r/iOSBeta/comments/xhv2jc/ios_161_20b5045d_youtube_app_pip_grey_screen_and/

Any ideas how to solve?

Edit: That's all the detail I can provide. I'm wondering where you'd look to solve this type of bug.

awesomeolion fucked around with this message at 22:19 on Jun 16, 2023

ultramiraculous
Nov 12, 2003

"No..."
Grimey Drawer

awesomeolion posted:

I'm getting this bug and the only relevant thing I've found online is this https://www.reddit.com/r/iOSBeta/comments/xhv2jc/ios_161_20b5045d_youtube_app_pip_grey_screen_and/

Any ideas how to solve?

Edit: That's all the detail I can provide. I'm wondering where you'd look to solve this type of bug.

I know this is an old post, but it seems like maybe there are some specifics you might need to give like if this is an HLS stream/local/etc.

...and I'd also I'd give you the same advice I wish I could give to that entire subreddit...please file a feedback/radar and post FB# somewhere if you're having an issue. It's a lot easier to cite as a reason to prioritize something than "some dude on reddit agrees we suck" 😂.

awesomeolion
Nov 5, 2007

"Hi, I'm awesomeolion."

ultramiraculous posted:

I know this is an old post, but it seems like maybe there are some specifics you might need to give like if this is an HLS stream/local/etc.

...and I'd also I'd give you the same advice I wish I could give to that entire subreddit...please file a feedback/radar and post FB# somewhere if you're having an issue. It's a lot easier to cite as a reason to prioritize something than "some dude on reddit agrees we suck" 😂.

Hey! I resolved the bug and forgot to post here. Basically I was making the pip controller too early in my video player lifecycle. Setting it up slightly later resolved the issue. Why exactly? Idk. I guess in an ideal world I would have gotten a "hey dumbass set up ur poo poo at the right time" error in the delegate callback but that's asking a lot lol

dizzywhip
Dec 23, 2005

Are there any good resources out there for learning how to do low-level profiling and optimization of Swift code?

I've done plenty of basic profiling of apps with Instruments but haven't really gone beyond using the time profiler to diagnose relatively simple performance issues. But now I'm looking to optimize some code which isn't particularly slow but is going to be part of a game loop, and I'd like to get it running as fast as I reasonably can. Time profiler isn't giving me anything that seems actionable, and I'm kind of at a loss on how to dig deeper.

I see people talk about things like being bottlenecked by reference counting or dynamic dispatch overhead, or optimizing by messing with inlining, which I understand in a general sense, but I don't know how I would go about determining whether any of those are actually issues in a specific area of code without just guessing blindly. Are there other instruments or tools that help to diagnose these sorts of things?

awesomeolion
Nov 5, 2007

"Hi, I'm awesomeolion."

dizzywhip posted:

Are there any good resources out there for learning how to do low-level profiling and optimization of Swift code?

I've done plenty of basic profiling of apps with Instruments but haven't really gone beyond using the time profiler to diagnose relatively simple performance issues. But now I'm looking to optimize some code which isn't particularly slow but is going to be part of a game loop, and I'd like to get it running as fast as I reasonably can. Time profiler isn't giving me anything that seems actionable, and I'm kind of at a loss on how to dig deeper.

I see people talk about things like being bottlenecked by reference counting or dynamic dispatch overhead, or optimizing by messing with inlining, which I understand in a general sense, but I don't know how I would go about determining whether any of those are actually issues in a specific area of code without just guessing blindly. Are there other instruments or tools that help to diagnose these sorts of things?

If you need to tune one piece of code that's expensive in your game loop I would write that in C/Objc C. Also out of curiosity why are you writing a game in native code? As opposed to Unity or Unreal or Godot or whatever

dizzywhip
Dec 23, 2005

That's a fair suggestion, and I'm not totally against dropping down to C for performance (I've done it for some audio signal processing as part of the same project), but I'd prefer to avoid it if I can. I'm hoping to get a better grasp of low-level Swift optimization so that I don't have to use C unless it's really necessary.

In this particular case it wouldn't really be an option anyways because the code in question is a result builder interface for constructing skeletal animations programmatically. There's no real point to that system if I can't use result builders and other Swift features. Worst case, if it's too slow to run the result builder to construct animations on the fly, then I can just run it ahead of time and cache the results. Which is fine, but doing it on the fly would be nice because I'd be able to do a lot more parameterization and make the animations more dynamic.

I'm interested in the subject outside of just this project though. I also do app development for my job and as a hobby, so it would be pretty useful to understand this stuff better in general.

As for why I'm doing this at all, that's a good question! This is a game engine project I'm building for my own use as a hobby. It's obviously not a practical or efficient approach to building a game compared to using an existing engine, but it's more fun and has been a great learning experience for me. I like Swift a lot, and it has a lot of cool unique features that I think have potential for creating novel game development workflows, so I'm exploring that and seeing where it goes.

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.
I have no suggestions from experience, but when I poke around the Swift stdlib or stdlib-adjacents like swift-collections I see a lot of annotations and private storage types and such that must be partly for performance optimization. Could give you something to look up at least?

Speaking of swift-collections, https://github.com/apple/swift-collections-benchmark might be of use.

dizzywhip
Dec 23, 2005

That does seem like a good starting point. Thanks for the idea!

ultramiraculous
Nov 12, 2003

"No..."
Grimey Drawer
Using Signposts might be a place to start as well (There's a Swift API available as well))

101
Oct 15, 2012


Vault Dweller
Mannnn… async await, TCA, and their swift-dependencies system are just so god-drat good.

I honestly don't think I'd enjoy SwiftUI 10x as much as I do if not for them.

Froist
Jun 6, 2004

I've had a sideproject on the backburner since I hit an issue with SwiftUI views not updating when CoreData relationships changed. This was right around the time of WWDC, so figured I'd wait it out and try again with SwiftData. Lo and behold, having rebuilt the app from scratch on the iOS 17 RCs I still have the same issue, though with a bit more investigation it seems a different problem than I originally thought and now I'm more confused.

The tl:dr; version is: I have two models, a "Group" and an "Item". Items can be added to Groups, and in the main "Groups" list I wanted to show a label with the count of items in that group (for the trivial problem demo, the real data is more involved). If I generate the rows for that list from a local @ViewBuilder function it updates the count when an item is added to the group, but if I generate it from a separate View struct it doesn't.

Can anyone explain what the difference is between these, and if there's a simple "fix" to get the external View to update correctly? i.e. I'm hoping there's some magic place to put an Observable/ObservedObject/etc annotation, not some hack of faking an update on some dummy property on the Group to trick the view into updating.

Demo code:

Swift code:
import SwiftUI
import SwiftData

@main
struct MinimalTestApp: App {
    var sharedModelContainer: ModelContainer = {
        let schema = Schema([
            Device.self,
            DeviceGroup.self
        ])
        let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false)

        do {
            return try ModelContainer(for: schema, configurations: [modelConfiguration])
        } catch {
            fatalError("Could not create ModelContainer: \(error)")
        }
    }()

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .modelContainer(sharedModelContainer)
    }
}
Swift code:
import SwiftUI
import SwiftData

// MARK: - Models

@Model final class Device {
    var name: String
    @Relationship(inverse: \DeviceGroup.devices) var group: DeviceGroup?
    
    init(name: String) {
        self.name = name
    }
}

@Model final class DeviceGroup {
    var name: String
    var devices: [Device]
    
    init(name: String, devices: [Device] = []) {
        self.name = name
        self.devices = devices
    }
}

// MARK: - Main view

/// First tap 'Add group' at least once to add a group. 
/// Then tap 'Add item' to add an item to the first group.
/// The text on the right of the group row shows the number of items it's associated with.
/// The first row (generated by a ViewBuilder func) updates when the relationship changes.
/// The second row (generated by an identical external View struct) does not update.
struct ContentView: View {
    @Environment(\.modelContext) private var modelContext
    @Query private var groups: [DeviceGroup]

    var body: some View {
        NavigationStack {
            List {
                ForEach(groups) { group in
                    VStack {
                        groupTile(group: group) // ViewBuilder function updates when the group changes
                        GroupTile(group: group) // External View struct doesn't
                    }
                }
            }
            .toolbar {
                ToolbarItem(placement: .bottomBar) { Button("Add group") { addGroup() } }
                ToolbarItem(placement: .bottomBar) { Button("Add item") { addItem() } }
            }
        }
    }
    
    private func addGroup() {
        modelContext.insert(DeviceGroup(name: "Group \(groups.count + 1)"))
    }
    
    private func addItem() {
        let newItem = Device(name: "Dummy item")
        newItem.group = groups.first
        modelContext.insert(newItem)
    }
    
    @ViewBuilder private func groupTile(group: DeviceGroup) -> some View {
        HStack {
            Text(group.name)
            Spacer()
            Text("\(group.devices.count) items")
        }
    }
}

struct GroupTile: View {
    let group: DeviceGroup
    var body: some View {
        HStack {
            Text(group.name)
            Spacer()
            Text("\(group.devices.count) items")
        }
    }
}

// MARK: - Preview

#Preview {
    ContentView()
        .modelContainer(for: [Device.self, DeviceGroup.self], inMemory: true)
}
(Note: The above needs Xcode 15/iOS 17 because it’s using SwiftData, but really that’s only because it’s easier to share the code than CoreData models. Now I’ve realised the problem is “fixed” using @ViewBuilder I’ve found the same works for my old CoreData version.)

Froist fucked around with this message at 18:39 on Sep 17, 2023

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.
In the first example, @Query is a DynamicProperty that tells SwiftUI about changes to the list of groups, including changes to any of its elements, and that triggers a render. The views in the tree at this point change when the count changes, so there's a diff and you see the new view.

In the second, I think what happens is the GroupTile has a plain old group property that makes the view tree look identical. So the Query picks up the change as before, but the render pass creates an identical GroupTile so it looks like there's no diff from the previous tree. I think you want an @ObservedObject in front of GroupTile's group.

Froist
Jun 6, 2004

Thanks, yeah I was guessing something behind the scenes of the @Query modifier was causing it - taking SwiftData/CoreData out of the equation and replicating it with regular structs causes both to fail to update. I’m just surprised if it knows to regenerate the tree via the ViewBuilder that the same doesn’t apply to the external struct.

Unfortunately @ObservedObject isn’t the magic bullet - it still doesn’t update automatically. It does if I call objectWillChange.send() on the Group at the point I add the Item to it, but that still feels like a workaround (albeit not particularly hacky).

I’d be happier if it didn’t work in either case, but the fact the scoping of the same object changes the behaviour is undermining my understanding of SwiftUI..

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.
I don't think ViewBuilder makes a difference here, it's generating the whole tree vs. having a separate custom view. Like if you drop the @ViewBuilder and return a View the old fashioned way, I would expect no difference in behaviour. (Maybe that's obvious but one less variable in the confusion?)

I'm fairly sure Core Data objects emit KVO notifications when a relationship's count changes, so I wonder if a) I'm wrong about that b) NSManagedObject's ObservableObject implementation is completely separate from KVO or c) SwiftData works differently.

What happens if your GroupTile stores properties derived from the Group? Like a let name: String and let deviceCount: Int.

Froist
Jun 6, 2004

pokeyman posted:

I don't think ViewBuilder makes a difference here, [snip...] Like if you drop the @ViewBuilder and return a View the old fashioned way, I would expect no difference in behaviour. (Maybe that's obvious but one less variable in the confusion?)
Yeah sorry, really I was just using "ViewBuilder" to refer to the function version vs the external struct, I didn't expect that to be doing any extra magic. Just to sanity check it I did drop that and change it to return AnyView and it made no difference (i.e. function version still worked, struct version without objectWillChange workaround didn't).

pokeyman posted:

I'm fairly sure Core Data objects emit KVO notifications when a relationship's count changes, so I wonder if a) I'm wrong about that b) NSManagedObject's ObservableObject implementation is completely separate from KVO or c) SwiftData works differently.
I think you're right - surely they must be emitting a notification because the function version works correctly? I'm not sure how to dig into your 'b' possibility though. But I'd rule out 'c' - I had the identical problem originally with CoreData, and afaik SwiftData is backed by CoreData under the hood anyway.

pokeyman posted:

What happens if your GroupTile stores properties derived from the Group? Like a let name: String and let deviceCount: Int.
This actually fixed it - first I tried making these 'let' properties so the caller in the main view body had to pass in each of these individually, then I created an init(group: ) on GroupTile so the calling code could be unchanged and this worked too :toot:

I'm still a bit baffled by why this makes a difference. Going back to the original code (i.e. removing this fix) but adding logging shows:
  1. It's re-calling GroupTile.init() with the new DeviceGroup because it knows it's changed
  2. But then doesn't call body to get an updated view to show
  3. But if I override the equality operator on DeviceGroup to explicitly compare the count of the child items, it does re-call body to generate a new view but still doesn't end up showing it

pokeyman posted:

[snipped from earlier] it's generating the whole tree vs. having a separate custom view.
This hits at something I had misunderstood. If var body: some View { defined a big tree, but only some deep down node had changed (e.g. a single Text() item), I'd always thought that it was intelligent enough to only re-generate that single node, not the entire view tree. It sounds/looks like that's not the case though (unless the way @Query is propagating changes is causing that).

Thanks a lot for the pointers, even if I'm still confused I at least have some more satisfying workarounds to use! But I don't want to drag this on and on..

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
Think of it as two levels of hierarchy. Each view has a local hierarchy of views, which is described by the value of the body property. That’s the level at which changes to State are tracked: if State changes, body is re-read, and the new value is compared to the last one to see how the local hierarchy changes. The same thing happens separately for any child views (assuming they survive the changes above them in the hierarchy). But that’s the granularity that happens at, and in general there’s no machinery for figuring out that, like, only one portion of the body getter uses a particular piece of state and so the rest of the body doesn’t change. If that’s an important optimization for you, you should split out that portion of the body as its own view (or alternatively, the portions you specifically don’t want to re-run so often) so that the tracking there will naturally be more targeted.

duck monster
Dec 15, 2004

Apparently theres swift bindings to the Godot game engine. This is a rather pleasing thing to learn.

Third party , and possibly goofy to run, but hey, swift! On a real big-boy game engine.

Pulcinella
Feb 15, 2019
Probation
Can't post for 27 days!
From the Xcode 15.1 Beta release notes

quote:

@IBDesignable views are deprecated and will be removed in a future release. (115873872)

RIP bozo, you never worked well and broke incredibly easily. Still, I wonder if it is a sign of things to come. I can't see UIKit/AppKit going away anytime soon (SwiftUI feels like it is becoming more of a wrapper around UIKit as the years go on) but I wonder how long InterfaceBuilder will be around. The only feature I really use it for is visually laying out constraints, so I would actually prefer if the only feature was laying out a bunch of gray, featureless rectangles and generating constraints (even better if it then just spat out the code to generate the constraints. I don't really need the .xib). I know IB is generally unpopular (and a lot of the "magic" was a bunch of poo poo the barely or never worked) but it still feels like the end of an era.

If SwiftUI gets a true collection view equivalent (meaning all the crazy layout stuff you can do beyond just simple grid layouts, also cell reuse) and a .layout() modifier that lets you setup constraints rather than manual layout calculation, I think I would finally move over to SwiftUI, as much as I dislike it. Well move over in my hobby apps, which I hold to a much higher standard than my professional work, where I have been using SwiftUI where it makes sense (simple screens that can be done in <20 minutes in SwiftUI vs 1-2+ hours in UIKit).

Also the 15.1 Beta download page just straight up mentions that "Developing for visionOS requires a Mac with Apple silicon." Guess it got too tedious to maintain a simulator compatible for Intel+Metal on AMD.

duck monster
Dec 15, 2004

Oh drat its going away? Part of why I ended up drifting out of ios work (apart from the job market getting its dick ripped out out by those stupid html5 apps) was I was just finding it tiresome keeping up with the new tech. Backend has always moved at a more comfortable pace, faddish nodejs nonsense notwithstanding, and SwiftUI was top of that list. I just.... couldn't be bothered throwing away so much built up experience for that f'ing thing, it was time to go back to Unix.

The shame of it is, at the start of the IOS sdk days, I made filthy sums of cash ($5K+ a week) off it, at a time when everyone else was in welfare queues due to the stockmarket crash, because for about a year, I was the only guy in Perth doing it as best as I could tell. Well one other guy, and he's now stupid rich and I'm still grinding code because I'm highly dumb with money [also he swiped my taxi contract, and that lost me about 4 months of work] lol

duck monster fucked around with this message at 06:31 on Oct 4, 2023

awesomeolion
Nov 5, 2007

"Hi, I'm awesomeolion."

It's interesting how Apple prioritizes their developer tools. Xcode and Swift and Swift UI are pretty ill suited to huge code bases or performance critical code which makes me think Apple is optimizing for indie devs and small dev teams making new apps.

I guess if you look at the number of published apps created by small teams it would be 99%+ or something. But if you slice it by total user time spent or revenue generated it would skew heavily to apps made by large companies/teams.

One of my favorite apple dev forums posts was someone explaining that Apple couldn't possible use Xcode internally because it was just so buggy and half baked. Another good one was the person who made clearing xcode's caches one of the build steps cause it was so bad at warm
builds.

If I was Tim Cook I would shift the priorities a bit toward performance of xcode and apple's frameworks and away from allowing a noob to build a hello world app in 3 hours instead of 5.

awesomeolion
Nov 5, 2007

"Hi, I'm awesomeolion."

Another idea is to put a loud siren in Tim Cook's office that goes off any time an Xcode build takes over an hour.

Data Graham
Dec 28, 2009

📈📊🍪😋



It's absolutely mind-boggling how terrible the user experience of using Xcode is compared to any full-featured IDE like JetBrains*. It's so bad I feel like I have to be missing something extremely fundamental, like I need to unlock a power-up or something.

I have a friend who's completely code-illiterate and barely technically proficient and he thinks he is going to go through the Swift Playgrounds exercises on his iPad and go from "🍎 + 🎱 = 🐊, good job! Yaaay!" to production-grade user-facing apps for the industry he's in, all because "Apple makes it easy for people like me", if I'll just help him through the occasional tricky spots. Having built a few fairly bare-bones apps myself in both Obj-C and Swift I keep trying to find diplomatic ways to tell him that he's going to need like ten years of intensive computer science training to understand OO principles, memory management, unit testing, UI layout, debugging, and a million other things that I with 20+ years of experience in a variety of languages am completely intimidated by in the Apple world and wouldn't feel comfortable touching without at least another half-decade of intensively studying it with the goal of making it my primary platform, with everything I already know in other languages as a foundation.

And that's without even getting into how diabolically painful it is to use Xcode even as someone who more or less knows how these things are supposed to work. It's rickety and awkward on the best of days and if I ever get something working I dare not breathe for fear that it will all come collapsing down on me without warning. I wouldn't wish it on my worst enemy but I don't know how to tell my friend that without it sounding like I'm just being obstinate for no good reason.

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed
There has to be something deeply wrong on the project management side because it's not like they aren't investing heavily into Xcode. It might be as simple as that they reward shipping things which can be showed off at WWDC and don't reward making those things actually work, or perhaps the sheer miserableness of reporting bugs to them means they genuinely have no clue how broken everything is.

Vesi
Jan 12, 2005

pikachu looking at?
I use flutter for iOS stuff now even if we don't always need android, xcode is there just for setting up the devices and ipa upload

Canned Sunshine
Nov 20, 2005

CAUTION: POST QUALITY UNDER CONSTRUCTION



I'm a complete idiot when it comes to programming, but I had a general question. If I create a kext for my personal use, to allow display and system sleep to occur under certain hardware, I assume that I'd have to disable SIP in order to use it?

If I sign up for a developer account though, am I able to request it be signed, so then I wouldn't have to disable SIP?

Like I said, complete idiot.

SaTaMaS
Apr 18, 2003
In Core Data I have the main ViewContext for everything view related, and all changes are copied to a background context where changes are synced with the server in order to not clog the main thread, and to keep syncing decoupled from view state. Is there any way to do something similar in SwiftData? It looks like in SwiftData, a new model context is spun off from a model container, changes are made in this new context, and then these changes are saved back into the container when ready, which is great for persisting locally, but not great for continually looking for data changes that need to be remotely synchronized.

Graniteman
Nov 16, 2002

SaTaMaS posted:

In Core Data I have the main ViewContext for everything view related, and all changes are copied to a background context where changes are synced with the server in order to not clog the main thread, and to keep syncing decoupled from view state.

With SwiftData they gave us a type of class called a ModelActor for doing background work. It has its own special ModelContext which you use for that background work. I’ve made a couple in my current project and find it works fine, and when you save that background context you will get changes on the main actor that show up in the UI. I can point you to some example code when I’m at my desk in a day or so if you can’t find a good example. The syntax changed some during the betas fyi.

You should definitely using a model actor to perform your background data access and sync. I don’t offhand know the best way to use that to monitor for changes in the model context to trigger that background work. In Core Data I would subscribe to a notification. Maybe you can still do that since it’s using Core Data internally?

Side note: I really hate that their official recommendation for solving some SwiftData problems is “implement and maintain a compete parallel data storage stack in Core Data and use that to solve your problem.”

Ihmemies
Oct 6, 2012

Data Graham posted:

Phew, yeah I knew pokeyman was around, but it's good to have confirmation. Sucks that everything must rest on one person's shoulders though.

I would help but I am barely competent with iOS dev. Like "can follow a tutorial" at best

iOS dev also has an enormous barriers of entry. You need to buy specialized expensive, legacy specced hardware you won’t be using for anything else. You need to learn a new language and new tools you won’t use with anything else. It’s not enough to just own an iPhone.

I guess they just want to keep the poor and non-faithful developers away from their walled garden. Maybe if I some day get a Mac for free, I could look at the iOS development. I doubt Apple wants to loan hardware for developers for free either.

Corb3t
Jun 7, 2003

Ihmemies posted:

iOS dev also has an enormous barriers of entry. You need to buy specialized expensive, legacy specced hardware you won’t be using for anything else. You need to learn a new language and new tools you won’t use with anything else. It’s not enough to just own an iPhone.

I guess they just want to keep the poor and non-faithful developers away from their walled garden. Maybe if I some day get a Mac for free, I could look at the iOS development. I doubt Apple wants to loan hardware for developers for free either.

Mac Minis regularly go on sale for like $500. MacBook Airs can be found for under $800. Even if you only use it for 5 years to develop on, you're only spending $8 a month on the hardware. Cheaper than an iPhone Pro, that's for sure...

It's never been more affordable to get a Mac.

Corb3t fucked around with this message at 15:35 on Oct 14, 2023

Ihmemies
Oct 6, 2012

Yes but that is 500€ for legacy spec. I bought a 2012 model laptop in 2018? For 150€ and it came with 8GB of ram and 256GB of ssd. No way I’d pay even 150€ for a similar computer without a display, and a battery and a dvd drive in 2023.

I already have a two good and fast pc’s, my old laptop and a Xeon server too. There is simply no reason at all to waste any amount of money for specialized low spec hardware I can’t use for anything else.

Chamook
Nov 17, 2006

wheeeeeeeeeeeeee

Ihmemies posted:

You need to learn a new language and new tools you won’t use with anything else.

Swift on the server is totally a thing (please let me believe that there’s a nice way out of .NET land, I need this)

Adbot
ADBOT LOVES YOU

SaTaMaS
Apr 18, 2003

Graniteman posted:

With SwiftData they gave us a type of class called a ModelActor for doing background work. It has its own special ModelContext which you use for that background work. I’ve made a couple in my current project and find it works fine, and when you save that background context you will get changes on the main actor that show up in the UI. I can point you to some example code when I’m at my desk in a day or so if you can’t find a good example. The syntax changed some during the betas fyi.

You should definitely using a model actor to perform your background data access and sync. I don’t offhand know the best way to use that to monitor for changes in the model context to trigger that background work. In Core Data I would subscribe to a notification. Maybe you can still do that since it’s using Core Data internally?

Side note: I really hate that their official recommendation for solving some SwiftData problems is “implement and maintain a compete parallel data storage stack in Core Data and use that to solve your problem.”

Some sample code would be awesome, but monitoring for changes is key, in Core Data I can listen for the ContextDidSaveNotification, copy the changes from the viewContext to the syncContext, then look at the objects associated with the notification, and for each endpoint I have there is an associated NSPredicate that when true means the object needs to be synchronized. For SwiftData I know there is a new query language but I'm not sure how to run queries on the set of changed objects from a save notification like I can in Core Data.

SaTaMaS fucked around with this message at 00:20 on Oct 18, 2023

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply