Suppose I have a UISlider interface element that I connected to a property in my view controller called alphaSlider. Is it possible to pull out the name of that view controller property at runtime?
The approach I tried was this:
NSString *objectName = [slider description];
Here is my approach in more detail
for (UISlider *slider in sliders)
{
NSString *objectName = [slider description];
// Do some stuff with the NSString
}
But I discovered that the description is not what I thought it was (it's just a listing of the slider properties).
Not sure if I understand what you are asking, but it might be slider.tag
So if I understand you correctly, you have a bunch of UISlider interface elements that are wired to a bunch of UISlider IBOutlets in your code, and you want to figure out which one is the one you have at the moment (in your loop).
Have you tried testing for equality with each of your IBOutlets to find the one that matches? You can do this using == because the pointers will be the same.
Otherwise, I don't believe it is possible since the mapping really only exists in the xib file and is accessed at runtime when the view is being built and the IBOutlets are being populated.
Related
I am creating an application with multiple buttons and corresponding labels.
The layout is in a nib (.xib) file which is connected to the class I have the code below in. I'm trying to avoid using an IBOutlet for every label, since this would create a lot of extra code.
I know there is a way to reference a label using the tag:
UILabel *countLabel = (UILabel *)[self.view viewWithTag:numOfTag];
I called this within my buttonPressed method. However, when I try to change the text
[countLabel setText:#"newLabel"];
the app crashes. Am I accessing it wrong? I'm new to XCode..Help!
Thanks :)
This is not the correct way of doing it. Firstly whenever you creating UILabel in your XIB file, you can name them there only so technically, there is no need for you to set the label values in the connected view controller. Secondly, even if you want to reset the labels at the later stage, connecting them using IBOutlets is the best bet. Scanning through all sub views and then finding a particular subview with its tag is more tedious and should be avoided in this case.
EDIT:
For your case where you need to create more than 50 buttons and labels, I would suggest you to create a custom UIView with UIButton and UILabel in it. And then in the view where you want to display them, create objects in a for loop and display them. And when a UIButton is tapped it will be easy for you to fetch the associated UILabel though the custom UIView object.
Your label must not be found with viewWithTag:, so it will be nil. And when you try to access property of nil control, it might give you a crash.
Check if your label is not nil and check if it is label using
if(countLabel != nil && [countLabel isKindOfClass:[UILabel class]])
[countLabel setText:#"newLabel"];
else
NSLog(#"countLabel is not found");
viewWithTag: will search the view in the receiver’s hierarchy whose tag property matches the value in the tag parameter. This will return first control it will encounter with tag in hierarchy. So make sure your tag needs to so unique in entire view. Just make sure you are giving immediate parent of Label instead of self.view.
Edit:
To can try this way also if you are not able to track issue.
for (UIView *child in self.view.subviews) {
if([child isKindOfClass:[UILabel class]] && [child tag] == numOfTag)
{
[child setText:#"newLabel"];
break;
}
}
While using NSTokenField something strange is happening, as shown in the images below :
As I type A, selection from popup is shown.
I scrolled it
Some more scroll, and it went below the visible area.
This is a behaviour with all the tableviews. The view behind the rows are visible , but it automatically springs to normal position. But not in this case.
It is fine in Mail app, it is working fine.
My implementation is :
Created an NSTokenField.
Set its delegate to AppDelegate.
In the implementation file
-(NSArray *)tokenField:(NSTokenField *)tokenField completionsForSubstring:(NSString *)substring indexOfToken:(NSInteger)tokenIndex indexOfSelectedItem:(NSInteger *)selectedIndex{
return #[#"A",#"B",#"C"];
}
Even the sample code from apple documentation behaves incorrectly.
How can I make it auto-spring or restrict by some code?
What you see in Mail.app is not an actual NSMenu (Apple cheats, shocking!). Turns out, it's actually a custom NSTextField linked to an NSTableView stuck in a transparent window.
It's a fairly old trick to get around the extremely poor version of scrollWheel: NSMenu happens to have implemented. MTTokenField is a mature alternative to pulling your hair out trying to stick a scroll view in an NSMenu.
You need to predicated the substring with the array content.This will list you the exact matching records(this is the plus point). The other is this will avoid you scrolling as well.
You got to change the delegate method in the following way which will fix the issue.
-(NSArray *)tokenField:(NSTokenField *)tokenField completionsForSubstring:(NSString *)substring indexOfToken:(NSInteger)tokenIndex indexOfSelectedItem:(NSInteger *)selectedIndex
{
NSArray *arrayContents = #[#"A",#"B",#"C"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF beginswith[cd] %#", substring];
return [NSArray arrayWithArray:[arrayContents filteredArrayUsingPredicate:predicate]];
}
Hope this will help you.
I am new in ios development, so i don't know this question is correct or not.
I want to create a uibutton from a separate uiview class in view based application template.
if anybody know ,please clear my question.
That's pretty easy to do. This code snippet should help;
NSArray* nibRollViews = [[NSBundle mainBundle] loadNibNamed:#"TiltData" owner:self options:nil];
myRollDataView = [nibRollViews lastObject]; // TODO, look it up by name, don't assume last
[myRollDataView setFrame:CGRectMake(rollDataViewFPO.frame.origin.x,
rollDataViewFPO.frame.origin.y,
myRollDataView.frame.size.width,
myRollDataView.frame.size.height)];
[self.view addSubview:myRollDataView];
[myRollDataView initWithType:RollType];
There are a few things to note. I have a rollDataViewFPO (FPO means "for position only") in my xib. I use the FPO frame for positioning the object I just loaded. This way I can position it my xib, not my code.
Also note that I call my own initWithType method. My TiltData objects can be used to show Roll or Pitch data, and I need to tell them what type they are.
Add a newFile ObjectiveC class make it as SubClass of UIView(assume name here: SubView).
if you doesn't want to use the view of UIViewController Class then just select the view in xib
of UiViewController and change the class name to SubView in inspector window.put the UIButton
in that view and do anything what you want.If you want Separate View then simply drag and
drop UIView from menu bar and connect that as an outlet to your ViewController Class and
change name of UIView class to SubView.
I'm quite a rookie when it comes to Cocoa programming, so I hope some experts can hint me on the right direction with a problem I'm facing.
I have a NSCollectionView that is bound to a NSArrayController (A) of elements having two properties: an URL to a picture and a NSArray (B) of elements of another class.
For every element inside the NSArrayController (A) , I load a subview with a NSImageView that should display the image in the URL and a NSTableView that is bound to the elements of the NSArray (B).
Everything works fine, except for one very important thing: the URL to the picture is not immediately available when I create the subview, it becomes available later, but when it does, I don't see the picture loading in the NSImageView.
I would think of a problem in the KVC/KVO implementation, but the strange thing is that the image loads correctly if, when the URL becomes available, the subview is not visible (e.g in a portion of the scrollview that is not displayed).
Example: The NSScrollview size is such that it can display only two subviews at a time. I add three elements to the NSArrayController (A): the first two images don't load, if I scroll down the scrollview to see the third element, I find the image loaded correctly.
Any ideas about what could cause such a strange behaviour?
Thank you in advance
Luca
series.h
#interface Series : NSObject {
#private
NSMutableString * banner;
}
-(Series*)initWithEpisode:(Episode*)ep;
-(void)setBanner:(NSString*)_banner;
#property (retain, readwrite) NSMutableString *banner;
#end
series.m
#implementation Series
#synthesize banner;
-(Series*)initWithEpisode:(Episode*)ep
{
self = [super init];
if(self){
banner = [[NSMutableString alloc]initWithString:#"some invalid URL"];
}
-(void) setBanner:(NSString*)_banner
{
[banner setString:[NSString stringWithFormat:#"some root path/%#", _banner];
}
-(void)dealloc
{
[super dealloc];
[banner release];
}
SeriesListViewController.m
-(void)VideoChangedStatus:(Episode*)ep{
//This is the delegate called by the object Episode when it retrieves the URL via asynchronous call to a webservice
Series *tmp = [[Series alloc]initWithEpisode:ep];
[[seriesList objectAtIndex:[seriesList indexOfObject:tmp]]setBanner:[ep banner]];
}
The binding is done in the subview nib file, to the NSImageView: I set File's Owner of type NSCollectionViewItem and then bind Valueurl to representedObject.banner
I didn't subclass NSCollectionView nor NSCollectionViewItem
After days of trying I found a solution that works: apparently it's not enough to use the setString method, I need to re-intialize the property inside the setBanner method
-(void) setBanner:(NSString*)_banner
{
banner = [NSMutableString[NSString stringWithFormat:#"some root path/%#", _banner]];
}
Still, I'd be very glad to know if someone has an explanation of why setString was causing that strange (to me) problem and why this solution works.
Thank you
Luca
I’m not sure why you’ve declared banner to be a mutable string — it looks like an immutable string would suffice.
At any rate, when you write a custom setter method you need to send -willChangeValueForKey: and -didChangeValueForKey: to ensure KVO (and hence bindings) compliance:
-(void) setBanner:(NSString*)_banner
{
[self willChangeValueForKey:#"banner"];
[banner setString:[NSString stringWithFormat:#"some root path/%#", _banner];
[self didChangeValueForKey:#"banner"];
}
Basically I want to use a nib file and view controller as a template for a view that I plan to create a number of times. This nib will have a couple of labels and custom views.
The idea is that I will iterate through an array of objects and for each I will create an instance of this controller and set a property to that of the object from the array.
This all works nicely at the moment except for one thing - the labels won't update when I call setStringValue: !!!
I'm using a method within the view controller's code to make the change but it just doesn't work, I'm guessing that the IBOutlet isn't being hooked up properly, which is strange because the custom views are hooking up perfectly.
Any ideas?
Set a breakpoint on awakeFromNib and look in the debugger what the value of the label outlet is. All outlets should have been connected before awakeFromNib is being called. If it is still nil, you have your answer. Calling setStringValue: on nil does exactly "nothing". In that case you have not correctly bound the outlet or maybe you once had it bound correctly and later on changed the name, in that case there should be a yellow warning triangle in Xcode4 or interface builder indicating that something is wrong; however it will not prevent your app from building or running, the outlet will simply keep its initial value after object creation (which is nil).
When you alloc your NSViewControllers, just init with name of NIB:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
Thanks for the replies, they were helpful but not quite what I was getting at.
I ended up solving it by creating an empty NIB and filling it with just a custom NSView and a few other controls. I created an NSView subclass with IBOutlets for those controls and set the custom view's identity to my subclass in interface builder.
The trick in getting it to work each time I wanted to draw it was by making a class method in my subclass that would load the nib and return the view set up the way I wanted.
Code below:
+(id)todoViewFromNibWithFrame:(NSRect)frameRect todoList:(TodoList *)aTodoList
{
NSNib *todoViewNib = [[NSNib alloc] initWithNibNamed:#"TodoView" bundle:nil];
NSArray *objects = nil;
id todoView = nil;
[todoViewNib instantiateNibWithOwner:nil topLevelObjects:&objects];
for (id object in objects) {
if ([object isKindOfClass:[self class]]) {
todoView = object;
[todoView setTodoList:aTodoList];
break;
}
}
[todoViewNib release];
return todoView;
}
Thanks again for the replies!
Steve