Detect which root element will appear in QuickDialog - viewwillappear

A key difference for me of QuickDialog is that a single .m file (settingsFormBuilder.m) can carry all of the code for multiple views in the navigation controller under the one root, as such it seems to get linked to one view controller (settingsViewController.m).
My issue is that when i click on a tableviewcell, the underlying view will get pushed and the viewWillAppear in settingsViewController.m will get hit. I wan't to insert an if statement in this viewWillAppear method to see if a particular rootElement is being pushed rather than another.
How can I create an if statement to determine if my 'userAccessRoot' is being loaded in viewWillAppear as opposed to say my 'deviceConfigRoot'?
For example I need something like this, but just can't find a code combination that will do it
- (void)viewWillAppear:(BOOL)animated {
if ([self.root.activeRoot.key isEqualToString:"userAccessRoot"]) {
//Do something
}
else {
}
}
Thanks in advance

I figured out how to resolve the issue, it was more a lack of my understanding of how quickDialog works. In case someone else runs into this issue this is what to do.
The key is how you set the controllerName of your QRootElement. For all of my QRootElements I had the controllerName referencing the same .m file. For example:
userListRoot.controllerName = #"SettingsViewController"; userAccessRoot.controllerName = #"SettingsViewController";
For some reason I thought it had to be this way as the sample project seemed to be set up in a similar fashion. I simply needed to create a new class which was a subclass of QuickDialogController and point the controllerName to that. Now when that QRootElement is loaded everything operates through the created .m file being the "UserSettingsViewController". Therefore no need to try and figure out which root is initiating the viewWillAppear as long as you only link one QRootElement to one .m file as you normally would. Refer below for an example of how my QRootElements now have different controllerNames
userListRoot.controllerName = #"SettingsViewController"; userAccessRoot.controllerName = #"UserSettingsViewController";

Related

NSTableView + NSTextView = Disaster :(

This is driving me a bit crazy..
Down below is a screenshot of my program so far.
On the right is an NSTableView (view-based). This is where the user can select a document they want to work on.
On the left is the NSTextView. Text will be displayed depending on what item they choose in the NSTableView.
There are also big plus and minus buttons for creating/deleting new items in the tableview.
Simple right? I wish.
Right now I have it so the tableview gets data from a mutable array. The mutable array contains objects of a class called DocumentItem. The DocumentItem just has two strings, one for the document text and one for the document title.
What works so far:
When I manually add objects to the array using code, I am able to freely switch through the documents and the textview will update accordingly.
What doesn't work:
When the user switches to a different document, I want to call the NSTableView replaceObjectAtIndex method save the changes that they have made to the object in the array.
How my code works so far:
The mutable array is stored in a data class. The data class is a shared class and is referred to in my code as theDATA.
I have a thread looping in my class that has the textview. In my tableview class I have a method called blastToScreen that will change a BOOL called shouldBLAST to YES.
Here is the code in my TableController class to set the BOOL to YES:
- (void) blastToScreen{
theDATA.blasttext = [[theDATA.globaldoclist objectAtIndex:[tablevieww selectedRow]] doccontents];
theDATA.shouldBLAST=YES;
}
Here is the shouldBLAST method in my looped thread(in a different class from the textview). Please note that the if-statement that says if(theDATA.switchedrow) is there to make sure that certain code gets runned only when a user switches their row in the tableview.
if(theDATA.shouldBLAST){
if(theDATA.switchedrow){
DocumentItem * itemr = [theDATA.globaldoclist objectAtIndex:theDATA.lastindex];
NSLog(#"(%li) prev content - >%#",(long)theDATA.lastindex,itemr.doccontents);
itemr.doccontents=textvieww.string;
NSLog(#"(%li)adding content - > %# <- to %#",theDATA.lastindex, itemr.doccontents,itemr.docname);
theDATA.switchedrow=NO;
[theDATA.globaldoclist replaceObjectAtIndex:theDATA.lastindex withObject:itemr ];
NSLog(#"changed: - > %#",[[theDATA.globaldoclist objectAtIndex:theDATA.lastindex] doccontents]);
}
textvieww.string=theDATA.blasttext;
theDATA.shouldBLAST=NO;
NSLog(#"changed: - > %#",[[theDATA.globaldoclist objectAtIndex:theDATA.lastindex] doccontents]);
theDATA.lastindex=theDATA.selectedrow;
}
Here's the weird part about all this:
According to the NSLog statements I set up, my code works for a split second and then resets.
Down below is what the console says. ignore the (0). that is just talking about the last selected index.
What it is saying is that the text before switching was nothing(fine). It is saying that it is adding the text "Potato" to that array(still fine). Then, the first time I fetched the object from the array it shows that it successfully changed to "Potato"(Still fine). Then when I tried to fetch the SAME exact data a few lines later, it returned nothing. :(
I feel like the issue resides somewhere in my TableController class. Here's a link to the code in my TableController class.
Here's what the console returned:
2015-09-14 17:17:46.024 Simplicity[4801:432580] (0) prev content - >
2015-09-14 17:17:46.025 Simplicity[4801:432580] (0)adding content - > Potato <- to Untitled
2015-09-14 17:17:46.025 Simplicity[4801:432580] changed: - > Potato
2015-09-14 17:17:46.025 Simplicity[4801:432580] changed: - >
I really hope you guys can help me. I tried pretty much everything I could to solve this issue.This is holding me back from finishing my software.
Probably, the doccontents property of your DocumentItem class is strong (or retain) when it should be copy.
From the docs for the string property of NSText (from which NSTextView inherits):
For performance reasons, this method returns the current backing store of the text object. If you want to maintain a snapshot of this as you manipulate the text storage, you should make a copy of the appropriate substring.
So, if you're just keeping a reference to that same object, when the text view's content is changed, the content of the object you've got a reference to also changes. You need to make a private copy.

understanding whether to use protocol or inheritance (or both?)

I have a type of object in my game that simply moves horizontally.. It has a method like this:
-(void)moveLeftWithBlock:(void(^)())block {
self.targetX = self.position.x - MOVE_AMOUNT;
id action = [CCMoveTo actionWithDuration:0.125f position:ccp(self.targetX, self.targetY)];
id ease = [CCEaseInOut actionWithAction:action rate:4];
[self runAction: [CCSequence actions: ease,
[CCCallBlock actionWithBlock:block], nil]];
}
...
Now, I wanted to make a second type of object that's exactly the same, except that it can also move vertically... My initial thought was to just subclass that object's class, and overwrite the moveLeftWithBlock and update its targetY.. but not only do I not like that solution because I still end up with 99% duplicate code amongst the two classes, but also because my game needs the Y position set prior to that moveLeftWithBlock method being called.
So next I thought-- Ok, so I can make my game call a prepareToMove method, which could do any kind of setup that might be required... For the main object type, nothing.. For this 2nd object type, set the targetY.
However, I immediately started thinking-- wait---- I know protocols are about explicitly defining methods that are OPTIONAL or REQUIRED, and it made me think that perhaps I should be utilizing this here, but I just am not sure how.
So, can anyone explain to me how a protocol could be used in this case-- and if it is "the way to go" or not?
Any of these would work. You could add to this andAlsoMoveVertically: (bool) isVertical and then add the vertical movement in an if statement in the function.

When is a NSManagedObject really accessible?

I have a problem.
I have an NSObjectController called "mapController" and I want to put some defaults when the object is created. I do this inside the windowControllerDidLoadNib method of my document, as suggested by the docs. But…
if (![mapController content]){ // No map defined yet.
[mapController add: self]; // This should create the instance.
NSLog(#"%#",[mapController content]); // Gives NULL.
I tried:
BOOL ok = [mapController fetchWithRequest:nil merge:NO error:nil];
NSLog(#"%#",[mapController content]); // Gives NULL.
The content of mapController is in the Core Data "scratch pad" but I can't access it. I have to set one of its attributes like this:
[[mapController content] setValue:[matrix colorReference] forKey:#"mapData"];
This gives no error, the file is marked as changed, but it I test the value:
NSLog(#"%#",[mapController content]); // Gives NULL.
When the heck it the controller's content really HERE? Something appears on the screen but… what actually? Reading the docs doesn't help me…
OK, I found the answer in the docs:
add: Creates a new object and sets it as the receiver’s content object.
Discussion
Creates a new object of the appropriate entity (specified by
entityName) or class (specified by objectClass)—see newObject—and sets
it as the receiver’s content object using addObject:.
Special Considerations
Beginning with Mac OS X v10.4 the result of this method is deferred
until the next iteration of the runloop so that the error presentation
mechanism can provide feedback as a sheet.
That's why
[[mapController content] setValue:[matrix colorReference] forKey:#"mapData"];
worked fine when called elsewhere in the app. It was a few iterations later…
Well… maybe this post will save you a couple of hours you could use to sleep longer.
Regards,
Bernard
I don't think its your mapController, I think it is your NSLog. Try this:
NSLog(#"%#", mapController);
also try getting simple data from the content, like the float value of the CGColorRef so you can use other formatters like %f.
I would have tested this but I cannot seem to create an instance of NSObjectController because it is an undeclared identifier. What framework is it defined in? Did you have to #import anything?

Accessing property of other class

I've got a UIViewController which has three views: Category -> Sub-Category -> Detail View. The content of the Sub-Category and Detail View depends on which row is clicked in the Category view. This is done with a property called 'categoryClicked' and is declared in the sub-category.m file. It's value is given in the category.m file by the following lines of code.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
Sub-category *sub = [[Sub-category alloc] initWithNibName:#"Sub-category" bundle:nil];
sub.categoryClicked = [_categoryArray objectAtIndex:indexPath.row];
[self.navigationController pushViewController:rubrieken animated:YES];
}
This works perfectly fine until I want to use the value of categoryClicked in the Detail View. In both the category.m and the DetailView.m sub-category.m is imported. For testing purposes I putted a label on the Detail View and in the DetailView.m file I've got the following code:
Sub-category *sub = [[Sub-category alloc] initWithNibName:#"Sub-category" bundle:nil];
label.text = sub.categoryClicked;
I'm convinced this code should do the job but in fact I get an empty label. Is there anybody able to tell me what I'm doing wrong.
Edit
categoryClicked is a property declared in Sub-category.h and synthesized in Sub-category.m.
Wanted to post some more code but there is no more relevant code.
This line...
Sub-category *sub = [[Sub-category alloc] initWithNibName:#"Sub-category" bundle:nil];
...creates a new Sub-category. Since it's new, it doesn't know anything about what information has been given to some other Sub-category object. You need to get a reference to the existing object if you want to access its data.
When you alloc an object, you're allocating memory space for it. Then when you use something with init (like initWithNibName) you're initializing it. So when you allocate memory space for sub and initialize it, you have one object. But then you alloc and init again, which creates an entirely new (and completely unrelated) object. Make sure that you remove anything that could destroy your old object.
Also, the * symbol means that sub is a pointer (it points to a memory location). Whenever you use the assignment operator (=) you're telling it to point to a new thing. What you're doing is telling the label.text pointer to point at what sub is pointing at. But if you change what sub is pointing at and point label.text at the same thing, neither one is pointing at the value you want.
Hope this is clear enough, if it's not trying posting some more code and maybe someone can suggest exact changes.
-EDIT-
If you want to have a reference to an object you can only get it a few ways. What's important to know is that you can't really "create" a reference to an existing object. You have to have some connection to the object.
Declare the object inside of the file you want the reference in with something like Category c = [[Category alloc] init]; Remember this creates a new object, it won't create a reference to an existing object. However, creating the object inside of another object means that one "owns" the other and can do whatever it wants with it (obviously including accessing properties and calling methods).
Use a "chain" of objects to get a reference to your object. So if your file owns a file that owns the object you want you can use topfile.otherfile.objectyouwant. The most obvious example of this is getting a reference to an object owned by a subview.
That's about as basic as it gets; just remember that there aren't any "global" objects that you can just call by name. If your problem isn't solved by this, either look at some sample code and try to figure out how references work, or post another question that's more closely related to your problem

How do I keep an NSPathControl updated with the path of the selected cell in an NSBrowser

I need to keep an NSPathControl updated with the currently selected path in an NSBrowser, but I'm having trouble figuring out a way of getting notifications when the path has changed from the NSBrowser. The ideal way to do this would just to be to observe the path key path in the NSBrowser, but that gives a KVO can only observe set<key> methods which return void message and no updates (setPath returns a bool success value).
I also tried observing the selectedCell key path, but I'm not getting notifications when the selection there is changed.
Is there some other really obvious way to do this that I'm missing?
Courtesy of Rob Keniger over at Cocoa Dev:
Have you looked at the SimpleBrowser
example in /Developer/Examples? It
shows how to get the current selection
when it is changed by the user,
basically by just setting up the
action of the NSBrowser.
That is indeed the way to do it. Just implement a method like - (void)browserClicked: in your controller and map it to the NSBrowser's action in interface builder with whatever you want to happen each time the selection changes inside that method, e.g.
- (void)browserClicked:(id)browser {
self.pathToSelectedCell = [browser path]; // NSPathControl is bound to pathToSelectedCell
}
I just checked in IB, and it looks like NSBrowser has a selection index paths binding (an array of NSIndexPath objects) that you could possibly monitor with KVO. It's strange but I don't see any mention of it in the docs, so you might need to do a little research to see if that's something you should or shouldn't use, even if it seems to work. If it does, in your KVO observation method you would find the browser's current path, and convert that to an NSURL the path control can use.
If that doesn't work there's also the delegate methods - (BOOL)browser:(NSBrowser *)sender selectRow:(NSInteger)row inColumn:(NSInteger)column and - (BOOL)browser:(NSBrowser *)sender selectCellWithString:(NSString *)title inColumn:(NSInteger)column.
As of 10.6, one can find out which items are selected, by using the delegate callback as follows:
- (NSIndexSet *)browser:(NSBrowser *)browser selectionIndexesForProposedSelection:(NSIndexSet *)proposedSelectionIndexes inColumn:(NSInteger)column
{
NSLog(#"New first item of the new selection is at index %#", [proposedSelectionIndexes firstIndex]);
// Do something with the selected index or indicies
return proposedSelectionIndexes; // Allow the selection to occur by not changing this
}