Saving and loading doc-based Apps in ASOC

In former AS Studio you could save and load datas from a table view by collecting all the datas in a set of sets (record) and using the handler ‘data representation’. To load the data you could use the handler ‘load data representation’ .
Now in ASOC there are two new handlers:


on dataOfType_error_(typeName, outError)
		
		-- Insert code here to write your document to data of the specified type. If the given outError is not missing value, ensure that you set contents of outError when returning missing value.
		
		-- You can also choose to override -fileWrapperOfType:error:, -writeToURL:ofType:error:, or -writeToURL:ofType:forSaveOperation:originalContentsURL:error: instead.
		
		if outError is not missing value then
			set contents of outError to my NSError's errorWithDomain_code_userInfo_(my NSOSStatusErrorDomain, my unimpErr, missing value)
		end if
		return missing value
end dataOfType_error_
	


on readFromData_ofType_error_(data, typeName, outError)
		
		-- Insert code here to read your document from the given data of the specified type.  If the given outError is not missing value, ensure that you set contents of outError when returning false.
		
		-- You can also choose to override -readFromFileWrapper:ofType:error: or -readFromURL:ofType:error: instead. 
		
		if outError is not missing value then
			set contents of outError to my NSError's errorWithDomain_code_userInfo_(my NSOSStatusErrorDomain, my unimpErr, missing value)
		end if
		return true
end readFromData_ofType_error_


In the documentation I have found these examples for a text document, but I can’t ‘translate’ it.
In particular the following lines:

NSData *data = [ … and InitWithData:data …

I’m very gratefully for every kind of help.

Heiner

set myData to textView's dataFromRange_documentAttributes_error_({|location|:0, |length|:textView's textStorage()'s |length|()}, false, missing value)

set fileContents to current application's NSAttributedString's alloc()'s initWithData_options_documentAttributes_error_(myData, missing value, missing value, missing value)

But from your mention of tables, I have a feeling they’re not going to help you at all. The handlers you posted are for document-based apps – is that what you are working on? If not, they’re the wrong approach.

So what are you trying to do?

Hi Shane,
yes I’m working with table views in a document-based app.
In ASStudio it was verry easy to build a construct for saving the datas:

on data representation theObject of type ofType

set theDataSource to data source of myTableView – (it’s well-known)
set myData to contents of every data cell of every data row of theDataSource – (*)
.
.
.
set theData to {theList:mydata}

return theData
end data representation

thedata is here a list of lists (for every item) , a record with lists: {theList:{{“”,“”,“”},{“”,“”,“”}},…,}
I think the line (*) has to be converted into ASOC.

I thought the example with text view could be a tip.
Any idea?

Heiner

Look at NSDictionary’s writeToFile:atomically: and dictionaryWithContentsOfFile:. This is the easiest way to store and retrieve your tableview data. Read this tutorial for an example.

Hi Craig,

your lessons are are well-known me and I learned the basics of it (many thanks of me too !!).

The handlers you mentioned it are very static.
The tasks is to provide the user the ‘freedom’ of choosing the save directory. The consequence of this is to provide a save panel / open panel and so on. That all is in a document based app not necessary, that all is ‘build in’. The ‘only’ (!) thing is to find the abracadabras of the new handlers.

Maybe we’ll find a solution.

Thanks again
Heiner

I suspect ASStudio is using the NSPropertyListSerialization class. The dataWithPropertyList:format:options:error: method will convert your record into NSData, and propertyListWithData:options:format:error: will take data and return your dictionary.

(And you really ought to try using NSArrayController and bindings instead of datasources – it’s so much less trouble.)

Shane is right!

Up to now I did the following:


on dataOfType_error_(typeName, outError)
		set theFormat to 100 -- NSPropertyListXMLFormat_v1_0
		set theOptions to 0 -- default
		set theError to missing value
		
		set outError to missing value -- otherwise: 
		-- [MyDocument dataOfType:error:]: [<NSDocument 0x7fff704e3b40> valueForUndefinedKey:]: this class is not key value coding-compliant for the key NSError. (error -10000)
		
		set theData to current application's class "NSPropertyListSerialization"'s dataWithPropertyList_format_options_error_(kDataSource, theFormat, theOptions, theError)
		log theData -- a set of unreadable datas
		
		-- Insert code here to write your document to data of the specified type. If the given outError is not missing value, ensure that you set contents of outError when returning missing value.
		-- You can also choose to override -fileWrapperOfType:error:, -writeToURL:ofType:error:, or -writeToURL:ofType:forSaveOperation:originalContentsURL:error: instead.
		
		if outError is not missing value then
			set contents of outError to my NSError's errorWithDomain_code_userInfo_(my NSOSStatusErrorDomain, my unimpErr, missing value)
		end if
		
		return theData
	end dataOfType_error_
	
	on readFromData_ofType_error_(theData, typeName, outError)
		set theFormat to missing value -- ? otherwise error message!
		set theOptions to 0 -- default
		set theError to missing value
		
		-- set outError to missing value
		
		set propertyList to current application's class "NSPropertyListSerialization"'s propertyListWithData_options_format_error_(theData, theOptions, theFormat, theError)

		log propertyList -- read correctly (and readably) back
		
		kDataSource's addObjectsFromArray_(propertyList)
		kTableView's reloadData()
		
		-- Insert code here to read your document from the given data of the specified type.  If the given outError is not missing value, ensure that you set contents of outError when returning false.
		-- You can also choose to override -readFromFileWrapper:ofType:error: or -readFromURL:ofType:error: instead. 
		
		if outError is not missing value then
			set contents of outError to my NSError's errorWithDomain_code_userInfo_(my NSOSStatusErrorDomain, my unimpErr, missing value)
		end if
		return true
	end readFromData_ofType_error_


Saving and reading back up to propertyList is OK: In the log pane I get back the former data source in readable form, but the table view has no contents.
I get the error message:


I need a little help for error-handling, I think.

Heiner

If you add a new subclass of NSDocument to your project (File → New File, select NSDocument type), you will see it contains the following:

	on dataRepresentationOfType_(typeName)
		-- Insert code here to write your document to data of the specified type.  This method has been deprecated in favor of -[NSDocument dataOfType:error:], but AppleScript/Objective-C does not support (NSError **) parameters yet, and this method is forward-compatible.
		
		return missing value
	end dataRepresentationOfType_
	
	on loadDataRepresentation_ofType_(|data|, typeName)
		-- Insert code here to read your document from the given data of the specified type.  This method has been deprecated in favor of -[NSDocument readFromData:ofType:error:], but AppleScript/Objective-C does not support (NSError **) parameters yet, and this method is forward-compatible.
		
		return true
	end loadDataRepresentation_ofType_

I suspect it answers your question.

Yes, and so I replaced the handlers against the following


on dataRepresentationOfType_(typeName)
                set theDataSource to kDataSource
		set theFormat to 100 -- NSPropertyListXMLFormat_v1_0
		set theOptions to 0 -- default
		set theError to missing value
		
		set theData to current application's class "NSPropertyListSerialization"'s dataWithPropertyList_format_options_error_(theDataSource, theFormat, theOptions, theError)
		--log theData
		
		return theData
	end dataRepresentationOfType_
	
	
	on loadDataRepresentation_ofType_(theData, typeName)
		set theFormat to missing value --? otherwise error message !
		set theOptions to 0 -- default
		set theError to missing value
		--set outError to missing value
		set propertyList to current application's class "NSPropertyListSerialization"'s propertyListWithData_options_format_error_(theData, theOptions, theFormat, theError)
		--log propertyList -- OK!
		
		kDataSource's addObjectsFromArray_(propertyList as list)
		kTableView's reloadData()
		
		return true
	end loadDataRepresentation_ofType_

Now I get no error message. But the result is the same: I don’t get the damned propertyList into the data source and into the table. The propertyList looks like a record (a list of lists). Can addObjectsFromArray_ append the data into the data source?

What happens if you try:

set my kDataSource to propertyList

?

Could kDataSource be an NSArray rather than an NSMutableArray?

I wish you’d reconsider and move to bindings…

I think I got it.

The reason why I couldn’t replace the propertyList’s data source back to my data source is that the awakeFromNib handler ( I defined the data source therein) starts later than the readFromData_ofType_error_ handler. My data source is at that moment unknown.
I solved it with a help-property.


property helpDataSource : missing value
	property dataloaded : false
	
	
	on dataOfType_error_(typeName, outError)
		set theFormat to 100 -- NSPropertyListXMLFormat_v1_0
		set theOptions to 0 -- default
		set theError to missing value
		
		set outError to missing value -- otherwise: 
		-- [MyDocument dataOfType:error:]: [<NSDocument 0x7fff704e3b40> valueForUndefinedKey:]: this class is not key value coding-compliant for the key NSError. (error -10000)
		-- About the error problem see discussion above
		
		set myData to {theDataSource:myDataSource}
		set theData to current application's class "NSPropertyListSerialization"'s dataWithPropertyList_format_options_error_(myData, theFormat, theOptions, theError)
		
		if outError is not missing value then
			set contents of outError to my NSError's errorWithDomain_code_userInfo_(my NSOSStatusErrorDomain, my unimpErr, missing value)
		end if
		return theData
	end dataOfType_error_
	
	on readFromData_ofType_error_(theData, typeName, outError)
		set theFormat to missing value --? otherwise error message!
		set theOptions to 0 -- default
		set theError to missing value --outError
		set outError to missing value
		
		set propertyList to current application's class "NSPropertyListSerialization"'s propertyListWithData_options_format_error_(theData, theOptions, theFormat, theError)
		
		set helpDataSource to propertyList's theDataSource
		set dataloaded to true
		
		if outError is not missing value then
			set contents of outError to my NSError's errorWithDomain_code_userInfo_(my NSOSStatusErrorDomain, my unimpErr, missing value)
		end if
		return true
	end readFromData_ofType_error_


on awakeFromNib()
		
		set myDataSource to NSMutableArray's alloc()'s init()
		
		if dataloaded then
			set myDataSource to helpDataSource
			myTableView's reloadData()
			set dataloaded to false
		else
			-- do others
		end if
		
		
	end awakeFromNib
	

Maybe there is a better solution, I’m interested in it.

Heiner