はじめに
UITableViewCellのように「画像とテキスト」を並べたい場合、attributedTitleForRowを使う方法と、viewForRowを使う方法のいずれを採用すべきか。

結論
横並びの場合、attributedTitleForRowで済ませたほうが実装の簡潔さになります。
これに対して、テキストの上下に画像が配置されるなどレイアウトが複雑になる場合は、viewForRowを使う必要があります。
余談: delegateのメソッドが呼ばれる順番
ところで、UIPickerView delegateのメソッドが呼ばれる順番はどうだったでしょうか。
1. widthForComponent
まず、ローの高さよりも先に幅を指定するメソッドが呼ばれます。
func pickerView(_ pickerView: UIPickerView,
widthForComponent component: Int) -> CGFloat
2. rowHeightForComponent
次に、高さです。ここでは、確定したwidthを利用できます。
func pickerView(_ pickerView: UIPickerView,
rowHeightForComponent component: Int) -> CGFloat
3. titleForRowなど
実際にローに表示する中身を指定するメソッドが呼ばれます。
3種類ありますが、仮に3つが実装されている場合は、viewForRow > attributedTitleForRow > titleForRow の順番で優先されます。
特にどのメソッドを使うかを指定する必要はありません。コードを書くだけで、優先度の高いメソッドが呼ばれます。
func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView
func pickerView(_ pickerView: UIPickerView, attributedTitleForRow row: Int, forComponent component: Int) -> NSAttributedString?
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String?
viewForRowを実装した場合は、attributedTitleForRow以下は無視されます。
attributedTitleForRowとtitleForRowを実装している場合、attributedTitleForRowのreturn がnilのときは、titleForRowが呼ばれます。
関連
UIPickerViewDelegate Reference
実装例 StringPickerPopover.swift