I am working on an app that will sync data between users through a server that I control. Currently, I am recording the UTC time of changes on each device, which then helps
Absolutely you cannot rely on the iOS device clock being correct. The user can set them to whatever they like, and does not have to synchronize with a time server.
When doing a sync, you could begin the process by obtaining the device's view of the current time. If this differs from the server's view of the current time, you could then apply this offset to the timestamps of the changes that are being uploaded, to bring them onto 'server time'. Clearly this assumes that the device clock has not been changed during the period in which the changes have been made—that is, it ignores the possibility that some of the changes have the correct time, and some require the offset to be applied.
The safest option would be to keep track of this offset, and see whether it would make any difference in a sync conflict. In any case where it would make a difference, apply the offset, but in any case where it would not affect what was regarded as the latest data, use the unmodified timestamp from the device—so if the user recalls that it was "3:00pm" when they did something, they will still see that event timestamped with 3:00pm. If using any offset calculation, don't forget to ensure that no item should ever be moved forward in time relative to the server to the point that it is being claimed to have occurred in the future. :)
For your purposes, it is best to use a logical clock like http://en.wikipedia.org/wiki/Lamport_timestamps
Do not depend on time being accurate on multiple machines for the core algorithm in a distributed system.
The biggest problem (especially with something like occasionally connected devices), is they can be disconnected for a long time and make many changes. We're not talking about drift here, we're talking potentially about many edits over long periods of time not connected to a server without a reliable time on the device.
If you want an approximation to interleave operations in a system where its not critical (facebook app, not financial), the server could maintain an ever increasing changeId long with every change - sort of a journal of changes applied. Then when the device changes an entity, it records it and references the last changeId it knows about. Writing that entity revision back to the server will cause a new changeId to get logged but the entities revision maintains the changeId when it was written by the device (what determines where it interleaves in the history of the entities writes) and the new server changeId (used when other clients get all revisions since changedId x).
the device can then retrieve all changes since the last changedId it knew about and will get all the entities - it can order revisions when viewing the entities based on the changeId it knew about when it was written.
That means a device thats connected more consistently will win more on writes (interleaved) and devices more occassionally connected will lose more often. But, all revisions will be written - just the latest wins. You could do that at a field or entity level. If at a field level, field changes by different users would effortlessly merge - if that's what you want.
It's an approximate interleaving of distributed revisions which simply interleaves based on your last message with the server.