Since this was such a major obstacle for me, I thought I'd share my solution of how to recognize a touch and hold. No sense in others suffering like I did!
In one of the posts I made on these forums asking for help figuring out how to recognize a touch and hold, someone suggested storing the touch in a variable, starting a timer, and then examining the current touch and comparing it to the initial touch. A sound suggestion, except for the last part. As it turns out, I don't think reviewing the current touch is possible when you're talking about doing so outside of the touch event methods (touchesBegan, touchesMoved, and touchesEnded).
Instead, this is the approach I took - which is now working perfectly.
1) In my header file for the class that this code is running in (a UIViewController in my case), I've declared an NSTimer called "touchTimer" and synthesized it in the corresponding implementation file. That, of course, makes it a variable that is accessible across multiple methods in the implementation file.
2) In the touchesBegan event method add the timer to the run loop or call a method that will do so.
Code:
touchTimer = [NSTimer scheduledTimerWithTimeInterval:delay target:self selector:@selector(touchHasBeenHeld:) userInfo:nil repeats:NO];
3) In the "touchHasBeenHeld" method that is called when the timer fires, do whatever you like to have happen when the touch has been held. However, after that functionality you'll need to invalidate the timer if it's currently valid and re-add the timer to the run loop.
Code:
touchTimer = [NSTimer scheduledTimerWithTimeInterval:delay target:self selector:@selector(touchHasBeenHeld:) userInfo:nil repeats:NO];
if ([touchTimer isValid]) [touchTimer invalidate];
That might seem odd to do... I mean, the code that's running here is in a method that is called when the timer fires (at which point the timer should not be valid). And why re-add it to the run loop? If you don't, you'll find that your application will lock up when you touch and hold and then move. I'm not sure I understand exactly why myself.
4) This one is probably obvious if you've read up to this point. In both the touchesMoved and touchesEnded event methods you'll need to invalidate the timer if it's currently valid. In the touchesMoved method, you'll also need to re-add the timer to the run loop just like you did inside the method that the timer triggers. Again, it doesn't really make sense to me just yet... but it prevents the app from locking up when you touch and move. This is not necessary to do in the touchesEnded event method.
Right now I've got a UILabel that I put text into when the touch starts, when it moves, when it ends, and when it's been held for a set number of seconds. And it works flawlessly!
Hope that helps someone out there
-Toryn