I played with NSTimer and CVDisplayLink a long time ago and I did not like them. A better way, in my opinion, would be to make a "traditional" game loop with a simple while - no timers and no callbacks.
You use Vsync to avoid burning cpu cycles.
Basically this in pseudo-code:
loop {
UpdateGame();
CallOpenGLStuff();
NSOpenGLContext#flushBuffer();
}
The flushBuffer call would then block until Vsync - and immediately after start over the loop. As you can see no need for callbacks. I think it is much simpler.
If you like the sound of this and want to investigate further, I can recommend you read the source code for GLFW
https://github.com/glfw/glfw - check out the OSX adapter.
By the way, this advice only applies to OSX and not necessarily iOS.