The main problem with dependency injection is that, while it gives the apparience of a loosely coupled architecture, it really isn't.
What you're really doing is moving that coupling from the compile time to the runtime, but still if class A needs some interface B to work, an instance of a class which implements interface B needs still to be provided.
Dependency injection should only be used for the parts of the application that need to be changed dynamically without recompiling the base code.
Uses that I've seen useful for an Inversion of Control pattern:
- A plugin architecture. So by making the right entry points you can define the contract for the service that must be provided.
- Workflow-like architecture. Where you can connect several components dynamically connecting the output of a component to the input of another one.
- Per-client application. Let's say you have various clients which pays for a set of "features" of your project. By using dependency injection you can easily provide just the core components and some "added" components which provide just the features the client have paid.
- Translation. Although is not ususually done for translation purposes, you can "inject" different language files as needed by the application. That includes RTL or LTR user interfaces as needed.