Я не знаю , почему ваш текст повторяется.Я бы предположил , что это связано с заменой символов в диапазоне, в то время как функция также заменяет символы в диапазоне (диапазон заменяется дважды, таким образом, двойной текст).
Однако я бы не стал использовать метод shouldChangeTextIn для того, что вы пытаетесь сделать.Почему бы просто не заменить textView.text по нажатию кнопки ??
buttonAction() {
textView.attributedText = // bolded text
}