Let's start with a formal definition:
To be honest, this is not really clear: what is Inversion of Control? Why is it useful for resolving dependencies?
In procedural programming, each object interacts with all of its collaborators in a direct way and also instantiates them directly. In Inversion Of Control, this flow is managed by a third party, usually, a framework that calls the objects and receives notifications.
An example of this is an implementation of a UI engine. In a UI Engine, there are two parts: the Views and the Models part. The Views part handles all the interaction with the users, such as tapping buttons and rendering labels, whereas the Models part is responsible for business logic. Usually, the application code goes in the Models part, and the connections with the Views are done via callbacks that are called by the engine when the user interacts with a button or a text field. The paradigm changes from an imperative style where the algorithm is a sequence of actions, like in do this then do that, to an event style, when the button is tapped then call the server. The control of the actions is thus inverted. Instead of being the model that does things, the model now receives calls.
The essence of this principle is, "Don't call us, we'll call you," which is a response you might hear after auditioning for a role in Hollywood.
In procedural programming, the flow of the program is determined by the modules that are statically connected together: ContactsView talks to ContactsCoreData and ContactsProductionRemoteService, and each object instantiate its next collaborator.
In Inversion of Control, ContactsView talks to a generic ContactsStore and a generic ContactsRemoteService whose concrete implementation could change depending on the context. If it is during the tests, an important role is played by the entity that manages how to create and connect all the objects together.
Martin Fowler, in his 2004 article https://martinfowler.com/articles/Injection.html about IoC, says that it can be reached with patterns such as ServiceLocator or Dependency Injection, but it can also be done with a Template Pattern or a Strategy Pattern.
After having defined the concept of IoC, let's give a simpler definition of DI:
The first principle of the book Design Patterns by the Gang of Four (https://www.artima.com/lejava/articles/designprinciples.html), is "Program to an interface, not an implementation" which means that the objects need to know each other only by their interface and not by their implementation.
After having defined how all the classes in software will collaborate with each other, this collaboration can be designed as a graph. The graph could be implemented connecting together the actual implementation of the classes, but following the first principle mentioned previously, we can do it using the interfaces of the same objects: the Dependency Injection is a way of building this graph passing the concrete classes to the objects.