Usually delay loops are used in unsophisticated programs where a short or rough delay is required. Of course you can make them cycle-perfect by adding a few NOPs or whatever. If the micro will do nothing else other than count a clock and output a square wave, you can count exactly 500,000 cycles with a 4MHz clock (inclusive of the looping and toggling instructions), toggle the output pin and repeat, and the output will be a 1Hz square wave as accurate as the clock (give or take nanosecond jitter) and with 50% duty cycle.
If you want accurate 1-second times, you can also use a timer/counter peripheral, clocked by the system clock, which allows the micro to do something else other than counting. Many PICs also have a secondary oscillator input which can work with (say) a 32,768Hz watch crystal, allowing an inaccurate clock such as the internal RC to be used for the system clock. If the counter/timer is programmed to toggle the output pin directly, the micro can be used for other purposes than just counting, and need only return to set up the next compare value before the next comparison would come due. Again the output will be about as accurate as the input clock frequency to the counter. Some have a real time counter peripheral that does the counting for you.
If you don't care too much about a bit of jitter (but frequency can still be bang-on) you can trigger periodic interrupts and count those. For example, if you had interrupts every 2ms you could simply count (in the interrupt service routine) to 250, then toggle the output, and reset the counter. Since the ISR can take varying amounts of time on some micros to begin (depending on what it was doing when it was interrupted) and for other reasons there can be a bit of jitter in this approach (some instruction cycles).
I lied a bit when I implied that the micro could do nothing else if it was counting cycles- it's possible (but rather tedious) to craft assembler code that is isochronous - it takes exactly the same number of cycles to execute no matter which branch is taken- so that useful things can be accomplished within a delay. It's not really a nice thing to have to do.
Any of these methods may be "correct" for a given purpose.