|Home » Learning Curve
OS X Text & Services
A look at the sophisticated OS X text system and how it relates to OS X services.
OS X text is complex: it has to do a lot of things. It has to hold and manipulate text and ultimately it has to interact, both with other code classes and the user.
Most everything in OS X is built up around the 'model view controller' (MVC) paradigm: functionality is delegated into three areas. 'Model' is what holds the data; 'view' is what displays the data for a user and accepts input back; and 'controller' is what coordinates the other two.
The model for OS X text starts with a class called NSString.
NSString is a direct derivative of the OS X base class NSObject. NSString holds strings - but does not manipulate them. You can still do a lot with the string but you can't change it.
You can ask for a character at an index, you can get the length of the string, you can see if a string can be converted to another encoding, get back a capitalised version of the string, an upper case version, a lower case version; you can compare two strings in a myriad of ways, you can convert a string to an ASCII equivalent; you can take out not only integer but floating point values; you can parse a string as a file system path, adding or truncating components;
You can interpret a string as a property list, search for substrings, append strings (to get back new ones) and add formatted strings, pad strings, trim certain characters from strings, extract substrings, create UTF-8 strings - and finally you can write strings to disk (with all your I/O taken care of you automatically).
And in each case you're working with the original copy of the string which you cannot manipulate. If you get back something else, it's a new 'product'. The string itself cannot be changed and is called 'immutable'.
Obviously to manipulate strings you need a way to make them mutable.
NSMutableString takes up where NSString leaves off. As the string held by NSString is immutable, operations will be a lot faster. But when you need to modify a string in place, NSMutableString is what you use.
NSMutableString doesn't have as many methods as NSString but it has enough: it can append formatted strings, append strings, delete characters from a string, insert strings, reset the string, and do 'find and replace' operations.
And so far these are simple text strings: they might be Unicode but they have no formatting - colours, fonts, and the like. For formatting you need another class.
Strangely NSAttributedString does not derive from NSString. But it's a way of using functionality as found in NSString and adding formatting attributes. But it too is an immutable class.
NSMutableAttributedString derives from NSAttributedString and allows manipulation of its string.
The classes will also allow use of attachments.
A derivate of NSMutableAttributedString, NSTextStorage starts to get close to where you're dealing in text that will actually be seen 'on screen'. NSTextStorage manages instances of NSLayoutManager.
The name might suggest otherwise, but NSLayoutManager doesn't display anything either: it's a 'controller' class. As a controller, it coordinates the display of the string held by NSTextStorage: it maps characters to glyphs, sets the glyphs in a series of NSTextContainer objects, and works with NSTextView objects to finally display them.
An NSTextContainer object defines a 'region' where text is laid out. The NSLayoutManager object uses the objects to figure out how to format the text on screen. By default NSTextContainer objects are rectangular, but circular regions, regions with holes in them, and regions that flow alongside graphics can also be used.
NSTextView is the front end to all the above. It works with the layout manager and the text storage. It display the text and allows user input. It's based on a generic OS X 'view' class which in turn is based on a generic 'responder' class capable of parsing user input.
NSTextView is the base class used by TextEdit, Rixedit, Mail - even Safari.
And because so many elements of OS X use this same class, there's a lot of functionality found all around the system.
Which is the whole point.
Even simple text entry fields are managed by something similar: an instance of NSText which is the base of NSTextView. Meaning most of the functionality you find in a text editor is also there in the most common entry text fields.
Text & Services
OS X has two big frameworks: the 'application' kit' and the 'foundation' kit. In general the foundation kit is used for things that won't be displayed on screen and the application kit serves graphical user interface applications.
It's also the application kit - or AppKit for short - that takes care of OS X services. As many (or most) of the services used are based on text, this is already built into the OS X text system with no further coding necessary. But basically the protocol works as follows.
When your menu opens up, the AppKit must validate each item. For items belonging to your application the procedure is relatively straightforward. For each item the AppKit tries to find a target class that will handle it; if it doesn't find any, it disables the item. If it finds a target, it will first query the target whether the item should be enabled. If the target won't even respond to that query, the AppKit presumes the item should be enabled.
When it comes to services it's a different ball game altogether. The providers of the services are strewn around the file system. The AppKit knows on initialisation (not Finder but something really native OS X) where these applications are found because it knows basically where all applications are found and looks inside their Info.plist files for the magic word 'NSServices'. It's here the AppKit learns the nature of each service, how it works, whether it will return data, what types of data it will deal in, and so forth. When the menu opens, the AppKit must coordinate all this with the 'client' - your application or more precisely the 'first responder' or 'key view' in it.
The first responder or key view in any application is the 'view' that's getting keyboard input - or the next higher up in the 'responder chain'. It's this view that is in focus and often surrounded by a light blue rectangle. You know where your keyboard input is going to do. In a window with several input fields, hitting Tab will march you through them, highlighting each field in turn. And so forth.
So the AppKit figures out who is the 'key view' (or 'first responder') and sees if there's the possibility of a 'transaction' with a service provider.
And all this is automatic with OS X text.
When opening a menu, the AppKit sends the following method to the views in the 'responder chain'.
-(id)validRequestorForSendType:(NSString *)sendType returnType:(NSString *)returnType;
The AppKit queries the client; the client determines whether the pairing can be supported or not. For example, it's perfectly possible to invoke ACP Text Services within a text editor but not with Safari's web page rendering, while the ACP Web Services will work everywhere. This is because editable fields will not object to having a return type but Safari's rendering view will (as it's read-only).
If the client supports the service and if the service is chosen by the user, the AppKit sends a request for the client to put data on a special clipboard.
-(BOOL)writeSelectionToPasteboard:(NSPasteboard *pb) types:(NSArray *)types;
The client is given a pointer to the clipboard to use and also a list of what data types should be supported. If the client succeeds, it returns a non-zero value and the AppKit will proceed to invoke the provider.
If the service was bidirectional - if the client wants data back - then when the provider has put data back on the same clipboard and returned control to the AppKit, the latter now calls the client and tells it the data is ready.
But again, all this is ready built into each and every text view and text field in OS X.
All this comes naturally for NeXTSTEP.
ACP Web Services
AWS Resource Page
ACP Service Browser
Introducing the ACP Service Browser
ACP Service Manager Pro
Baker Street Blues