get value of tableview items from array controller

Ok, I have my two table sample working great, So now I want to save the table data.

I try saving it to user defaults simply but realized I have set my record to contain image objects

set theValue to NSWorkspace's sharedWorkspace()'s iconForFile_(newFilepath)
set theNewTableValues to {{fileicon:theValue, filename:newFilename, pathtofile:newFilepath, filesize:"---"}} & theOldTableValues

This creates weird corrupt plist files. So I remove the images and it all works.

Then I try adding in the images at run time and removing them at quit. That works but the defaults plist is being written to during runtime and the odd plist files are created as I add rows to the table etc…

So forget User defaults. Can I write these records to file somehow, including the image objects? Remember we are dealing with a record here…

{{backupset:"newBackupset", sourcefiles:{{fileicon:theValue, filename:newFilename, pathtofile:newFilepath, filesize:"---"}}}} 

I have tried to convert it to NSMutableArray with no luck. This is an OBJ-C area that really confuses me.

I also read that you can have a datasource for a table that uses bindings but can’t get that to work so far. I figured I could then use the table datasource methods to set the images as Craig does in booklist example.

So close again but not sure of what direction to take this. Any guidance appreciated.

Rob

I should really start a new thread here but…

It isn’t the image that causes the corrupted plist file. It is the open panel!

my plist file name is normally
com.rdutoit.backuplistc.plist

When the open panel gets called:

set openPanel to current application's class "NSOpenPanel"'s openPanel()
		tell openPanel
			set allowsMultipleSelection of it to true
			set canChooseDirectories of it to true
			set allowsOtherFileTypes of it to true
			runModal()
			set fileUrl to |URL| of it
			if fileUrl is missing value then
				return
			end if
			set newFilepath to |path| of fileUrl as text -- Error occurs without 'as text'
end tell

When I press the “add” button it triggers the above open panel call. At that moment and after accepting a choice in the open panel, endless new defaults plist files are generated with a names like

com.rdutoit.backuplistc.plist.7gSYoM7
com.rdutoit.backuplistc.plist.0XVtcPM
etc.

They are corrupted files!

I suspect something odd is happening with the URL word?

Anyone have a clue here.

I am suing this for defaults write:

-- on Awake from nib
tell NSUserDefaults of current application
	tell its standardUserDefaults()
		set storedDataArray to its arrayForKey_("theArrayRecord")
		set my theData to storedDataArray
		if my theData is in {"", missing value} then set my theData to {{backupset:"newBackupset",sourcefiles:{}}} 
	end tell
end tell

-- on quit
tell NSUserDefaults of current application
	tell its standardUserDefaults()
		its setObject_forKey_( my theData, "theArrayRecord")
	end tell
end tell

Rob

Hi Rob,

Not really sure of why you have a problem but I have used this snippet without any problems:

It may help

All the best

Terry



		tell class "NSOpenPanel" of current application to set myOpenPanel to its openPanel
		
		myOpenPanel's setAllowsMultipleSelection_(false)
		myOpenPanel's setCanChooseFiles_(true)
		myOpenPanel's setCanChooseDirectories_(false)
		
		myOpenPanel's runModal
		
		set tFileArray to myOpenPanel's filenames()
		set tFilepath to tFileArray's objectAtIndex_(0)
		tell MyView to setImageWithPath_(tFilepath)


Hi All,
Back with my two tables experiment. All is well and I am trying to now save the table data. USer defaults weren’t working for reasons I posted earlier so I tried “writeToFile” which seems to be working. Here it reads in the file and then writes out.

on awakeFromNib()
		set theNewArray to NSMutableArray's alloc()'s initWithContentsOfFile_(FILE_PATH)
		if theNewArray is equal to missing value then
			set theNewArray to NSMutableArray's alloc()'s init()
			set theData to {{backupset:"newBackupset", sourcefiles:{}}}
			theNewArray's addObjectsFromArray_(theData)
			set my theData to theNewArray
		else
			--workaround for empty image column. We set the images one by one!
			set my theData to theNewArray
			my addImagesAfterArchiving()
		end if
		set my theData to my theData
	end awakeFromNib

on writeToFile()
		set theNewAnotherArray to NSMutableArray's alloc()'s init()
		theNewAnotherArray's addObjectsFromArray_(my theData)
		if not theNewAnotherArray's writeToFile_atomically_(FILE_PATH, true) then
			set messageText to "There was an error writing to file"
			display dialog messageText buttons {"Ok"} default button 1
		end if
end writeToFile

What confuses me is I am using a record but then it gets turned into an array so it will archive. This seems to work. One little bug though is if you add a new set to table one and try to quit without editing the set name, it throws the “WriteToFile” error and doesn’t retain the new entry.

on addSets_(sender)
		set my theData to {{backupset:"newBackupset", sourcefiles:{}}} & my theData
		set my theData to my theData
end addSets_

Somehow the new entry is seen as something foreign by writeToFile_atomically?

It isn’t the end of the world but makes me nervous. Any thoughts appreciated, or thoughts about a better archiving method.

Thanks, Rob

Try logging the value of theNewAnotherArray when you get the error. My guess is that having sourcefiles as {} is causing the problem, although I can’t see an obvious alternative.

The log shows something interesting

on applicationShouldTerminate_(sender)
		--before archiving, we need to clear out all the image objects 
		my removeImagesBeforeArchiving()
		my writeToFile()
		return true
end applicationShouldTerminate_

on removeImagesBeforeArchiving()
		set theOldArraysValues to Backset's arrangedObjects()
		repeat with i from 1 to count of theOldArraysValues
			set theSourceItems to Backset's arrangedObjects()'s objectAtIndex_(i - 1)'s valueForKey_("sourcefiles")
			repeat with j from 1 to count of theSourceItems
				set theSourceItemsObject to theSourceItems's objectAtIndex_(j - 1)
                                --here we remove the image and set fileicon to ""
				theSourceItemsObject's setValue_forKey_("", "fileicon")
			end repeat
		end repeat
		log theOldArraysValues
end removeImagesBeforeArchiving

You can see that, on terminate, the images are removed so the array can be archived (I tried NSCoding etc. with no luck.)

So when a new item is added to table 1 and you quit without editing that items name, it returns the array with images in it even though removeImagesBeforeArchiving() is called. Then the error happens. When you edit the new item in table 1 or do anything there, it returns the image-less array which is archived fine.

I have tried numerous ways of triggering the array into the current form but no luck yet.

Cheers, Rob

Can you try something like changing the selection when quitting?

I tried that and no luck but this works

on writeToFile()
		set theCurrentArrayValues to Backset's arrangedObjects()
		set theNewAnotherArray to NSMutableArray's alloc()'s init()
		theNewAnotherArray's addObjectsFromArray_(theCurrentArrayValues)
		if not theNewAnotherArray's writeToFile_atomically_(FILE_PATH, true) then
			set messageText to "There was an error writing to file"
			display dialog messageText buttons {"Ok"} default button 1
		end if
end writeToFile

That makes sense since I change the images to “” in Backset’s arrangedObjects(). It is theData variable that isn’t getting updated yet.

What I don’t understand is why this doesn’t work as well:

on writeToFile()
		set theCurrentArrayValues to Backset's arrangedObjects()
		if not theCurrentArrayValues y's writeToFile_atomically_(FILE_PATH, true) then
			set messageText to "There was an error writing to file"
			display dialog messageText buttons {"Ok"} default button 1
		end if
end writeToFile

Isn’t Backset’s arrangedObjects() an array? Why do I have to create new array and then add that to it to pass to writeToFile?

Well, It’s solved now. The archive works and the table bindings are incredibly fast, even with dozens of files and images added and with hardly any code!

Now if I can only add drag and drop to the table - so far no luck. There are six datasource methods! I may have to make aOBJ-C class for that one.

Thanks, Shane

Rob

Could it be that something requires an NSMutableArray and you were passing an immutable one?

I thought of that. I think I read somewhere that NSAArrayController’s arrangedObjects returns a plain Array… though you can change the values of it with setValue_forKey_ so maybe not. Is there a way in cocoa to log what class something is?

Or perhaps we need to pass the writeToFile an new instance of the Array and not the results of the array controller itself?

Rob

class() should do the trick.