I am building a UI in Interface Builder and am looking for the simplest (least code) way to identify an element from code.
I'd like to avoid using outlets because frankly I detest visual programming and don't want to pollute my class space with countless outlet properties. Is there some unique string identifier I can assign to static elements that I can either reference directly or easily look up from code?
Ideally I just want to look up an object by its id like I can do in JavaScript:
document.getElementById('myIdentifier');
I agree with rightfold that outlets are the best solution, but there is an answer that addresses your question directly: you can use the (integer) tag property of UIView (setting it either in IB or in code), and then you can fetch the view with the method UIView -viewWithTag:.
Successive calls to -viewWithTag: will iterate through the subviews that have the given tag. Because it's an integer, you'll probably want to use named constants for tag references in code, but unfortunately there's no way (that I am aware of) to use constants in that manner in IB.
The default value for the tag property is 0, so avoid using that as a semantically meaningful tag.
Related
I'm trying to write an application which should display some data. The data in question comes from a different module in our code (written in C, not ObjC), and for various reasons is identified by a string, not an integer or other form of constant. After the glue code, I have an incoming method on my AppDelegate like so:
-(void)newstringdata:(NSString*)data withLabel:(NSString*)label;
This method should always take the value of data and set it as the text for a particular label in the UI. The problem is, which label.
I could of course create an NSDictionary and fill it at run time with the possible values for the label parameter in the newstringdata:withLabel: method and references to outlets, but this seems somewhat ugly and inefficient; it requires me to maintain the outlets, the nib, and the NSDictionary-initializing code.
Instead, if possible, I would like to set a property in the interface designer somewhere, and then do a lookup in my newstringdata:withLabel: method based on the label which was passed which returns the NSLabel.
Is this possible? If so, how would I do it?
If the value of label will never include a slash (/), backslash (\), or colon (:), you can use the identifier property of NSView.
In the xib, enter each label string as the NSTextViews's identifier (in the Identity tab, 3rd tab from left).
Then in your code, loop through all views and:
if ([aView.identifier isEqualToString:label])
[aView setStringValue:data];
I don't understand why, even on Xcode 6, I need to click on self, search the property, and only then see the value.
If the object have 100 properties it's very annoying.
I'm searching for simple solution that when I set my mouse cursor on self.someproperty,
above "someproperty" I will see the value of it, in any case, NSString, NSArray, Etc.
Thanks.
That's presumably because the "properties" you're hovering above are not really variables. They are syntactic sugar for accessor methods (that generally reference a backing instance variable, but not necessarily so). These accessor methods, the getter and setter, were either synthesized for you, or you may have manually implemented your own custom methods. For more information about declared properties, see Declared Properties discussion in Apple's Core Competencies document or Properties Encapsulate an Object's Value in the Programming with Objective-C document.
Consider the foo property below. You cannot hover over references to self.foo and see what you were expecting. But, if you hover over the instance variable (ivar) that backs the property, you may:
(As an aside, note that the reference to self.foo = ... above does not reference the foo getter method, but actually calls the setter method setFoo. So, it seems like a non-trivial exercise to have the IDE debugger recognize that by hovering over that "property" while execution is paused there, but realize you want to call the getter to see the value rather than calling the setter that line of code actually references.)
Anyway, back to the IDE, you can also twist open self, you'll see it there, too:
These techniques are imperfect (sometimes the debugger gets confused), but hopefully this illustrates the basic UI.
I gather you would like it to call the accessor method when you hover over the property name. Does that mean you also want it to call any random method that the mouse happens to hover over, too? In a purely functional language, this notion seems a little more plausible, but it seems dangerous in the procedural languages where any method could conceivably change a state variable and have some unintended consequence. I would have thought that if you contemplate a feature like this, it should require some something more affirmative action than merely hovering over it.
Anyway, if you really want this feature, file a "feature request" at http://bugreport.apple.com.
You can use the the logging functionality of lldb right in the console, it's a huge help:
In the right part of your Debug area you have the Console (that's also where all NSLog output goes to).
In the Console you can just use the command po (print object) and print to print the value of a variable.
I have multiple sliders in my application,how to know which slider is selected. And how to set the slider values to integer type where double is default type;
You can use the Tag property of the slider to assign an integer (or even better, use an enum). This is useful if you have multiple buttons or controls with the same target.
The sender will be the control that triggered the action, and you can get the tag from that. You can also cast back to the original control type if you need to access other properties.
See Objective C IBOutlets for information on the sender.
Also note that normally you would set the tag in Interface Builder (IB), but you can also set them in code.
You should set up the slider to target a method when it changes, that way you can be informed when a slider changes. You should do this in interface builder but if for some reason you can't, perhaps you have to dynamically determine the sliders needed then you can use methods like
[NSControl setAction:]
[NSControl setTarget:]
NSControl can have their value set with various data types (int, float, double) even some types that are not applicable to NSSliders (for example NSString), their is no default type, just use the following method.
-[NSControl setIntValue:]
Is there some way to make the Watch window display all inherited properties and fields in one long flat list, rather than hidden behind a nested "base" node?
I'm debugging some C# code that makes massive use of inheritance - some of the properties I want to watch are behind three levels of "base" in the Watch window. This would be more or less bearable if I just wanted to examine a single such object, but I'm actually looking at a tree of them...
see http://blogs.msdn.com/b/jaredpar/archive/2010/02/19/flattening-class-hierarchies-when-debugging-c.aspx
UPDATE: I wrote a commercial tool called OzCode that solves this problem. The idea is that if you're interested in a property of the base class, you can "Star" that property, which causes the property to appear at the top of members list, and also in the text of its parent.
So for example, in the following scenario, I had to expand two base nodes to get to see the properties I wanted, "Important" and "Interesting":
But once I star these properties, they will always appear at the top, even when viewing variables of the Derived type, so I'll see:
These stars are persisted and will be shown whenever you view a an object of that type in the DataTip or QuickWatch window from that moment on, so the next time you a variable of that type, you won't need to expand those "base" nodes. And because starred values appear as the parent node's text, if you're looking at a tree datastructure of these heavily nested objects (as you stated you were), you will be able to see these properties without even expanding the nodes at all.
FULL DISCLOSURE: I'm the co-author of the tool I've described here.
Not as such. You see, it is a feature! The ability to see where a property comes from is important most of the time.
I understand your pain though. There are some work arounds. First, you can just put the object.property in the watch window. This will just display the property you are looking for. It is great for digging into a specific property but not so much for getting all the others.
You can also try (BaseClass)object. This will cast it to the base object that contains the property (properties?) you are looking for. Again it is great for looking a a specific subset of properties but completly hides all the others.
Good luck and good hunting.
Let's say I have a Size class which has height and width properties (in reality the class is a bit more complex than this, but Size makes a good example).
I want to display this as $width x $height in my UI.
The obvious way to do this is to bind to a dimensions property which is dependent on width and height.
My question is where is the best place to add this new property?
I could add it to the Size class itself in the modal, but then if another controller wants to display the string different I'm stuck creating yet another property. I'm also a bit reluctant to do this because in my case the Size class is in a framework that will be used in a couple different places (although likely all from code I have control over).
I could add it in a category to the Size class inside the project containing the view/controller so it will only be availiable in the places I know it will be used, but in various places I've seen suggestions that categories tend to be overused, and am forced to wonder if this is one of those cases.
In the case of a single Size instance I could create the property in the controller class containing it, but this becomes more difficult when you have an array of Sizes.
I could bind to the entire size object and use a transformer to turn them into strings, but binding to an array of sizes would then cause you to have to transform each element of the array into a new array in the transformer, which seems a bit ugly.
If want to display this composite value as a string, then bind "Display Pattern 1" of a text field to the width property and "Display Pattern 2" (shown when you bind Display Pattern 1) to the height property. In the Display Pattern 1 binding, set the "Display Pattern" to %{value1}# x %{value2}# (yes, slightly unintuitive syntax). This will give a text field that displays "[width] x [height]" and will update on changes in either property.
You can do the same with an NSTextFieldCell, e.g. as the cell in an NSTableColumn. The downside of this method is that the text field will not be able to edit the bound width and height values. You would have to write an NSValueTransformer if you need to be able to edit them.
Using multiple bindings through a display pattern as Barry suggested sounds like the best approach, at least without knowing more about your UI. I've used the same thing in the past, where I built an inspector for an array of images and had the dimensions bound to a single text field.
In general it's good practice to use value transformers or formatters if you can, but in cases of last resort there's nothing wrong with using a category. I've done this in the past when I had trouble binding to a date, but breaking it down into individual time and date pieces. A category is a good approach because it lets you maintain separation with the model, but you don't need to do anything crazy like binding directly to the controller.
I want to display this as $width x $height in my UI.
Why not two fields? Then you could make them editable.
(in reality the class is a bit more complex than this, but Size makes a good example)
Assuming the above is not feasible in your real situation, you might try creating a custom subclass of NSFormatter, and setting it as the formatter on the cell (I assume this is in a table view, since you wouldn't bind a single control to an array). You would then bind to whole Size objects.