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
Glimm
Jul 27, 2005

Time is only gonna pass you by

rjmccall posted:

I think there’s supposed to be some laziness about those loops when the elements are fixed-size, but that might not have ever been real.

I thought List was lazy but VStack and HStack were not, and they now have LazyVStack and LazyHStack variants

Essentially List is backed by UITableView, I think

Adbot
ADBOT LOVES YOU

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed
Even a LazyVStack scales much worse with a large number of elements than using a UITableView as long as the UITableView code isn't using reloadData. UITableView with fixed-height rows works fine for arbitrarily large numbers of rows, and List... doesn't.

awesomeolion
Nov 5, 2007

"Hi, I'm awesomeolion."

I recently started Swift UI and I'm trying to sync the player's current score from a SpriteKit scene with a Swift UI overlay. At first I tried to use a @StateObject in my SKScene which didn't work. Then I tried KVO and a delegate pattern but didn't get very far with those either. My goal is for frequent updates to flow out of my GameScene SKScene and into my Swift UI View GameOverlayView. I know that the Swift UI piece works because I made an empty project and synced one property across a bunch of Swift UI views using this same approach. I guess I could use notifications but that seems like a hack when there should be a proper way for data to flow with this configuration... Apologies (for my code) and thanks in advance <3

code:
import SpriteKit
import SwiftUI

class GameData: ObservableObject {
    @Published var score: Double
    
    init(score: Double) {
        self.score = score
    }
}

struct GameView: View {
    @StateObject var gameData = GameData(score: 0)

    var scene: SKScene {
        let scene = SKScene(fileNamed: "GameScene")! as! GameScene
        scene.scaleMode = .resizeFill
        return scene
    }
    
    var body: some View {
        ZStack {
            SpriteView(scene: scene)
                .edgesIgnoringSafeArea(.all)
            GameOverlayView(gameData: gameData)
        }
    }
}

struct GameView_Previews: PreviewProvider {
    static var previews: some View {
        GameView()
    }
}

Glimm
Jul 27, 2005

Time is only gonna pass you by

awesomeolion posted:

I recently started Swift UI and I'm trying to sync the player's current score from a SpriteKit scene with a Swift UI overlay. At first I tried to use a @StateObject in my SKScene which didn't work.

Maybe try passing your GameData to the scene, or even just the binding to the score property? The scene can update it and re-render your view.

I don't know how expensive creating a scene is but I think your code will re-create the scene every time body is called, which may not be ideal.

Glimm fucked around with this message at 16:34 on Jan 24, 2021

awesomeolion
Nov 5, 2007

"Hi, I'm awesomeolion."

Glimm posted:

Maybe try passing your GameData to the scene, or even just the binding to the score property? The scene can update it and re-render your view.

I don't know how expensive creating a scene is but I think your code will re-create the scene every time body is called, which may not be ideal.

Thanks for your thoughts. After a few hours of poking at it I've decided to go with just using NotificationCenter to post the score and an onReceive publisher on my overlay Swift UI view. Not very elegant but it will do for now!

prom candy
Dec 16, 2005

Only I may dance
If I have a screen with a bunch of stuff going on is it bad to just have a single updateAllTheSubviews() function and then call that from all the places where the data that powers the screen might change? I'm talking about like filling text in labels, enabling/disable buttons, showing/hiding certain subviews, maybe some Auto Layout, stuff like that. Are there performance issues to consider to the point where I'd really want to focus on making my UI updates more surgically or is it not really a big concern? I'm finding my UI is getting out of sync with my state and just thinking it would be nice to have a single place to definitively (re)draw the screen based on the current data.

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.
I think it's a good idea. If you find any performance issues, fire up Instruments and see what's going on.

I forget if it's still the case but I remember getting some noticeable flickering sometimes when setting a label's text to its current value, so I tend to check if the new string equals the current text before setting.

prom candy
Dec 16, 2005

Only I may dance
Ok great thanks! when I'm building interfaces I really like my UI to be predictable based on the current data so being able to do that helps a lot.

Glimm
Jul 27, 2005

Time is only gonna pass you by

prom candy posted:

If I have a screen with a bunch of stuff going on is it bad to just have a single updateAllTheSubviews() function and then call that from all the places where the data that powers the screen might change? I'm talking about like filling text in labels, enabling/disable buttons, showing/hiding certain subviews, maybe some Auto Layout, stuff like that. Are there performance issues to consider to the point where I'd really want to focus on making my UI updates more surgically or is it not really a big concern? I'm finding my UI is getting out of sync with my state and just thinking it would be nice to have a single place to definitively (re)draw the screen based on the current data.

I think you just invented SwiftUI

:tipshat:

(I agree with pokeyman, it's probably fine and if you do run into performance issues you can probably solve them without adjusting much)

Glimm fucked around with this message at 20:39 on Feb 2, 2021

prom candy
Dec 16, 2005

Only I may dance

Glimm posted:

I think you just invented SwiftUI

:tipshat:

(I agree with pokeyman, it's probably fine and if you do run into performance issues you can probably solve them without adjusting much)

Haha yeah I'm super interested in SwiftUI! This is my first iOS project ever though and I had no say in what we used. Also my understanding is it's still not quite ready for prime time?

Glimm
Jul 27, 2005

Time is only gonna pass you by

prom candy posted:

Haha yeah I'm super interested in SwiftUI! This is my first iOS project ever though and I had no say in what we used. Also my understanding is it's still not quite ready for prime time?

We're using it in an app we shipped recently (very little UIKit) and it is mostly awesome. But there are major pain points that I hope are smoothed out.

Unfortunately for us we will be supporting iOS 13 well after iOS 16 comes out so we probably won't see those things smoothed out for some time :cry:

I wish Combine/SwiftUI were libraries available through SPM and reasonably backported.

prom candy
Dec 16, 2005

Only I may dance
From what I've seen I think it'll be helpful to learn UIKit anyway. I'm having fun working on iOS, starting to think I might want to move my career in this direction. Could be a nice bump in pay.

Centrist Committee
Aug 6, 2019
I wrote a little app in swiftui having no previous Apple developer experience. It’s really nice when it works and swift itself is a very elegant language

prom candy
Dec 16, 2005

Only I may dance
In Swift do I always need to put code inside a completion handler in DispatchQueue.main.async {} or only if the completion handler is doing some kind of background task? Like if I have a view that takes an onButtonClicked property with a completion handler is there a chance that could be fired off the main thread or would I actually need to deliberately start executing code outside the main thread?

Side question: is there a way to avoid nesting completion handlers if I have code that can't execute until they're all done? Do people just use PromiseKit if they have a bunch of async code? I miss async/await

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.

prom candy posted:

In Swift do I always need to put code inside a completion handler in DispatchQueue.main.async {} or only if the completion handler is doing some kind of background task? Like if I have a view that takes an onButtonClicked property with a completion handler is there a chance that could be fired off the main thread or would I actually need to deliberately start executing code outside the main thread?

Side question: is there a way to avoid nesting completion handlers if I have code that can't execute until they're all done? Do people just use PromiseKit if they have a bunch of async code? I miss async/await

You need to touch UI stuff only on the main queue, and you need to make sure your shared state is synchronized somehow (e.g. always fiddle with a property on the same serial queue, or use a lock). UIKit stuff (e.g. button tap handler) is always on the main queue unless the documentation says otherwise. Other frameworks (e.g. photos, or the user notifications permission check) can and will call you on an arbitrary queue. Usually it's documented, but if it isn't then you should assume the worst. And of course if you dispatch work yourself on to a background queue, you'll often need to dispatch back to the main queue to handle the result.

It used to be fashionable to decide whether to dispatch or call immediately by checking the current queue, but it's a bad idea. I'm also pretty sure the relevant methods are deprecated and/or unavailable in Swift.

When I'm writing code that takes a completion block, I tend to go out of my way to call the completion on the main queue. Avoids hard-to-find bugs if I fiddle with UI from the completion block without checking.

PromiseKit is alright, pretty good if you're used to JavaScript promises and pretty opaque if you aren't. I tend to use it, or something like it, in larger projects. If Combine is an option you could try that, otherwise yeah it's nested blocks all day.

Also don't forget about the Thread Sanitizer and Main Thread Sanitizer, which catch some concurrency issues. I leave the latter on at all times.

prom candy
Dec 16, 2005

Only I may dance
Cool, thanks! I'll check out Combine and the thread sanitizer stuff.

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.
I should add that I've done nothing with Combine, it just sits in the "rx-like async thing" bucket in my head, so that might have been a terrible suggestion. But I'm sure others here can help if you get stuck.

brand engager
Mar 23, 2011

Did they add a way to chain async stuff in combine yet? Last I checked Future looked like the closest thing to a Promisekit promise, but it didn't look like you could chain futures.

Lumpy
Apr 26, 2002

La! La! La! Laaaa!



College Slice
So at work, we recently got this email:

quote:

Your Distribution Certificate will no longer be valid in 30 days. To generate a new certificate, sign in and visit Certificates, Identifiers & Profiles.

I am Admin on the team, so I assume I will be able to do this. Could someone explain like I'm an idiot (which I am) how to renew or do whatever I need to do? The original cert was created by someone else who is no longer around. Apple gives me lots of confusing links and conflicting info. I remember tis always being something that was baffling as all hell as well when I used to do iOS stuff a while back.

Glimm
Jul 27, 2005

Time is only gonna pass you by

brand engager posted:

Did they add a way to chain async stuff in combine yet? Last I checked Future looked like the closest thing to a Promisekit promise, but it didn't look like you could chain futures.

You can chain things with Combine, just like Rx. You might have to `.eraseToAnyPublisher()` your future to make it play nicely with your other publishers though (this is very common when using Combine).

I like Combine a lot, but I like Rx a lot too.

Glimm
Jul 27, 2005

Time is only gonna pass you by

Lumpy posted:

So at work, we recently got this email:


I am Admin on the team, so I assume I will be able to do this. Could someone explain like I'm an idiot (which I am) how to renew or do whatever I need to do? The original cert was created by someone else who is no longer around. Apple gives me lots of confusing links and conflicting info. I remember tis always being something that was baffling as all hell as well when I used to do iOS stuff a while back.

The nice thing is that this isn't especially urgent unless you're planning to ship, not having a valid distribution certificate doesn't disable your live application or anything.

You can make a new distribution cert on the dev site:
https://developer.apple.com/

Go into your account, "Certificates, IDs & Profiles", Certificates, hit the +, you probably want "Apple Distribution", then follow the prompts.

I believe Xcode will do this for you as well if you go through the Preferences, Accounts interface (or maybe just by virtue or selecting automatic code signing?) I'm not 100% sure.

Lumpy
Apr 26, 2002

La! La! La! Laaaa!



College Slice
/\ Thanks for the info! Got me started, which leads to question number two:

So it used to be I had to do a dance with making .p12 files and using that to make an iOS distribution cert. It seems now I just make a generic "Apple Distribution" in XCode, and there are no more p12 files involved? Since this app is set to use Fastlane and github actions, it has stuff about the p12 file in the Fastfile. Fastlane's docs are showing XCode 8 screens and so forth, and I'm not really sure what to do to switch over to a p12-less way of doing things if that is what I am supposed to do. Would I just replace this:

code:
   import_certificate(
      certificate_path: "./Code Signing/my-file.p12",
      certificate_password: ENV["CERTIFICATE_PASSWORD"],
      keychain_name: "SOME_NAME",
      keychain_password: "SOME_PASSWORD"
    )
with:
code:
   import_certificate(
      certificate_path: "./Code Signing/cert-xcode-made-and-i-downloaded.cer",
      keychain_name: "SOME_NAME",
      keychain_password: "SOME_PASSWORD"
    )

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed
You can still shove the new certs in a p12 file. AFAICT the only difference is that it's a single cert for all platforms rather than one per platform.

KidDynamite
Feb 11, 2005

if you're already using fastlane why not use match to handle all the cert stuff for you?

perfect time to do it since current are expiring.

Lumpy
Apr 26, 2002

La! La! La! Laaaa!



College Slice

KidDynamite posted:

if you're already using fastlane why not use match to handle all the cert stuff for you?

perfect time to do it since current are expiring.

I guess I can do that. I didn't know what Fastlane was a couple days ago, so I'm open to suggestions. The way it was set up is that when you push to a branch, it builds an app that is released on Testflight and when you merge into master, it creates a build you can then select in the app portal website thingy. Will that match thing work with that?

KidDynamite
Feb 11, 2005

Lumpy posted:

I guess I can do that. I didn't know what Fastlane was a couple days ago, so I'm open to suggestions. The way it was set up is that when you push to a branch, it builds an app that is released on Testflight and when you merge into master, it creates a build you can then select in the app portal website thingy. Will that match thing work with that?

Yeah generally you have match run before the build step(gym line in your Fastfile) to sync certificates or make new ones if need be. Video is from one of the fastlane devs(THE fastlane dev?) and will do a way better job of explaining the whole process than I could. If you have any questions drop ‘em in here and I can help.

https://youtu.be/6Jz-Ywxki0U

awesomeolion
Nov 5, 2007

"Hi, I'm awesomeolion."

SpriteKit question here

https://i.imgur.com/fluwiHk.mp4

Here's what my scene looks like at the moment. The bottom sprite has this weird refresh line looking thing going on and I'm not sure what the cause might be. Any ideas or what you even call this so I can Google for it would be much appreciated :)

awesomeolion fucked around with this message at 18:14 on Feb 8, 2021

Doc Block
Apr 15, 2003
Fun Shoe
So that sprite is just a texture? How are you drawing it? etc. etc. etc.

There's a lot of stuff it could be, depending on how you're doing the drawing.

It could also be a bug in SpriteKit.

awesomeolion
Nov 5, 2007

"Hi, I'm awesomeolion."

Doc Block posted:

So that sprite is just a texture? How are you drawing it? etc. etc. etc.

There's a lot of stuff it could be, depending on how you're doing the drawing.

It could also be a bug in SpriteKit.

Not sure which parts are important so I'll explain below what I did from start to finish. Also here's a gist of the code that does the scrolling.

1. Exported 1x, 2x, 3x png files
2. Made a new image asset in Assets.xcassets
3. Dragged my pngs from finder onto the new image asset
4. Do this for each of my 6 images that make up my repeating background
5. Create an SKSpriteNode using SKSpriteNode(imageNamed:) for each image
6. Position current and next SKSpriteNode
7. Update the position of current and next each frame
8. When current is off screen and set current to next, set next to the following SKSpriteNode (see gist for implementation)

Thanks!

Doc Block
Apr 15, 2003
Fun Shoe
It looks like a clipping problem, so I would make sure your code that figures out the size of the sprite, its position, and whether or not it's on screen is actually doing what you think it does.

Is there a reason you have the max X and Y values set to be the center of the frame? What is the anchor point of each sprite?

Where is node.minX and friends coming from in isOffscreen()? The docs don't show SKSpriteNode or SKNode having those.

Glimm
Jul 27, 2005

Time is only gonna pass you by

Does anyone use Applanga or a similar tool to handle translations? Any thoughts on it?

I saw a demo from them recently and like most marketing demos it looked a little too good to be true, but still probably useful.

KidDynamite
Feb 11, 2005

is anyone familiar with jamf? i signed our app with a new cert and some of our devices are popping an untrusted developer error. which is driving me bonkers that it's only some devices and of course with jamf locking them down they can not simply trust the cert in settings. is there something IT needs to do in jamf with the new cert?

edit: updating the devices to ios 14.2 worked????

KidDynamite fucked around with this message at 20:37 on Feb 11, 2021

prom candy
Dec 16, 2005

Only I may dance
Hey here's a can of worms: thoughts on the best ways to deal with global state? We're using CoreData as kind of a global state store right now but having stuff persist actually kind of sucks and gets in the way for us. I'm thinking about stuff like the currentUser object, or data such as Authors and Books that are managed in lots of different ViewControllers.

Doc Block
Apr 15, 2003
Fun Shoe
Haven’t worked on a new app in a while, but isn’t the idiomatic way to either
A)stuff it in your AppDelegate
B)make your own singleton and put it in there

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.

prom candy posted:

Hey here's a can of worms: thoughts on the best ways to deal with global state? We're using CoreData as kind of a global state store right now but having stuff persist actually kind of sucks and gets in the way for us. I'm thinking about stuff like the currentUser object, or data such as Authors and Books that are managed in lots of different ViewControllers.

Generally you make global instances, then either pass them to initializers/methods (sometimes easier for testing) or refer to them directly (more convenient). Your app delegate is a sometimes convenient singleton created for you, so it used to be fashionable to dangle all your singletons off your app delegate, but I think that's no longer en vogue? Just changes the spelling really.

Swift's type inference means you can do some nice things like extend your User type with a
static var current: User { MySingleton.instance.currentUser }
or similar, then at call sites you can do
showProfile(user: .current).

What about Core Data/persistence is getting in the way?

Glimm
Jul 27, 2005

Time is only gonna pass you by

I'd be wary of using the AppDelegate in a UISceneDelegate (multi-window app) world. The user may have selected different modalities in each window of the app.

Typically we use constructor based dependency injection and pass our data layer around to the ViewModels that need to access the data.

A nice thing about this over singletons and the like is you can do fancy stuff while debugging like throw your non-tab based app in a tab view and put a different user in each tab, ex: a turn-based game app, log in as multiple users on one device and play against yourself. This is a bit contrived but it is useful imo and not terribly difficult to avoid singletons if you design things such that you can pass the data layer (or small slices of it specific to each component) to the types that require it.

awesomeolion
Nov 5, 2007

"Hi, I'm awesomeolion."

Doc Block posted:

It looks like a clipping problem, so I would make sure your code that figures out the size of the sprite, its position, and whether or not it's on screen is actually doing what you think it does.

Is there a reason you have the max X and Y values set to be the center of the frame? What is the anchor point of each sprite?

Where is node.minX and friends coming from in isOffscreen()? The docs don't show SKSpriteNode or SKNode having those.

Thanks again for your thoughts! Those are extension I made for some dubious amount of convenience haha. Anyway I tested a bunch of different combinations and was able to find a solution. When every node is the same zPosition I get the weird clipping behavior. When every node is on a different zPosition then I no longer get the clipping. I'm able to replicate the issue and fix it repeatedly by switching just the zPositions so I'm pretty sure it was the issue. Yay!

Doc Block
Apr 15, 2003
Fun Shoe
Weird that SpriteKit does that instead of just using Z as the draw sorting order like other 2D engines do.

prom candy
Dec 16, 2005

Only I may dance

pokeyman posted:

What about Core Data/persistence is getting in the way?

Mainly there's just stale data in there and it's almost worse to have that vs. just having nothing at all. Plus it seems like all the calls have to be async and that just adds a lot of extra boilerplate/indenting (thus my question about promises earlier this week)

Glimm posted:

I'd be wary of using the AppDelegate in a UISceneDelegate (multi-window app) world. The user may have selected different modalities in each window of the app.

Typically we use constructor based dependency injection and pass our data layer around to the ViewModels that need to access the data.

A nice thing about this over singletons and the like is you can do fancy stuff while debugging like throw your non-tab based app in a tab view and put a different user in each tab, ex: a turn-based game app, log in as multiple users on one device and play against yourself. This is a bit contrived but it is useful imo and not terribly difficult to avoid singletons if you design things such that you can pass the data layer (or small slices of it specific to each component) to the types that require it.

This project isn't using ViewModels at all and is mostly powered by a handful of really big view controllers. I don't want to slag off the contractor that we're working with because this is my first iOS/Swift project and he's been doing this since 2010 or so and I've learned a ton about iOS working with him but he just has a higher tolerance for like 1000-line classes that do a whole lot of stuff than I do.

That approach sounds interesting though, so essentially your ViewModel or VC has an initializer where you pass in the currentUser? Do you then save that as an instance variable within the class? If so how do you keep that in sync? The instance var would be a copy and not a direct reference, right?

Adbot
ADBOT LOVES YOU

awesomeolion
Nov 5, 2007

"Hi, I'm awesomeolion."

Doc Block posted:

Weird that SpriteKit does that instead of just using Z as the draw sorting order like other 2D engines do.

My guess is that there's some Spritekit bug related to figuring out a reasonable drawing order when sprites on the same z position.

I've now run full speed into the next issue... spawning obstacles on a timer and dropping my frame rate from 60 to 8 to freezing. So far my impression of going from Unity to SpriteKit is that it's very foot-gun-y. Which I guess makes sense because Unity is pretty idiot-proof. Anyways, something to debug next time!

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