I need to search some strings and set some attributes prior to merging the strings, so having NSStrings -> Concatenate them -> Make NSAttributedString is not an option, is there any way to concatenate attributedString to another attributedString?
-
18It is ridiculous how difficult this *still* is in August of 2016. – Wedge Martin Aug 12 '16 at 05:10
-
23Even in 2018... – DehMotth Mar 22 '18 at 14:24
-
17still in 2019 ;) – raistlin Feb 28 '19 at 11:03
-
22still in 2020 ... – Hwangho Kim Mar 17 '20 at 05:41
-
3Still in November 2020 ;) – Emon Nov 05 '20 at 09:53
-
9Ah... two weeks before 2021! Merry Christmas all of us ;) – Sapozhnik Ivan Dec 12 '20 at 23:06
-
1Hopefully things change in 2021 ¯\\_(ツ)_/¯ – aheze Jan 17 '21 at 17:09
-
3Still in 2021 March – Alok Vishwakarma Mar 10 '21 at 07:32
-
1Still 2021 April hahha – Jalil May 06 '21 at 19:15
-
1Still 2021 June XD – Mohammad Azam Jun 14 '21 at 15:02
-
1This really is a joke! (Aug 2021) – user139816 Aug 06 '21 at 12:38
-
November 2021, alright this is ridiculous! – Ben Giannis Nov 09 '21 at 16:05
-
2March 2022, the tradition remains – Andrew Mar 28 '22 at 18:37
-
1August 2022, yet... xD – javi_swift Aug 02 '22 at 15:07
-
Mandatory Check In - Nov'2022 it continues..... xD – Ultimate_93 Nov 28 '22 at 17:42
-
and still in Mar 2023 – Fahim Parkar Mar 06 '23 at 06:19
9 Answers
I'd recommend you use a single mutable attributed string a @Linuxios suggested, and here's another example of that:
NSMutableAttributedString *mutableAttString = [[NSMutableAttributedString alloc] init];
NSString *plainString = // ...
NSDictionary *attributes = // ... a dictionary with your attributes.
NSAttributedString *newAttString = [[NSAttributedString alloc] initWithString:plainString attributes:attributes];
[mutableAttString appendAttributedString:newAttString];
However, just for the sake of getting all the options out there, you could also create a single mutable attributed string, made from a formatted NSString containing the input strings already put together. You could then use addAttributes: range:
to add the attributes after the fact to the ranges containing the input strings. I recommend the former way though.

- 129,200
- 40
- 280
- 281
-
1Why do you recommend appending strings instead of adding attributes? – ma11hew28 Aug 08 '17 at 03:45
If you're using Swift, you can just overload the +
operator so that you can concatenate them in the same way you concatenate normal strings:
// concatenate attributed strings
func + (left: NSAttributedString, right: NSAttributedString) -> NSAttributedString
{
let result = NSMutableAttributedString()
result.append(left)
result.append(right)
return result
}
Now you can concatenate them just by adding them:
let helloworld = NSAttributedString(string: "Hello ") + NSAttributedString(string: "World")

- 7,802
- 4
- 31
- 37

- 27,584
- 13
- 78
- 80
-
-
5
-
-
4You can use the mutable subtype in any context that expects the immutable parent type but not vice versa. You may want to review subclassing and inheritance. – algal Nov 15 '15 at 18:25
-
it was sarcasm. again, you should not return mutable subtype in immutable parent context in case of security. It doesn't make sense that you return 'hidden' mutable object in immutable context. Please, review immutable/mutable contexts and purposes of each one – gaussblurinc Nov 15 '15 at 18:32
-
6Yes, you should do a defensive copy if you want to be defensive. (Not sarcasm.) – algal Nov 15 '15 at 18:42
-
1If you really want to return NSAttributedString, then perhaps this would work: `return NSAttributedString(attributedString: result)` – Alex Sep 16 '16 at 10:29
-
Swift 3: result.append(left) - where do you declare such an overload? Is there a standard place where to do it? Seems weird if it's just randomly in the file you just happen to be in... – n13 Nov 12 '16 at 06:23
-
2@n13 I would create a folder called `Helpers` or `Extensions` and put this function in a file named `NSAttributedString+Concatenate.swift`. – David Lawson Nov 20 '16 at 08:55
Swift 3: Simply create a NSMutableAttributedString and append the attributed strings to them.
let mutableAttributedString = NSMutableAttributedString()
let boldAttribute = [
NSFontAttributeName: UIFont(name: "GothamPro-Medium", size: 13)!,
NSForegroundColorAttributeName: Constants.defaultBlackColor
]
let regularAttribute = [
NSFontAttributeName: UIFont(name: "Gotham Pro", size: 13)!,
NSForegroundColorAttributeName: Constants.defaultBlackColor
]
let boldAttributedString = NSAttributedString(string: "Warning: ", attributes: boldAttribute)
let regularAttributedString = NSAttributedString(string: "All tasks within this project will be deleted. If you're sure you want to delete all tasks and this project, type DELETE to confirm.", attributes: regularAttribute)
mutableAttributedString.append(boldAttributedString)
mutableAttributedString.append(regularAttributedString)
descriptionTextView.attributedText = mutableAttributedString
swift5 upd:
let captionAttribute = [
NSAttributedString.Key.font: Font.captionsRegular,
NSAttributedString.Key.foregroundColor: UIColor.appGray
]

- 5,486
- 5
- 41
- 66

- 4,694
- 7
- 54
- 98
Try this:
NSMutableAttributedString* result = [astring1 mutableCopy];
[result appendAttributedString:astring2];
Where astring1
and astring2
are NSAttributedString
s.

- 34,849
- 13
- 91
- 116
-
13
-
@JWWalker your 'oneliner' is corrupted. you can't get this "concatenation" result because appendAttributedString doesn't return string. Same story with dictionaries – gaussblurinc Nov 12 '15 at 13:14
-
@gaussblurinc: good point, of course your criticism also applies to the answer we're commenting on. It should be `NSMutableAttributedString* aString3 = [aString1 mutableCopy]; [aString3 appendAttributedString: aString2];`. – JWWalker Nov 12 '15 at 15:55
-
-
@Linuxios, also, you return `result` as `NSMutableAttributedString`. it is not what author want to see. `stringByAppendingString` - this method will be good – gaussblurinc Nov 12 '15 at 16:57
-
@gaussblurinc: The original post isn't clear enough for us to know that, and I don't really see a problem with this method. – Linuxios Nov 12 '15 at 16:59
-
@Linuxios, `concatenate attributedStrings to another attributedString` <- no word about `mutable` or something else. Also, author said about `merge` two strings to get `NSAttributedString` ( not an option in case of lost attributes ). So, concatenate `attributesStrings` and get `NSAttributedString` – gaussblurinc Nov 12 '15 at 17:05
-
@gaussblurinc: Unless I'm misunderstanding inheritance in Obj-c, a mutable attributed string can be used anywhere a normal one can. – Linuxios Nov 12 '15 at 17:09
-
@Linuxios this means that your approach has potential problems in security/stability. Immutable objects are better, because they can't be changed by third-party person. For example, all properties of NSString type should be have copy attribute, because they should not be changed by anyone who has a pointer to them. – gaussblurinc Nov 12 '15 at 18:22
-
Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/94962/discussion-between-linuxios-and-gaussblurinc). – Linuxios Nov 12 '15 at 18:23
2020 | SWIFT 5.1:
You're able to add 2 NSMutableAttributedString
by the following way:
let concatenated = NSAttrStr1.append(NSAttrStr2)
Another way works with NSMutableAttributedString
and NSAttributedString
both:
[NSAttrStr1, NSAttrStr2].joinWith(separator: "")
Another way is....
var full = NSAttrStr1 + NSAttrStr2 + NSAttrStr3
and:
var full = NSMutableAttributedString(string: "hello ")
// NSAttrStr1 == 1
full += NSAttrStr1 // "hello 1"
full += " world" // "hello 1 world"
You can do this with the following extension:
// works with NSAttributedString and NSMutableAttributedString!
public extension NSAttributedString {
static func + (left: NSAttributedString, right: NSAttributedString) -> NSAttributedString {
let leftCopy = NSMutableAttributedString(attributedString: left)
leftCopy.append(right)
return leftCopy
}
static func + (left: NSAttributedString, right: String) -> NSAttributedString {
let leftCopy = NSMutableAttributedString(attributedString: left)
let rightAttr = NSMutableAttributedString(string: right)
leftCopy.append(rightAttr)
return leftCopy
}
static func + (left: String, right: NSAttributedString) -> NSAttributedString {
let leftAttr = NSMutableAttributedString(string: left)
leftAttr.append(right)
return leftAttr
}
}
public extension NSMutableAttributedString {
static func += (left: NSMutableAttributedString, right: String) -> NSMutableAttributedString {
let rightAttr = NSMutableAttributedString(string: right)
left.append(rightAttr)
return left
}
static func += (left: NSMutableAttributedString, right: NSAttributedString) -> NSMutableAttributedString {
left.append(right)
return left
}
}

- 9,318
- 5
- 65
- 101
-
2I'm using Swift 5.1 and I can't seem to just add two NSAttrStrings together... – brzz Feb 25 '20 at 16:49
-
1Strange. In this case just use `NSAttrStr1.append(NSAttrStr2)` – Andrew_STOP_RU_WAR_IN_UA Feb 25 '20 at 17:57
-
Updated my answer with extensions for just adding two NSAttrStrings :) – Andrew_STOP_RU_WAR_IN_UA Apr 16 '20 at 03:13
-
1Using Swift 5 joinWith didn't seem to work...ended up using append method. – Ultimate_93 Nov 28 '22 at 17:44
If you're using Cocoapods, an alternative to both above answers that let you avoid mutability in your own code is to use the excellent NSAttributedString+CCLFormat category on NSAttributedString
s that lets you write something like:
NSAttributedString *first = ...;
NSAttributedString *second = ...;
NSAttributedString *combined = [NSAttributedString attributedStringWithFormat:@"%@%@", first, second];
It of course it just uses NSMutableAttributedString
under the covers.
It also has the extra advantage of being a fully fledged formatting function — so it can do a lot more than appending strings together.
// Immutable approach
// class method
+ (NSAttributedString *)stringByAppendingString:(NSAttributedString *)append toString:(NSAttributedString *)string {
NSMutableAttributedString *result = [string mutableCopy];
[result appendAttributedString:append];
NSAttributedString *copy = [result copy];
return copy;
}
//Instance method
- (NSAttributedString *)stringByAppendingString:(NSAttributedString *)append {
NSMutableAttributedString *result = [self mutableCopy];
[result appendAttributedString:append];
NSAttributedString *copy = [result copy];
return copy;
}

- 3,642
- 9
- 35
- 64
You can try SwiftyFormat It uses following syntax
let format = "#{{user}} mentioned you in a comment. #{{comment}}"
let message = NSAttributedString(format: format,
attributes: commonAttributes,
mapping: ["user": attributedName, "comment": attributedComment])

- 3,579
- 2
- 20
- 32
private var fillAttributes:[NSMutableAttributedString.Key : Any]? = nil
fontAttributes = [.foregroundColor : SKColor.red,
.strokeWidth : 0.0,
.font : CPFont(name: "Verdana-Bold",
.size : 50,]
fontAttributes.updateValue(SKColor.green, forKey: .foregroundColor)

- 357
- 1
- 4
- 14