Passing data via $rootScope is basically like having objects in a global namespace, to which everyone has access. This can lead to problems where you don't know what changed your data.
The Shared Service (i.e. a singleton object) is better as you have control over access to the data within the service and also components must request to have the service injected into them so it is easier to see who is messing with the data.
The event strategy, is a different idea, where your component can raise events that may or may not be handled by someone else. It provides nice independence between components but doesn't provide a clear central data source - although this can be achieved with a service that exposes events. It is true that the scope is used to pass events (broadcast down the tree, emit up the tree) but this is simply a transport mechanism rather than using the scope as a global dumping ground for all your data. By the way, to get events to go to everyone you broadcast them from the rootScope.