Post

Replies

Boosts

Views

Activity

Reply to Swift user online status updates but it repeats on cells that is not supposed to
Glad it’s working, but this still seems vulnerable to the original problem. The completion handler still captures and updates the cell you are setting up (hCell) but if the handler actually runs after any appreciable time delay, then the captured hCell may not refer to the cell you want. Also, what’s up with the members.isEmpty check? Sounds like members is your data model, so if it’s empty, then why are there any cells being displayed at all? Or if members being empty means you are displaying a placeholder cell (e.g. “Sorry, you have no friends.”) then maybe you want to check earlier and dequeue a cell with a different identifier that is specially designed for this case.
Topic: Programming Languages SubTopic: Swift Tags:
Jan ’23
Reply to Swift user online status updates but it repeats on cells that is not supposed to
What would such a delegate do? Your onlineViewStatus view (btw, would the name be more clear as onlineStatusView?) seems to be just an “output” via its background color, and doesn’t seem to have any actual behavior that would need to be reported via a delegate back to the view controller. Is this correct? Try to make the cell behavior as simple as possible: you have an image, a name, and a view that shows online status. You already get the image and name from the Member object which is passed to the cell during configuration. Similarly, now you’ll want to pass the online status to the cell when you receive it, and then the cell just sets the color. Then the cell class becomes extremely simple. The fun starts at “pass the online status to the cell when you receive it.” So the view controller would launch async operation(s) to fetch everyone’s online status, and then updates the cell for each member when that member’s online status is received. The best way to do this is to build your table using a diffable data source. (If you’re not already using this, I strongly recommend it. It makes things much easier.) Then you use the diffable data source snapshot to tell the table to redraw the cells that need updating.
Topic: Programming Languages SubTopic: Swift Tags:
Jan ’23
Reply to Swift user online status updates but it repeats on cells that is not supposed to
I suspect a race condition due to using async operations to set up the cell. If getDocuments() is async, then the completion handler may be called after the cell has already appeared on screen, scrolled away, and even been reused for a different member that has scrolled onscreen. If that happens, the completion handler’s capture of self refers to the reused cell, which no longer represents the original member. (And the snapshot listener could cause an extreme case of this, if a snapshot update could happen a long time after you create it.) You could try to work around this by saving the Member or its documentId in each cell and checking it in the completion handler to make sure it matches, but it’s still not a great solution. This cell setup code will get called a lot as you scroll and it’s best to keep it fast and avoid redundant work. Can you do all this async work in your view controller or view model before you show the table? And then update the table when you receive changes.
Topic: Programming Languages SubTopic: Swift Tags:
Jan ’23
Reply to WeatherKit Timedate not showing local time
That looks correct. All those timestamps are in UTC (note the “Z” at the end, which means UTC) so they should be 11 hours behind your local time. If presenting them in your user interface, you’ll need to use a date formatter with the time zone set correctly. You did specify your local time zone in the request URL, but the API doc says that’s for determining day boundaries for daily forecasts. Looks like all timestamps in responses will still be in UTC.
Topic: App & System Services SubTopic: General Tags:
Jan ’23
Reply to how can i make my async func wait
In your verif() function, the async geocoding is inside a Task block, but below that block you have code that depends on the result of the geocoding. That won’t work. The code after the task block executes immediately after the task is started, which is before the geocoding inside the task completes. To make this work, your code that needs the geocoding result (specifically the checkAddress() call) needs to be inside the task block. Then it will run after the geocoding instead of before it. So basically your entire verif() function needs to be async. And since you call verif() from within a Task block, you don’t need another Task block inside verif(). Try removing that and changing the declaration like this: func verif() async -> Bool { ...and then call it like this: Task { @MainActor in if await verif() { // ...handle success... } else { // ...handle failure... } } Also, note you can optimize the logic a bit. It appears you don’t even need the geocoding result unless the checkCP() test returns false. So it may be helpful to not do the geocoding until you actually need it.
Topic: Programming Languages SubTopic: Swift Tags:
Jan ’23
Reply to how can i make my async func wait
If you declare a function as async then it should not use a completion handler. That’s the whole point of Swift concurrency: it takes over control of delivering results asynchronously so you don’t have to explicitly. So the proper declaration (with the result type adjusted) would be like this: func getLatLongFromAddress(_ address: String) async throws -> CLLocationCoordinate2D { As an async function there’s no completion handler. Instead, the task simply pauses until the function returns a result. And throws is needed because that’s how you report any error from the underlying geocoding operation, which may throw an error. Then to implement this, it’s easiest to use the async (no completion handler) version of the geocode API. That works like this: let geocoder = CLGeocoder() let placemarks = try await geocoder.geocodeAddressString(address) let location = placemarks[0].location // for now we’ll assume [0] always exists return location!.coordinate // for now we’ll assume the coordinate always exists Then to call this function from a button handler, you need to call it from a Task block (because it’s async) and you should also put it in a do / catch block so you can handle any errors that get thrown during the geocoding.
Topic: Programming Languages SubTopic: Swift Tags:
Dec ’22
Reply to cancel the async and make it run normally
That link from @Claude31 is very, very well worth reading. Then some further thoughts on this: completionHandler: @escaping (Double) -> Void It’s better to use type CLLocationDegrees rather than Double. They are actually the same (via typealias) but using CLLocationDegrees is much more clear to someone reading the code. But with that said, I’d suggest you change to result type to CLLocationCoordinate2D (lat + long) or even CLLocation (coordinates plus other information). Why? Because... Your other post mentions you have an equivalent getLongFromAddress method. That’s not a good idea if you actually need both coordinates, since both call geocodeAddressFromString which is async and relatively slow. Instead you should have a single (say) getLocationFromAddress to get both the latitude and longitude together. If in any any specific call you need only one of them, then that’s fine. So if you changed the completion handler to this... completionHandler: @escaping (CLLocationCoordinate2D) -> Void ...there’s still a problem: this doesn’t handle any error from the underlying geocodeAddressFromString call. The early return means the caller of your method never finds out if there was an error and can’t do anything about it. Any completion handler like this should report both success (with a result) and failure (with an error). If you follow the style used by geocodeAddressFromString then your completion handler would look like this: completionHandler: @escaping (CLLocationCoordinate2D?, Error?) -> Void That’s fine, though there is a newer convention for implementing this sort of “either result or error” completion handler, using the Result type: completionHandler: @escaping (Result<CLLocationCoordinate2D, Error>) -> Void And going further, as Claude said you can convert all of this to the modern async / await pattern, but I think that’s a topic for a bit later.
Topic: Programming Languages SubTopic: Swift Tags:
Dec ’22