It is possible to stroke arbitrary paths with a gradient, or any other fill effect, such as a pattern.
As you have found, stroked paths are not rendered with the current gradient. Only filed paths use the gradient (when you turn them in to a clip and then draw the gradient).
However, Core Graphics has a call
CGContextReplacePathWithStrokedPath that will transform the path you intend to stroke in to a path that is equivalent when filled.
Behind the scenes,
CGContextReplacePathWithStrokedPath builds up an edge polygon around your stroke path and switches that for the path you have defined. I'd speculate that the Core Graphics rendering engine probably does this anyway in calls to
Here's Apple's documentation on this:
Quartz creates a stroked path using the parameters of the current graphics context. The new path is created so that filling it draws the same pixels as stroking the original path. You can use this path in the same way you use the path of any context. For example, you can clip to the stroked version of a path by calling this function followed by a call to the function CGContextClip.
So, convert your path in to something you can fill, turn that in to a clip, and then draw your gradient. The effect will be as if you had stroked the path with the gradient.
Your code will look something like this…
const CGContextRef context = UIGraphicsGetCurrentContext();
// Define your stroked path. You can set up anything you like
// Set up any stroking parameters like line width (or dashing).
// Use the magic call to create a fillable path.
// Turn the fillable path in to a clipping region.
// Draw the gradient (it will clip to the path).
For additional details see this answer of this S.O. question.