Perhaps you want to append some UIImage into a UITextView similar to iMessage. Here’s an extension method that you can add to your project.

Append an Image to a UITextView

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

import UIKit
extension UITextView {

func addImage(image: UIImage) {

let attachment = NSTextAttachment()

let oldWidth = image.size.width
let scaleFactor = oldWidth / self.frame.size.width - 10

attachment.image = UIImage(CGImage: image.CGImage!, scale:scaleFactor, orientation: UIImageOrientation.Up)

let attributedString = NSAttributedString(attachment: attachment)

let currentMutable = NSMutableAttributedString(attributedString: self.attributedText)
currentMutable.appendAttributedString(attributedString)

self.attributedText = currentMutable
}

}

Get all the Images from a UITextView

If you need to get all the images that were attached, you can add this function to your extension.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
func getImages() -> [UIImage]{
var images = [UIImage]()
let attributedString = self.attributedText

attributedString.enumerateAttribute(NSAttachmentAttributeName, inRange: NSMakeRange(0, attributedString.length), options: NSAttributedStringEnumerationOptions(rawValue: 0)) { (value, range, stop) in

guard let attachment = value as? NSTextAttachment else { return }

if let image = attachment.image {
images.append(image)
}else if let image = attachment.imageForBounds(attachment.bounds, textContainer: nil, characterIndex: range.location) {
images.append(image)
}
}
return images
}

Getting String and UIImage as parts from a UITextView

Say you need to create some sort of way to send up data from your UITextView in parts. Think iMessage. You can add this function getParts() which will return you an array [AnyObject] ordered with UIImage or String as parts. It even strips out whitespaces by trimming them incase your user decided to start with a space before typing.

extension UITextView {
    func getParts() -> [AnyObject] {
            var parts = [AnyObject]()

            let attributedString = self.attributedText
            let range = NSMakeRange(0, attributedString.length)
            attributedString.enumerateAttributesInRange(range, options: NSAttributedStringEnumerationOptions(rawValue: 0)) { (object, range, stop) in

                if object.keys.contains(NSAttachmentAttributeName) {
                    if let attachment = object[NSAttachmentAttributeName] as? NSTextAttachment {
                        if let image = attachment.image {
                            parts.append(image)
                        }else if let image = attachment.imageForBounds(attachment.bounds, textContainer: nil, characterIndex: range.location) {
                            parts.append(image)
                        }
                    }
                }else {
                    let stringValue : String = attributedString.attributedSubstringFromRange(range).string
                    if !stringValue.isEmptyOrWhitespace() {
                        parts.append(stringValue)
                    }
                }
            }


            return parts
    }
}