Imagine a chip that senses some external condition that you don't know when it will occur. Let's say, for example, that the IIC chip does some external communication to some other device. That other device occasionally sends messages, but you don't know when.
With IIC being the only interface to this chip, the only way to know whether the external device sent a message is to poll the chip. That could use up a lot of IIC bus bandwidth, especially if you need to read the message with low latency.
In cases like this, the chip may provide a additional output that you can use if you want to. You can connect this to a separate digital input of the microcontroller. Now you don't have to send a IIC read message just to find out the IIC chip has nothing new for you. Instead you simply check the extra dedicated input.
You can take this a step further, which is to use interrupts. In the above case, the firmware is still regularly checking the dedicated input from the IIC chip. That's simpler and faster than doing a IIC read to see if the chip has something for you, but still requires active checking. The solution is to connect the signal from the IIC chip to a interrupt input of the micro. Now the foreground code doesn't have to do any checking at all. The interrupt routine runs only when the IIC chip has new data for you.
With something as relatively slow as IIC, it gets more complicated than that. You may not want to do the entire IIC transaction in the interrupt routine to avoid long latency in servicing other interrupts. You now also have to consider how to deal with foreground code using the IIC bus when the interrupt triggers. In the end, polling the dedicated line from the IIC chip in a separate task, then then does the IIC transfers when there is data might be the best firmware architecture. The polling loop includes a way to let other tasks run when there is no new data before going back and checking again.