Few things to take into account

### Missleading names

> Then I'd make a function called `User.update()` that just pulls userdata
> from the server and populates the User class properties. This is the
> only function that would be allowed to write over the User properties.

Whoever is familiar with *Active Record* design pattern would be fooled  by the name of the method.

The name could make us belive that we are pushing changes to the server, but in reality -*according to the question*- we would be doing the opposite!!! 

If we are pulling the latest `User`  representation, then we should consider changing  the name of the method for  something like *retrieve* , *refresh* or *reload*. If we are really synchronizing, *sync* would be more acurate than *update*.

### Too many requests

> I would run the `User.update()` function during times such as:
> 
>  - App launch
>  - App re-opened from sleep
>  - Profile update
>  - After in-app-purchase 
>  - etc.

If we need to retrive the `User` so often, it probably means that we shouldn't hold all its state. Or at least not completely.<sup>1</sup>

Ideally, we request the latest data when there's an evidence of changes and we need to be aware of them. For example, after specific business operations.

Otherwise, we come to realise that any *event*|*action*|*moment* is as good as any other. Such randomness, eventually,  lead us to retrieve half DB without consistent reasons. 

*If `App re-opened from sleep` is a good moment for refreshing the `User`,  why shouldn't it be good for any other entity?*

Remember that connections consume resources and they also have an impact on the data plan. So, I would consider  constraining the requests to the essential.

### Caching only the essential

Consider holding the URIs instead of the complete representantion. For example, we could request and hold data that is unlikely to change.

    GET /user/1    HTTP/1.1
    HTTP 200 OK
    {
      "fullname":"Han Solo"
    }

Caching the *fullname* and hold the URIs of those resources sensibles to changes. For example, `/user/1/profile` and `/user/1/score`.

Later, we can retrieve these resources only when the business need them instead of randomly after certain events of the application.

Finally, think who else is going to be changing the `User` beside the user himself. If there's no concurrency over the data, probably the client application always has the most up-to-date representation.

---

<sup>1: What we do with the local storage is caching. If we have to expire the cache often, it means either we don't need cache at all or we are caching the wrong data.</sup>