Giving the Simple Text Editor 'Legs'
Pages: 1, 2
|
|
Back to project builder
I said before that we're going to add functionality to our application by having MyDocument override specific abstract methods of NSDocument. In Project Builder, open the group Classes, and you will find the class interface and implementation files for MyDocument (remember, files with a .m extension are the implementation, and files with a .h extension are the interface, or header files).
Before we can implement the necessary methods, we have to let our source code know about the textView outlet we created. Again, an outlet is nothing more than an instance variable that points to an Interface Builder object. Because it is an object identifier, it will have data type id. Because it is also an Interface Builder outlet, we must modify the type to reflect this. Thus our instance variable will be typed IBOutlet in addition to id.
Clicking on MyDocument.h opens the class interface file in the text editor. Double-clicking it will spawn an independent text-editing window if you prefer that. Between the braces that follow the line @interface MyDocument : NSDocument add the variable declaration id IBOutlet textView. You see here how the instance variable is given the same name as the outlet, and typed to both id and IBOutlet. The names must be the same for the compiler to recognize that this instance variable is an Interface Builder outlet. While we're here let's add another variable. NSData *fileData, which we will use later to work with the contents of our document's file.
|
Now we want to look at the implementation file and study what we get by default, and modify it to our needs. Open MyDocument.m in the same way you did the interface file. You can quickly switch between a source and interface file easily by clicking the icon shown in the picture to the right.
The MyDocument.m source template has the following two methods that will be of interest to us:
- (NSData *)dataRepresentationOfType:(NSString *)aType
and,
- (BOOL)loadDataRepresentation:(NSData *)data ofType:(NSString *)aType
They are called by the application when a document is to be saved and loaded respectively.
In implementing these methods, we are assuming that the data type of our document is Rich Text Format with Attachments, or RTFD. RTFD is exactly like RTF, except it allows images and files to be associated with and embedded in the document. RTFD files are a bundle, like applications in OS X are. That is, the file seen in the Finder with an RTFD extension is a folder that contains the text file, as well as any embedded files or images.
We need to tell Project Builder that our document format is RTFD; actually, we're not telling it anything about the format in terms of data structure, but rather what the file extension, or signature is. To do this go to the Targets tab and click on the SimpleTextEditor target. In that view, click on the Application Settings tab.
There are two places we need to indicate the file extension in the Application Settings pane. In the Signature field of Basic Information type in rtfd. Now scroll down to Document Types and select the "DocumentType" line in the table. Below the table you can edit the type information; type in rtfd in the Extensions and OS Types fields. Scroll down further and click on Change. That's done now, so let's move on.
NSData
NSData is a class in the Foundation Framework that encapsulates raw data in memory. In a sense, it is like the smart bucket we talked about before, except it acts differently than the document bucket. It's still pretty smart, but in a different way. NSData takes a chuck of data -- it doesn't care what it is, it just sees it as an array of bytes -- and makes an object out of it. Like any object, the data is wrapped up in the methods that define the way it behaves and the way we interact with it.
Thus, there are several methods that let us do things like save and load the data from disk, and extract sub-data from it. The nice thing about NSData is that it provides a consistent and standard way of working with data of different types. Because of this consistency, many Cocoa classes exchange information and data using NSData instances. NSDocument is no exception, nor is NSText, and because of this, it is very easy to get data from the disk and into the window.
Back to the program
Let me explain in detail how an application such as this works with data and documents. When you choose to save a file through the menu or Command-S, whatever your preference is, the application will bring up a Save File sheet. Here the user moves around through directories, gives the file a name, and, if necessary, indicates the preferred format for the file. When you press the "Save" button a message telling your document -- represented by an instance of the class MyDocument -- to look at your document and return an NSData object containing a data representation of the contents of your document.
Opening a file is similar. When you select a file to open in the Open sheet, the application converts the contents of that file into an NSData object, and passes that to the loadDataRepresentation: ofType: method for your document to deal with in its unique way. Let's go ahead and implement these methods for our application.
Saving data to a file
Here is the code for saving our document:
- (NSData *)dataRepresentationOfType:(NSString *)aType
{
NSRange range = NSMakeRange(0, [[textView textStorage] length]);
return [textView RTFDFromRange:range];
}
NSRange is a standard C data structure -- not an object-predefined as part of the Foundation Framework that is just two numbers that define a range in the format of starting location and length. We can make a range using the NSMakeRange() function -- note, not a method -- as shown above. Here we have a range that begins at element 0, and has a length equal to the total number of characters in the document. This length is obtained by returning the NSTextStorage object, which is where the text is actually stored, associating it with our text view, and then asking it how many characters are in it by invoking the "length" method.
We then need to convert the text in textView into an NSData object as required by the return data type of the dataRepresentationOfType: method. The method RTFDFromRange: declared in the NSTextView superclass, NSText, does just that. It takes a range as an argument. In our case, the range includes our entire document, and converts the text in that range into data and returns it as an NSData object. The object returned by the message [textView RTFDFromRange:range] is then just turned around and returned as the NSData object returned by the dataRepresentationOfType: method.
Opening data files
Now we should talk about loading data from a file: This is done in the method loadDataRepresentation: ofType:. Here is the code for our implementation of that method:
- (BOOL)loadDataRepresentation:(NSData *)data ofType:(NSString *)aType
{
fileData = data;
return fileData != nil;
}
It's simple; it does nothing more than copies the data given to this method as an argument from the Open File sheet, and sets the NSData variable to identify the same object pointed to by data. The return value of this method is a Boolean indicating success or failure of retrieving the data. We do a logical test to see if fileData points to the nil object-nothing-or to something else; if it does point to data, then "Yes" is returned.
In the implementation file is another method called windowControllerDidLoadNib:. This is the method that is invoked after the nib file has been loaded and our application is aware of the NSTextView object in our interface. Now we can send a message to textView telling it to load the data contained in the "file," and it will receive the message. Before the nib file was loaded, our message to load the data would have been received by thin air. The implementation for this method looks like this:
- (void)windowControllerDidLoadNib:(NSWindowController *) aController
{
[super windowControllerDidLoadNib:aController];
if ( fileData != nil ) {
[textView replaceCharactersInRange:NSMakeRange(0, 0) withRTFD:fileData];
}
}
The first line simply tells the superclass of MyDocument to perform its method of the same name. While we are overriding and customizing the windowControllerDidLoadNib: method defined in NSDocument, the code in NSDocument is not lost, we access it by sending the message to "super."
The conditional statement is what we're interested in. Basically, we test again to make sure fileData doesn't point to thin air -- the nil object. If fileData does identify some data object, then we send a message to textView saying to replace the first character of the blank document with the text contained in the data object identified by fileData. This is the standard way of loading up a text view with data
Building and running the program
Go ahead and build and run the application. This is done by pressing Command-R, or clicking on the hammer icon (to build) and then the monitor icon (to run).
Play around with your application. Type text in, format it, do whatever. Save your document and then try re-opening it. Pretty cool? So that's it! You've made you're first fully functional application! Are you impressed with Cocoa yet? Come back next time when we will build a simple color meter application as a vehicle for further exploring Interface Builder and Project Builder.
You must be logged in to the O'Reilly Network to post a talkback.
Showing messages 1 through 68 of 68.
-
Modifications
2006-08-19 09:55:19 dhmclaughlin [Reply | View]
-
Modifications
2007-11-09 21:52:10 Psychentist [Reply | View]
dhmclaughlin,
Ok, I'm very new to C, so i need some help.
Im running through this tutorial and i think im very close.
im using Tiger 10.4.7, XCode 2.4, and IB 2.5.4. same as you, but when i use your code, i get 2 errors.
1: filedata is undeclared.
-how do i declare it and where?
2: warning: control reaches end of non void function.
-i have no idea what thats about.
Any help will be much appreciated.
-
I've finally figured this out
2005-06-19 15:35:30 jz87 [Reply | View]
Ok, you're getting a 11 error because you're trying to access a non-existent object. I don't know if this changed in Tiger (I'm using Tiger also), but I found that modifying the code in
- (BOOL)loadDataRepresentation:(NSData *)data ofType:(NSString *)aType
to
[fileData release];
fileData = data;
[fileData retain];
return fileData != nil;
solved the problem. data probably came from the system, and it was probably set as autoreleased. So when you copy the pointer to fileData and access it later you're accessing a non-existing object. That's why you gotta retain it so it doesn't get deallocated when you exist the loadDataRepresentation method. I also put release in there for good measure so we don't end up with a memory leak. Hope this helps.
-
Tiger and Open?
2005-06-16 17:44:16 Mosfet [Reply | View]
Has anyone else tried this in Tiger (10.4)?
I can save, but open gives me "mySimpleTextEditor has exited due to signal 11 (SIGSEGV)."
Not sure whats up since I've gone through this twice on 2 projects.
-
can't find Application Settings in Xcode
2004-10-25 09:48:40 Valennad [Reply | View]
Once more!
We need to tell Project Builder that our document format is RTFD; actually, we're not telling it anything about the format in terms of data structure, but rather what the file extension, or signature is. To do this go to the Targets tab and click on the SimpleTextEditor target. In that view, click on the Application Settings tab.
There are two places we need to indicate the file extension in the Application Settings pane. In the Signature field of Basic Information type in rtfd. Now scroll down to Document Types and select the "DocumentType" line in the table. Below the table you can edit the type information; type in rtfd in the Extensions and OS Types fields. Scroll down further and click on Change. That's done now, so let's move on.
Problem: How to apply it in Xcode? However I can't find and change Application Settings in this way. Help me please!
-
can't find Application Settings in Xcode
2004-10-27 09:33:34 SteveChiu [Reply | View]
I'm also trying to follow the steps to learn Cocoa. I'm on OS X.3.5, who has a newer version of Xcode.
After quite a long search, I found that I can update the extension and OS type fields at:
- Select the Taget "SimpleTextEditor"
- Go to Get Info
- Select the Properties tab
- You can then find them at the bottom pane
I believe Signature field is now the Creator field. I didn't change it, yet the application compiles and runs successfully.
-
can't find Application Settings in Xcode
2004-12-22 01:32:46 WurdBendur [Reply | View]
Yes, these are the same thing. This is the signature, or creator code, that a program leaves on it's files to identify what program created it. You don't have to use rtfd here. You can use anything you want as long as it's no more than four letters (but only A-Z and a-z, no other characters).
This helps the Finder decide what program to use to open a file, if it's not already associated with one.
I haven't been able to get the application to work correctly, though. It will open only RTFD files that it creates. It opens others, but no text is displayed in the textView. When I try to open RTFD files created by another program, it gives me this message:
loadFileWrapperRepresentation:ofType: must be overridden if your document deals with file packages.
But I thought it was dealing with packages. I don't know anything about that method, though. I wonder if I set something else wrong. I added RTF and TXT to the file types, just set as viewer, so it can't save them. But when it open them, it doesn't show any text. Do I have to change something to make it handle these?
-
Can't Run
2004-09-14 07:58:41 Briani [Reply | View]
Thanks for the articles. They have helped alot, but...
I've done everything to make an application that will save and load. When I compile I get five errors. They all say:
parse error before '{' token
Heres the code:
-------------------------------
//
// MyDocument.m
// SimpleTextEditer
//
// Created by Brian Allred on Mon Sep 13 2004.
// Copyright (c) 2004 __MyCompanyName__. All rights reserved.
//
#import "MyDocument.h"
@implementation MyDocument
- (id)init
{self = [super init];
if (self) {
// Add your subclass-specific initialization here.
// If an error occurs here, send a [self release] message and return nil.
}
return self;
}
- (NSString *)windowNibName
{return @"MyDocument";
}
- (void)windowControllerDidLoadNib:(NSWindowController *) aController
{
[super windowControllerDidLoadNib:aController];
if ( fileData != nil ) {
[textView replaceCharactersInRange:NSMakeRange(0, 0) withRTFD:fileData];
}
}
- (NSData *)dataRepresentationOfType:(NSString *)aType
{
NSRange range = NSMakeRange(0, [[textView textStorage] length]);
return [textView RTFDFromRange:range];
}
- (BOOL)loadDataRepresentation:(NSData *)data ofType:(NSString *)aType
{
fileData = data;
return fileData != nil;
}
@end
------------------ -
Can't Run
2004-10-13 15:23:08 ctatar [Reply | View]
I am using Xcode 1.1 in OS X 10.3.5, and I had nearly the same problem. After attempting to build & run, I got one
error: parse error before "NSData"
followed by four
error: parse error before '{' token.
When I double-clicked on the first error message, it took me to MyDocument.h. After comparing this to some of the files in FoundationFramework/Headers (such as NSBundle.h), I saw that all the variable declarations in the pre-made files ended in semicolons. Unfortunately, this was not made clear in the article. The code in MyDocument.hshould look something like this:
#import <Cocoa/Cocoa.h>
@interface MyDocument : NSDocument
{id IBOutlet textView;
NSData *fileData;
}
@end
After adding the semicolons, my code compiled with no problems. I composed, saved, and re-opened this message in the resulting program.
-
Xcode + Creating and connecting an outlet
2004-08-30 12:12:28 hEADcRASH [Reply | View]
Couldn't find the correct outlet. Any help out there? -
Xcode + Creating and connecting an outlet
2005-04-24 06:35:52 IDunno [Reply | View]
I have Mac OS X 10.3.9 with Interface Builder 2.4.2 and the tutorial is not working for me either (I don't mind, I'm just learning).
Have you tried to double-click on the Text View of your window? The text view is called "NSScrollView" and when I double-click on it, I get access to the real NSTextView hidden inside. Maybe this could be a part of your problem.
-
Works great!!!
2004-04-13 01:43:08 metacell [Reply | View]
I'm using 10.3. There are a few differences in XCode and Interface Builder, but I figured it all out. Much to my surprise, the program automatically allows for multiple document handling! Great!
-
Printing problem
2003-07-26 22:59:20 anonymous2 [Reply | View]
How do I make it possible to print my text? I tried it via Apple Help, but it didn't work. Any suggestions?
-
see also related project, HTMLEditorX
2003-01-17 21:41:25 anonymous2 [Reply | View]
You might be interested in the following related project. It includes downloadable source files which work on 10.2. I built it from the sources at the end of part 4 (the last part written so far), and it works ok as a simple text editor (especially after I hacked it by adding ".txt" as one of the recognized document types, besides ".html").
The series is incomplete -- this thing only edits black single-font text so far, though it'll also tell your browser to display that text as html (if the filename ends in .html) -- I hope the author will keep working on it.
Since it uses the Cocoa Document framework, it does some cool things that even BBEdit Lite 6.1 doesn't do, like notice when you rename or move a file in the Finder and update the open document window to match, and support the Services menu.
http://www.stepwise.com/Articles/HTMLEditorX/index.html
HTMLEditorX - A new beginning
By: Scott Anguish
November 28, 2002 - 04:15 AM
HTMLEditorX is a document-based multi-window HTML source editing
application. The goal is to introduce users to the Cocoa frameworks and
guide them through the building of an application.
- Bruce Smith
P.S. I like this Mike Beam series too -- I hope the author updates it for 10.2 and adds downloadable source/ProjectBuilder archives.
-
see also related project, HTMLEditorX
2007-11-09 22:04:12 Psychentist [Reply | View]
if you add the "format" bar into the menu, as this tutorial tells you, you can change the font and show the ruler. also, there is a blue button in the pallette for color change, simply put it on your gui you dont even have to program it.
-
can someone update this for 10.2?
2002-12-02 18:51:09 kelsted [Reply | View]
I'd also like to create this app, but i'm using the 10.2 developer tools, but the instructions don't seem to work and I get alot of compile errors. So can someone please let us know how to do this on 10.2?
Thanks.
-
dev tools 10.2
2002-09-22 13:12:08 anonymous2 [Reply | View]
hey,
first of all i want to say thanx for having such an awesome free site that explains so well, it has been a huge help to me. my only problem is i have dev tools for 10.2 and things are different. i was wondering if anyone could help me out, i've figured most of it out up until now. being a grrl who wants to learn programming kinda sucks, no one wants to help. so, if you got time and you don't mind helping a chic...you can email me @ macfemme@mac.com, post here...or msg me in iChat. screenname macfemme.
thanx again!
macfemme
-
Java Version - Solution
2002-05-25 15:12:43 jsumnertx [Reply | View]
I've been doing these examples in Java rather than Objective C. Here's the Java code version of this example
import com.apple.cocoa.application.*;
import com.apple.cocoa.foundation.*;
public class MyDocument extends NSDocument {
NSTextView textView;
NSData fileData;
public MyDocument() {
super();
}
public MyDocument(String fileName, String fileType) {
super(fileName, fileType);
}
public String windowNibName() {
return "MyDocument";
}
public void windowControllerDidLoadNib(NSWindowController aController) {
super.windowControllerDidLoadNib(aController);
// Add any code here that need to be executed once the windowController has loaded the document's window.
if ( fileData != null ) {
NSRange range=new NSRange(0,0);
textView.replaceCharactersInRangeWithRTFD(range, fileData);
}
}
public NSData dataRepresentationOfType(String aType) {
NSRange range = new NSRange(0, textView.textStorage().length());
return textView.RTFDFromRange(range);
}
public boolean loadDataRepresentation(NSData data, String aType) {
// Insert code here to read your document from the given data.
fileData=data;
return fileData!=null;
}
}
-
Java Cocoa Odysee
2004-03-02 05:01:31 linus4200 [Reply | View]
Hello ,
after days of searching for a solution, I found this cocoa java code which guide me to the idea, that you might help me.
I made a simple e-mail interface with interface builder with
4 fields, (from, to, subject,message), whereby from, to, subject, are NSTextFields and I used the NSTextView to be able to write a text inside. On the other hand I have a java code using javamail to send an email, also very simple and one send button.
Now my question how can I pass the NSTextView TEXT CONTENTS into the java code variable message?
Inside the java code the variable message holds the "email message that you send" but I do not know how to fill said variable with the contents of NSTextView. If you have any
suggestion for me it would be great. In any case thank you
for your help,
thx,
linus
the code I produce:
/* SendMail
e-mail function through JavaMail 1.3 from Sun
*/
import com.apple.cocoa.foundation.*;
import com.apple.cocoa.application.*;
import java.util.*;
import javax.mail.*;
import javax.mail.internet.*;
public class SendMail {
public NSTextField from; /* IBOutlet */
public NSTextView message; /* IBOutlet */
public NSTextField subject; /* IBOutlet */
public NSTextField to; /* IBOutlet */
public void send(Object sender) throws Exception { /* IBAction */
boolean debug = false;
// defining email variables
String host = "localhost";
String From = from.stringValue();
String To = to.stringValue();
String Subject = subject.stringValue();
// PROBLEM HOW TO USE NSTextView contents to pass it to message
// Get system properties
Properties props = System.getProperties();
// Setup mail server
props.put ("mail.smtp.host", "localhost");
// get session
Session session = Session.getDefaultInstance(props,null);
session.setDebug(debug);
// Define message
MimeMessage messageX= new MimeMessage(session);
messageX.setFrom(new InternetAddress(From));
messageX.addRecipient(Message.RecipientType.TO, new InternetAddress(To));
messageX.setSubject(Subject);
messageX.setText(MessageY);
// send message
Transport.send(messageX);
}
}
-
Custom Icon?
2002-03-12 10:14:17 needsglasses [Reply | View]
Great tutorial Mr. Beam. I'm impressed.
How can I change the NSApplication icon in the "About SimpleTextEditor" to a custom one that I've created?
Thanks. -
Custom Icon? Answered
2002-03-18 12:23:19 needsglasses [Reply | View]
Drag your .icns icon file into the groups & files window in Project Builder (Place it in the Resources folder). After pressing the 'Targets' tab, select the 'Application Settings' tab and place your .icns filename wherever 'Icon file' appears.
-
Using the December 2001 DevTools
2002-03-12 08:46:09 spiffyman [Reply | View]
First of all, great tutorial. I've got very little experience in C++ (that is, I've yet to even study classes), but this gives a very clear account of Objective-C and really does show how easy to use the PB/IB Tools are.
However, as mentioned in a thread earlier, the December '01 DevTools are subtly different from the version used in the tutorial. I worked a lot on it, though, and my app seems to be working just fine. So here's how I got it done:
When, in Interface Builder, we're supposed to add a new Outlet to MyDocument, but the interface is different in the new DevTools. When you click on the Classes tab for MyDocument.nib, one of the classes is NSObject. Click on that. In that menu is NSDocument, and MyDocument can be found there. Click on MyDocument, then choose 'Show Info' from the Tools menu (or hold shift-command-I).
In the resulting window, make sure "Attributes" is in the pop-up menu at the top. At the bottom you should see a list of Outlets, one of which is named myOutlet. Change the name of that to textView (leave the type as id).
Now do the rest of the Interface Builder section as Mike so expertly wrote it. Any differences are so subtle I didn't notice them. One word of caution, though: make sure the Show Info palette is showing "File's Owner Info" as opposed to "NSScrollView Info" (this can happen if you've accidentally deselected your File's Owner connection and have now selected the window itself).
Back in the Project Builder, the Classes tab is not the way you want to go. The MyDocument listed in that tab, if clicked, will only lead you to MyDocument.m, and there's some editing to do in MyDocument.h. To fix this, stay in the Files tab and click the arrow to the left of "Classes" -- that should show both MyDocument.h and MyDocument.m for your editing pleasure. Continue with the tutorial as Mike wrote it. Another word of caution: when editing MyDocument.h, be sure to put a semicolon (";") after the lines "id IBOutlet textView" and "NSData *fileData." I don't think Mike said to do this (if he did, I missed it and don't feel like checking right now). When you build and run the project, it'll tell you you need them, but why wait until then?
Again, thanks, Mike for a great tutorial. No problems (beyond the DevTools differences) thus far, and that's saying a lot.
-
A way to save as plain text?
2002-02-01 01:04:31 jimmu [Reply | View]
Are there any built in methods for saving as plain text? I want to work on a plain old text/code editor, so saving in rich text isnt realy the best thign to do.
any suggestions? -
A way to save as plain text?
2002-03-12 08:27:55 spiffyman [Reply | View]
I haven't tried this, but in Targets, you might change the Signatures, Extensions, and OS Types (what we changed in the tutorial) to 'text' -- of course, this might prompt OS X to open it with TextEdit (or BBEdit, if you've set it to do that).
-
SimpleTextEditor documents don't load in TextEdit
2002-01-06 12:19:21 snackdog [Reply | View]
This was a great article. I was able to save and open documents with my SimpleTextEditor with no problem. When I double-clicked one of my saved documents, the Finder launched TextEdit and it was not able to display my .rtfd document correctly -- it showed the internal rtf info. When I opened a file with a graphic saved in TextEdit in SimpleTextEditor, I got an error: loadFileWrapperRepresentation:ofType: must be overridden if your document deals with file packages.
Just curious about what is going on.
-- Mike. -
SimpleTextEditor documents don't load in TextEdit
2002-01-13 14:43:17 xbhoff [Reply | View]
RTFD files saved from this cocoa app will not open in TextEdit, only in itself.
RTFD files created and saved in TextEdit (containing a graphic, for example) are "openable" in this app but do not load.
If you tweak the code in this cocoa app to make it open and save files of type "rtf" (not "rtfd"), files created and saved in this cocoa app will open correctly in TextEdit. TextEdit files saved as "rtf" files (no graphics or attachments, just rich text content) will open correctly in this cocoa app.
I changed the code for data type from RTFD to RTF in two places:
NSMakeRange(0,0) withRTF:fileData
-- and --
return [textView RTFFromRange:range];
also, I changed application signature and document type extension and OS type accordingly.
This suggests to me that there is something wrong with the methods RTFDFromRange and NSMakeRange(0,0) with RTFD, or something wrong with this code that our author needs to address. The resulting file structure that gets created this way is not the same file structure as an RTFD doc created with TextEdit.
Even though the article is now several months old, its the first starting point for many people, I presume, and this kind of issue needs to be addressed by the author.
Mike, please investigate and explain.
-
tried in 10.1 dev tools?
2001-11-21 13:31:24 dwchris [Reply | View]
has anyone built this project with the 10.1 dev tools? I find that they are subtly different and you cant follow the instruction steps in the article anymore.
I trudged on anyway, but had to instantiate the mydocument class to get anything to work. but when I did it builds okay but I get the error "cant save document"
mentioned in the other messages. but none of the pitfalls there seem to apply. the outlet appears to wired up etc. when I debug, after a user save, my dataRepresentationOfType routine is called but evidently something goes wrong. -
Making the right connection (10.1 dev tools problem)
2001-12-21 02:37:35 ciofey [Reply | View]
I have another 10.1 problem.
When I make the connection I always get the source "textView" connected to the destination "NSScrollView(NSTextView)" instead of just "NSTextView", resulting in the following error message when I try to save a document from mySimpleTextEditor:
[NSScrollView textStorage]: selector not recognized.
I realize that this means that the NSScrollView has no textStorage, so I simply want to know how to (in 10.1) connect to the NSTextView instead of the NSScrollView. Control-click-drag-release always connects me to the NSScrollView(NSTextView).
Either that, or how to get hold of the NSTextView (that obviously has some relationhip - though not obvious which one - to NSScrollView) from the NSScrollView.
-
Saving multiple fields?
2001-10-14 16:35:58 martinatkinson [Reply | View]
Hello!
Great article!!! Everything worked fine on my mac (v10.03). I had one question though:
Is there any way to save multiple fields? This article tought us how to save one NSTextView, I would like to save multiple NSTextFields and/or NSTextView's. Can anyone help me out on this?
Thanks and have a great day!
Albert Atkinson
-
Port to Java
2001-10-09 09:29:26 mariox19@mac.com [Reply | View]
I did a port of this code to Java. The hardest part was handling constructors. I'm not very good at reading Objective-C (and only a beginner, hobbyist programmer anyway), but I got it to work.
If anyone wants to see the code, e-mail me: <MarioX19@mac.com>
I know a lot of people are interested in using Java with Cocoa (I am, too!)
Maybe there should be some kind of discussion list for that.
-
patching together speech and this
2001-07-14 10:52:12 psheldon [Reply | View]
I had thought that I had stripped down a speech example from apple enough that I could port tools into other applications, in particular Mike Beams nice and simple example . However, cleaning up text, I had to carefully rewire interface builder and then iterate back to the text . The stripped example code was still too big for me to think clearly about how to use it as a tool and my confusion illustrated this .
I believe what I am seeing is someone porting an archaic window method style shell into an oop framework where that makes things cumbersome for me . I am hoping similar shell experience in code warrior's puzzle ap 800 "example" will fire up my neurons to make a bit simpler example , just as promised in the last chapter would happen when oop frameworks got hot .
;-)
Each time I pass a new milestone of getting rid of an old bug and face a conceptual foolishness I had to make a new milestone, I make a new project builder folder with version number . I hope to fall back should a candidate milestone be messed up .
This example needs a bit of work, but, as I have challenged myself to present a structured walkthrough in two weeks to a new friend, provides excitement, tension and drama . But, as I am a physicist , my gift to mankind, if they should decide to accept it, is an attempt at $1M of simplification on which to build .
This trek into absolute dark makes me appreciate simple examples when they come my way .
Thanks Mike Beam for the newby reassurance.
-
How I solved my problem
2001-07-04 05:31:56 victory [Reply | View]
I too was encountering a problem where my textView connection wasn't being created properly. Maybe it's a glitch in my system or Interface Builder, but here's what I found works:
From Mike's column describing the Cntrl-drag to wire up the textView outlet:
>> the Inspector window will open and a list of all possible connections will be displayed. You should see the textView connection we just created. Highlight that and click the Make Connection button at the bottom of the window. <<
What I found works instead is to double-click on the highlit textView entry (in the list of available outlets near the top). When I simply hit the 'Make Connection' button, it was incorrectly creating a connection to NSWindow instead of NSTextView. This is despite the fact that I *was* careful to drag the pointer onto the NSTextView object (it even highlit indicated it had been selected rather than the entire NSWindow).
Once the outlet connection was made properly, the project compiled and worked as described.
What a great series of articles!
-
How does Objective-C compare to Java?
2001-06-10 13:39:14 e:)s [Reply | View]
I'm new into programming languages - or programming in general. Scripting Filemaker is as close as it gets for me. But I want to change all that the comming weeks, now that I have a summer holiday comming up and this brave new Mac on my desk.
So far I found out from various websites (like this one) that programming in either Java or Cocoa would be the best way for me to get up-to-date 'quickly' with developing on the Mac. Since I prefer being able to develop web-applications and cross-platform applications, I consider Java the most interesting option for me.
However, what is not clear for me is this: what is the mayor difference between Java and opbjective-C in power from the programmers point of view? I assume they both have their respective adventages and drawbacks, but I can't find out what they are!
I know Objective C stems from some 'ancient' structural language and that Java has been more modern and Object Oriented from the start. But how do they ultimately compare?
Anybody willing to share their insights?
BTW, I' ve posted this thread also to an earlier article about Java on the Mac. Just so you know... -
How does Objective-C compare to Java?
2001-06-12 04:28:09 Michael Beam |
[Reply | View]
You're right, for cross platform and eb applications its pretty hard to beat Java. Objective-C stems from Smalltalk, which is the grand-daddy of Object-Oriented Programming languages. Objective-C is a purely object-oriented, always has been.
Personally, I like Objective-C For a lot of the reasons in the article you mentioned. On a trivial level, i much prefer Objective-C's syntax over Java's. Its cleaner, and it is fundamentally different from the function constructs that are in C, and used in Java. I like how argument names are explicity included in the method name; it's self documenting that way, once you know what you're looking at it's much easier to read.
I don't think Objective-C is any less modern than Java. Another thing i like is the organuzation of the Cocoa frameworks. Java seems to be a bit of a mess in that respect. Thats just my opinion though. When i was learning JAva i was already familiar with Objective-C, and many of the things i learned in Java seemed intuitively backwards from the way it was done in Obj-C.
Those are some thoughts of mine. Hope it helps. I would learn both. If you learn C well, then you will alreayd have a leg up with both, as much of the syntax is closely related in Java and Obj-C.
-
Space in URL non-standard (breaks)
2001-06-08 20:28:13 halliday [Reply | View]
I don't know why I didn't notice this the first time through, but today I noticed that one of the images didn't display. The problem is a space in the file name that was not escaped in the URL: Spaces in URL's are generally given special interpretation, so, when they are not intended to have any such special interpretation, they are supposed to be escaped (%20, of course).
While it's true that some browsers will appropriately modify a given URL in their HTTP interchange with the server, this is non-standard and cannot be relied upon.
Therefore, the URL "http://www.oreillynet.com/mac/2001/06/01/graphics/h-m switch.gif" should be "http://www.oreillynet.com/mac/2001/06/01/graphics/h-m%20switch.gif".
-
Spell checking - Dictionaries
2001-06-07 09:34:04 darwinfo [Reply | View]
Hi,
it's a great series but I have a simle problem.
The built-in spell checking only provides an english dictionary.
Coming form germany I'd like to have a german one. Is there any way to install different dictionaries.
Thanks
Peter
-
My save problem solved...
2001-06-06 19:18:42 bhittle [Reply | View]
I was also getting the error message that the document could not be saved. Turned out the problem was that I named the outlet "testView" instead of "textView". Oops. Changing all the items in MyDocument.h and MyDocument.m to "testView" did the trick and everything worked. So if you're having this problem check the outlet name. BTW if you made the same error I did you could delete the outlet and put in a new one with the correct name instead of changing the code. Hope this helps.
-
How I solved my "Save problem"
2001-06-05 06:31:49 jonarnt [Reply | View]
Check that the project actually is compiled properly.
I did a silly mistake the first time, by not typing semicolon after the declarations in MyDocumnent.h . Here is the correct syntax of MyDocumnet.h:
// MyDocument.h
#import <Cocoa/Cocoa.h>
@interface MyDocument : NSDocument
{
id IBOutlet textView;
NSData *fileData;
}
@end
The author should make this part of the article clearer, but it will also show up as an error in ProjectBuilder.
-
Works fine; no problems
2001-06-05 05:41:10 lgp [Reply | View]
I found no problems at all (other than I think I may have added a couple of missing semicolons; I didn't look at the source too closely but they didn't seem to be there as I was typing).
I had a couple of typos, but the syntax checker found them and once they were corrected, everything worked perfectly.
I noticed someone said they didn't do any typing at all; that's fine for part one, but a little (very little) typing is required for part two.
-
Debugging?
2001-06-04 20:17:47 paplham [Reply | View]
It would help if you had a downloadable file of the examples. I'm having problems with compilation errors that are probably just typos. I've figured them out by trial and error, but since my programming experience consists of Fortran & Pascal a decade ago, and MS Excel Visual Basic occasionally, the symtax isn't clear at times. Having a working file to compare to would help. Along this line, exploring the debugging tools would help.
Good series so far. Would be interested in creating docklings.
-
Problem Saving
2001-06-04 16:55:20 dave.e.dave [Reply | View]
When I try to save I get nothing no error message or a saved document. However, back in Project Builder I get the following.
Jun 04 19:45:36 SimpleTextEditor[344] *** -[NSWindow textStorage]: selector not recognized
Jun 04 19:45:36 SimpleTextEditor[344] *** -[NSWindow textStorage]: selector not recognized
Any ideas??? -
Re: Problem Saving
2001-06-05 02:26:03 halliday [Reply | View]
The error:
SimpleTextEditor[344] *** -[NSWindow textStorage]: selector not recognized
suggests that when you made the connection for the textView outlet, you accidentally hooked to the Window rather than the NSTextView. Just open up the "nib" in InterfaceBuilder and look at the connections for the "File's Owner" (in the File's Owner Info panel). You will probably see that "Destination" for "textView" will be of class NSWindow, rather than NSTextView.
Just replace the connection. -
Re: Problem Saving
2001-06-05 16:13:12 dave.e.dave [Reply | View]
That was helpful. Thanks!
However, now I get this error.
Jun 05 19:04:14 SimpleTextEditor[398] *** -[NSTextView setWindowController:]: selector not recognized -
Re: Problem Saving
2001-06-05 19:16:03 halliday [Reply | View]
When you look at the "Classes" tab of your MyDocument.nib window, you do see two (2) outlets: textView /and/ window. Don't you?
Furthermore, you did check to make sure you were changing the appropriate one (only textView) when making the connection. Didn't you?
The behavior your getting is, somewhat, consistent with having only one outlet that is trying to do both functions, or, rather, setting both outlets to the same object.
-
Any ideas
2001-06-04 11:54:26 gadge47 [Reply | View]
This is off topic I guess but I can't think of where else to ask.
Does anyone know how I would go about extending this text editor to moniter input and do auto-correction? E.g. replace all typed instances of "teh" with "the." I checked the API docs on NSTextView but didn't find references to anything promising. -
Any ideas
2001-06-04 15:08:27 gregraven [Reply | View]
Have you checked out AutoCompleter? It seems to offer just what you are seeking:
http://www.catchysoftware.com/autocompleter/ -
Any ideas
2001-06-04 14:38:01 gregraven [Reply | View]
A couple of weeks ago I downloaded some "word service" programs that are supposed to work with all Cocoa programs that make use of the built-in hooks. They allow one to count words, make calculations on highlighted formulae, etc. Maybe that's the direction to look.
-
Getting Save Error
2001-06-02 14:42:43 edfigarsky [Reply | View]
Thanks for the articles. I'm feeling lost, however, since it all seems like black magic.
When I try to save, I get an alert telling me "Couldn't Save document". I copied everything, "wired" the connection, and set the "rtfd" type in the target settings.
How does one go about debugging? I set a breakpoint in dataRepresentationOfType (on the first line we added) and it wasn't hit. -
Getting Save Error
2001-06-05 05:05:58 Michael Beam |
[Reply | View]
Did you set 'rtfd' in both locations specified in the article? You might want to go back and double check, b/c in the 'Document Type' line in the table the setting may not take effect unless you pressed the change button.
From the sound of things, it seems like the error lies in this part of the program. Any syntax or code errors should have been caught by the compiler and you would know about those immediately. Additionally, cutting and pasting the code should be fine as well.
If you can give me any more details about the problem i'll see what more i can think of. Thanks everybody for helping out with this problem!
Mike -
Getting Save Error
2001-06-05 05:47:28 gregraven [Reply | View]
I get two error lines, both seemingly identical. They are:
Jun 05 05:45:39 Gredit[1152] *** -[NSWindow textStorage]: selector not recognized
Jun 05 05:45:39 Gredit[1152] *** -[NSWindow textStorage]: selector not recognized
(The name of my project is "Gredit".) -
Getting Save Error
2001-06-05 13:46:43 dpsimons [Reply | View]
From the messages you are getting, it looks like you accidentally wired your outlet to the window rather than to the NSTextView in Interface Builder. This is easy to do if you're not watching carefully what's highlighted as you drag out a connection.
Go back to IB and reconnect it and you should be okay. The connections inspector will show you which type of object your outlet is connected to.
Doug -
Re: Getting Save Error
2001-06-05 19:29:28 halliday [Reply | View]
Yep. The same errors dave.e.dave was getting (though once he changed to the NSTextView he got an error that suggested he had changed the window outlet to the NSTextView). So always be careful what outlet you set to what object! It really does make a difference. :-) -
Debugging (was Getting Save Error)
2001-06-05 02:45:16 halliday [Reply | View]
As to the question: How does one go about debugging? When you say you "set a breakpoint in dataRepresentationOfType (on the first line we added) and it wasn't hit", did you simply run the app, or did you run it in debug mode? (Menu option or debug button.)
Even if you have set breakpoints, if you don't run in debug mode, all breakpoints will be ignored.
(Incidentally, putting a breakpoint, or "NSLog" statement, here is a good idea---see if this method is even being called. If it's not being called, you may have created simply a Cocoa Application, rather than a Document based Application. [Just a thought.]) -
Debugging (was Getting Save Error)
2001-06-05 02:42:39 halliday [Reply | View]
As to the question: How does one go about debugging? When you say you "set a breakpoint in dataRepresentationOfType (on the first line we added) and it wasn't hit", did you simply run the app, or did you run it in debug mode?
Even if you have set breakpoints, if you don't run in debug mode, all breakpoints will be ignored.
(Incidentally, butting a breakpoint, or "NSLog" statement, here is a good idea---see if this method is even being called. If it's not being called, you may have created simply a Cocoa Application, rather than a Document based Application. [Just a thought.]) -
Getting Save Error
2001-06-04 11:12:53 gregraven [Reply | View]
I'm getting the same error while trying to save, and it sounds as if I followed the same steps that you did. The program compiles and otherwise runs, but will not save. The "monitor" window in Project Builder gives an error message of sorts, but I don't yet know enough to use that information to fix the problem. -
Re: Getting Save Error
2001-06-05 02:33:58 halliday [Reply | View]
We may be able to help better if all those that are having trouble would give more details about error messages (whether in compile, "monitor", console, or whatever). -
Getting Save Error: Editor's Note
2001-06-04 13:29:09 Derrick Story |
[Reply | View]
Looks like you've exposed a trip wire here. The author, Mike Beam is in Germany right now (that's a long way from Texas!), but I'll see if I can get him to take a look at this situation and post a comment. It may take a day or so, so if anyone has an ideas in the meantime, please chime in! -
Getting Save Error
2001-06-03 06:19:22 loeribas [Reply | View]
Everything works ok for me. Maybe you made a typo or tried to save to a readonly directory. -
Getting Save Error
2001-06-03 06:30:15 edfigarsky [Reply | View]
I didn't type a thing, all I did was copy and paste directly from the article. So if there's a typo (which compiles but doesn't run), it wasn't mine.
BTW, I've got Apache running with PHP and mySQL, and WebDAV (with the documents chown'ed to www, so it actually works), so read-only most likely isn't an issue. Although I did triple check where I was writing to.
Thanks, anyway.
-
Great Series... Didn't Work though
2001-06-02 05:24:09 ncallahan [Reply | View]
I have been following this series since its inception. Excellent work.
Unfortunately this weeks edition doesn't seem to work for me. All of the connections were created, I typed in all the code. But "save" and "open" were still greyed out. :-(
This series has really whet my appetite for Cocoa and Objective C. Thanks. -
PS
2001-06-02 10:29:48 Michael Beam |
[Reply | View]
I'm glad you like the solumns. I appreciate hearing that. Thanks!
Mike -
Great Series... Didn't Work though
2001-06-02 10:29:06 Michael Beam |
[Reply | View]
Hello,
I'm not near my computer right now (and won'T be for the rest of the month), so i can't check to see if the 'Save' and 'Open' menu items are greyed out, but i'm thinking that they should be active regardless of any code we've added. I don'T know exactly what to suggest. Maybe start the project with a fresh file and check the status of those particular file menu items and see if they are still in active at different points. Just another thought, did you accidentally create a 'Cocoa Application' rather than the 'Cocoa Document Based Application'? I hope this helps. If anyone else has any thoughts, please post them here. Good luck! -
Great Series... Works Now
2001-06-07 04:38:38 ncallahan [Reply | View]
Rebuilt the whole thing from scratch, copying and pasting the code from the other one I built. Took about 5 minutes and worked perfectly. I have no idea what went wrong the first time.
Thanks again for the series. Can't wait for the next installment. Must buy the book. (Nobody ever got fired for buying O'Reilly :-) -
Great Series... Didn't Work though
2001-06-04 22:13:37 delaneyrm [Reply | View]
I suggest a recheck of your MyDocument.m file. I copied and pasted from the html file and am pretty sure that I did everything correctly. After the Build I ran SimpleTextEditor and did a SaveAs. Everything seemed OK but nothing was saved.
When I returned to Project Builder and ran SimpleTextEditor from there, SaveAs gave this error message:
"Jun 04 23:26:29 SimpleTextEditor[330] dataRepresentationOfType: is a subclass responsibility but has not been overridden."
I opened MyDocument.m and found the replacement for
- (NSData *)dataRepresentationOfType:(NSString *)aType
was missing completely! I added it back in and now all is well.
I do remember a paste on top of the selected - (BOOL)loadDataRepresentation:(NSData *)data method, and getting an error of a duplicate. I was surprised to see the original method below the one from the article. So I deleted the original method. I swear that was the only deletion I made.
So if others can find similar problems with their MyDocument.m file, would they state whether they used copy-paste? It might indicate a problem area in Project Builder.
Bob








I was able to make things work with the following modifications to code:
- (void)windowControllerDidLoadNib:(NSWindowController *) aController
{
[super windowControllerDidLoadNib:aController];
if ( fileData != nil )
{
[textView replaceCharactersInRange:NSMakeRange(0, 0) withRTFD:fileData];
[fileData release];
}
}
- (NSData *)dataOfType:(NSString *)aType error:anError
{
NSRange range = NSMakeRange(0, [[textView textStorage] length]);
return [textView RTFDFromRange:range];
}
- (BOOL)readFromData:(NSData *)data ofType:(NSString *)aType error:anError
{
fileData = data;
[fileData retain];
return fileData != nil;
}
It doesn't print or read other rtfd files, but it ssave and loads its own files just fine. Thanks for a great series.