NSForegroundColorAttributeName doesn't work any more

I’m stuck again. I looked through the documentation, and it still lists ‘NSForegroundColorAttributeName’, but when I try to use it in Xcode 9.3 with Swift 4.1 it doesn’t exist ('Use of unresolved identifier ‘NSForegroundColorAttributeName’). I’ve searched for a solution, a change, anything that will work, and so far, nothing works.

This doesn’t work (unresolved identifier ‘accessibilityForegroundColor’:

mutableLog.addAttribute(accessibilityForegroundColor,
value: NSColor.blueColor(), // NSColor.blue doesn’t work here either
range: [0, mutableLog.length])

This also doesn’t work (after trying to fill in the parameters using NSForegroundColorAttributeName):

mutableLog.addAttribute(name: NSAttributedStringKey, value: Any, range: NSRange)

There is no key for foregroundColor that I can find.

I know there has to be a way to get this done, I’m just not figuring out the correct search to find it.

Here is my code. It works for everything up to this Color challenge.

AppDelegate.swift:

import Cocoa

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

var windowControllers: [ChatWindowController] = []

func applicationDidFinishLaunching(_ aNotification: Notification) {
	addWindowController()
}

func applicationWillTerminate(_ aNotification: Notification) {
	// Insert code here to tear down your application
}

func applicationDidResignActive(_ notification: Notification) {
	NSSound.beep()
}

// MARK: - Actions

@IBAction func displayNewWindow(sender: NSMenuItem) {
	addWindowController()
}

// MARK: - Helpers

func addWindowController() {
	let windowController = ChatWindowController()
	windowController.showWindow(self)
	windowControllers.append(windowController)
}

}

ChatWindowController.swift:

import Cocoa

private let ChatWindowControllerDidSendMessageNotification =
“com.JTApps.chatter2.ChatWindowControllerDidSendMessageNotification”

private let ChatWindowControllerMessageKey =
“com.JTApps.chatter2.ChatWindowControllerMessageKey”

private let ChatWindowControllerNameKey =
“com.JTApps.chatter2.ChatWindowControllerNameKey”

class ChatWindowController: NSWindowController {

@objc dynamic var log: NSAttributedString = NSAttributedString(string: "")
@objc dynamic var message: String?
@objc dynamic var userName: String? = "No Name Entered"

// NSTextView does not support weak references, so this outlet cannot be weak
@IBOutlet var textView: NSTextView!

// MARK: - Lifecycle

override var windowNibName: NSNib.Name? {
	return NSNib.Name(rawValue: "ChatWindowController")
}

override func windowDidLoad() {
    super.windowDidLoad()

    let notificationCenter = NotificationCenter.default
	notificationCenter.addObserver(self,
			selector: #selector(ChatWindowController.receiveDidSendMessageNotification(note:)),
				name: NSNotification.Name(rawValue: ChatWindowControllerDidSendMessageNotification),
								   object: nil)
}

deinit {
	let notificationCenter = NotificationCenter.default
	notificationCenter.removeObserver(self)
}

//MARK: - Actions

@IBAction func send(sender: AnyObject) {
	sender.window?.endEditing(for: nil)
	if let message = message {
		let userInfo = [ChatWindowControllerNameKey : userName!, ChatWindowControllerMessageKey : message]
		let notificationCenter = NotificationCenter.default
		notificationCenter.post(name: NSNotification.Name(rawValue: ChatWindowControllerDidSendMessageNotification),
								object: self,
								userInfo: userInfo)
	}
	message = ""
}

// MARK: - Notifications

// ChatWindowControllerDidSendMessageNotification
@objc func receiveDidSendMessageNotification(note: NSNotification) {
	let mutableLog = log.mutableCopy() as! NSMutableAttributedString
	
	if log.length > 0 {
			mutableLog.append(NSAttributedString(string: "\n"))
	}
	
	let caller = note.object as! ChatWindowController
	let userInfo = note.userInfo! as! [String: String]
	let message = userInfo[ChatWindowControllerMessageKey]!
	let userName = userInfo[ChatWindowControllerNameKey]!
	
	mutableLog.append(NSAttributedString(string: userName + ": "))
	mutableLog.append(NSAttributedString(string: message))
	
	if caller === self {
            // This produces the 'Use of unresolved identifier 'NSForegroundColorAttributeName' error
		mutableLog.addAttribute(NSForegroundColorAttributeName,
								value: NSColor.blue,
								range: [0, mutableLog.length])
		
	}
	log = mutableLog.copy() as! NSAttributedString
	
	textView.scrollRangeToVisible(NSRange(location: log.length, length: 0))
}

}

My problem is that I do not know what key (or where to find it) to insert in place of NSForegroundColorAttributeKey. I have been unable to find one yet. I have searched the documentation, and the keys listed do not include one for foreground color.

I found this in the documentation underText Attributed_String Attributes and Constants:

static let accessibilityForegroundColor: NSAttributedStringKey

so I tried this:

if caller === self {
mutableLog.addAttribute(NSAttributedStringKey.accessibilityForegroundColor,
value: NSColor.blue,
range: NSMakeRange(0, mutableLog.length))

	}

Which compiles, but doesn’t change the text color

NSMutableAttributedString.addAttribute

func addAttribute (_ name: NSAttributedStringKey, value: Any, range: NSRange)

NSAttributedStringKey is defined as a struct with static members; one of them is foregroundColor.

override func viewDidLayout() {
    print (#function)
    
    let text = "Hoot, Hoot!"
    var fancyText = NSMutableAttributedString (string: text)
    fancyText.addAttribute (NSAttributedStringKey.foregroundColor, value:NSColor.red, range:NSRange (location:0, length:fancyText.length))
    
    outletTextView.insertText (fancyText, replacementRange: NSRange (location:0, length:0))
}

Thanks ibex10! I would have sworn I tried that once, but apparently not. I missed it in all my changes. Now I have learned I need to make better notes of what I try and what doesn’t work. I made the following changes and it now works as it is supposed to.

Thank you again for your help.

// ChatWindowControllerDidSendMessageNotification
@objc func receiveDidSendMessageNotification(note: NSNotification) {
	let mutableLog = log.mutableCopy() as! NSMutableAttributedString
	
	if log.length > 0 {
		mutableLog.append(NSAttributedString(string: "\n"))
	}
	
	let caller = note.object as! ChatWindowController
	let userInfo = note.userInfo! as! [String: String]
	let userName = userInfo[ChatWindowControllerNameKey]!
	let message = userInfo[ChatWindowControllerMessageKey]!
	
	// if self, add color
	if caller === self {
		let attributedUserNameAndMessage =
			NSMutableAttributedString(string: userName + ": " + message)
		
		// Add color to both userName and message
		attributedUserNameAndMessage.addAttribute(NSAttributedStringKey.foregroundColor,
										value: NSColor.blue,
										range: NSMakeRange(0, attributedUserNameAndMessage.length))
		mutableLog.append(attributedUserNameAndMessage)
	} else {
		mutableLog.append(NSAttributedString(string: userName + ": " + message))
	}
	log = mutableLog.copy() as! NSAttributedString
	
	textView.scrollRangeToVisible(NSRange(location: log.length, length: 0))
}

}

addAttribute() doesn’t work anymore.

My solution is to make a var of string with user name and message and change the string conditionally to the caller being self :

    let userInfo = note.userInfo! as! [String : String]
    let message = userInfo[ChatWindowControllerMessageKey]!
    let user = userInfo[ChatWindowControllerUserNameKey]!
    var logLine = NSAttributedString(string: "\(user)\(message)")
    
    let caller = note.object as! ChatWindowController
    if caller == self {
        logLine = NSAttributedString(string: "\(user)\(message)", attributes: [NSAttributedString.Key.foregroundColor : NSColor.gray])
    }
    
    mutableLog.append(logLine)

It works (Swift 5.1, Xcode 12.3) :smiley: