Chapter 15 - Subscribing to an external publisher

Hi, I’m doing the excersices related with this chapter, I’ve found that either following the book’s code or opening the final project the ´onReceive´ method is not being triggered

I had the same issue. I fixed it by moving the “.onReceive” up one level - right after “.padding()”. I don’t know why it doesn’t work modifying the “ForEach” but does work modifying the “VStack” though. I have found that SwiftUI’s listing types (ForEach, List, etc.) tend to be a little finicky sometimes.

1 Like

Right, doing this the onReceive is called, but it’s receiving an event n times, where n is the number or rows in the List and in this case is calling n times to self.currentDate = $0

I tried moving it down a level after the List view, but that doesn’t work either. It looks like it needs to stay inside the ForEach. This actually makes sense though - there’s a separate last-update time for each row in the ForEach that needs to get updated.

I have not entirely pinned down the difference between the type of Views that are returned, but I believe that there must have been a change in XCode recently that broke it. Certain “display” elements allow the onReceive to fire, while the other “layout” elements do not. NavigationView and VStack (interestingly VStack, but not sure why) are display elements that are subscribing to the publisher it seems.

If you want to test this out, add a Text(“Anything”) before Section() and put the onReceive on that view (or even the Text() view that is the header for the Section() view) and you will see it only fire one time per timer cycle.

Also, there should not be a separate last update time for each row. The row is taking in a time from when the view was last updated, and using that to dynamically generate the … minutes ago. By calling it n times we are actually forcing the layout to re-render that many times, which is less ideal for performance. If I find out why these “layout” elements are not subscribing (and therefore, receiving the events) I will report back here

Run into the same issue and put the ‘onReceive’ one level up to the ‘VStack’. Assuming only Views can be subscribers of publisher events. ‘ForEach’ and Lists are not really Views…

Thanks everyone for chiming in on this issue - the behavior must’ve changed a bit in recent iOS updates. We’ll make sure to address this in the next book update :+1:t3:

I have encountered the same problem. Probably, it is due to some internal behavior of SwiftUI. But I could not figure it out the reason why.

The problem I saw, timer gets subscribed twice and cancelled once when you put .onReceive there. When you move it outer space, it is not cancelled and it starts working.

I’m trying this on Xcode12 beta6 and it seems to be behaving correctly - leaving the app open would every minute update the “X min ago” labels on each row. Could y’all try it again and let me know if you still find something behaving incorrectly?

@miibpa @psoybean @bhaze2263 @afrank @serhatsahin Do you still have issues with this?