Pass UILabel through a function - objective-c

I wonder how can I pass a UIlabel to a function ?
I wrote a function that gives a UILabel text from a table, but now i want to run the function with the UIlabel passed to the head of the function. Just like you would do with the text or int. Do I need a pointer or can I pass the label the normal way?
-(void)giveText:(NSString) *textinsert
{
label1.text=textinsert;
}
How could I save all the labels inside an array and run through the array?

To be honest after reading comments that you have put I don't believe you understanding what's going on at all.
This -(void)giveText:(NSString) *textinsert will just not work syntax error this method should be -(void)giveText:(NSString *)textinsert, but that isn't your problem.
From what I understand about what you are asking you want to pass a UILabel to the method.
So what you want to be doing is is something like
- (void)someMethod
{
UILabel *label1 = [[UILabel alloc] init];
[self giveText:label1];
}
- (void)giveText:(UILabel *)label
{
// Do what ever with label.
}
So what is going on?
We have created the method giveText: that takes a UILabel as a parameter then we call this method from someMethod by doing [self giveText:label1]; we pass in the UILabel that we have created.

Try this
NSMutableArray *arr=[[NSMutableArray alloc]init];
//label Creation
UILabel *lbl=[[UILabel alloc]init];
//add into array
[arr addObject:lbl];
// get label From array one by one
for (UILabel *lbl in arr) {
//pass label to function
[self passLabel:lbl];
}
-(void)passLabel:(UILabel *)lbl
{
// do here
}

you can pass label the same way as for example nsstring.
I think you shouldn't pass label to function if you are simply want to change ot's text.
Just create function which returns string
label.text = [self getLabelText];
- (NSString *) getLabelText {
NSString *text = #"text";
return text;
}

Related

Subclassing NSPopUpButton to add a bindable property

I'm trying to add a bindable property to a custom NSPopUpButton subclass.
I've created a "selectedKey" property, which is meant to store a NSString associated with selected menu item.
In control init, I set self as button target and an action for the button (valueChanged:), which in turn sets "selectedKey" in accordance with user selection:
#interface MyPopUpButton : NSPopUpButton {
NSMutableDictionary *_items;
NSString *_selectedKey;
}
#property(nonatomic, readwrite, copy) NSString* selectedKey;
- (void)addItemWithTitle:(NSString *)title andKey:(NSString *)key;
#end
#implementation MyPopUpButton
- (instancetype)initWithFrame:(NSRect)frameRect {
self = [super initWithFrame:frameRect];
if (self) {
_items = [NSMutableDictionary new];
[NSObject exposeBinding:#"selectedKey"];
[super setTarget:self];
[super setAction:#selector(valueChanged:)];
}
return self;
}
- (void)addItemWithTitle:(NSString *)title andKey:(NSString *)key {
[super addItemWithTitle:title];
[_items setValue:title forKey:key];
}
- (void)valueChanged:(id)sender {
for (NSString *aKey in [_items allKeys]) {
if ([[_items valueForKey:aKey] isEqualToString:[self titleOfSelectedItem]]) {
self.selectedKey = aKey;
}
}
}
- (void)setSelectedKey:(NSString *)selectedKey {
[self willChangeValueForKey:#"selectedKey"];
_selectedKey = selectedKey;
[self didChangeValueForKey:#"selectedKey"];
[self selectItemWithTitle:[_items valueForKey:selectedKey]];
}
#end
This seems to work as expected: "selectedKey" property is changed when user changes PopUpButton selection.
Unfortunately, trying to bind this property, doesn't work.
[selectButton bind:#"selectedKey" toObject:savingDictionary withKeyPath:key options:#{NSContinuouslyUpdatesValueBindingOption : #YES }]
When selection is changed bind object is not updated accordingly.
What am I doing wrong?
I've created a "selectedKey" property, which is meant to store an NSString associated with selected menu item.
Bindings is definitely the way to go here, but your use of bind:toObject:withKeyPath:options is incorrect.
The value that you pass to the first argument must be one of the predefined values made available by Apple for that particular control. For NSPopUpButton objects, the available values are documented in the NSPopUpButton Bindings Reference. When you look through this document you'll see that there is no selectedKey option. There is however a selectedValue which has the following description:
An NSString that specifies the title of the selected item in the NSPopUpButton.
Thus the correct way to set up the binding is as follows:
[self.btn bind:#"selectedValue"
toObject:self
withKeyPath:#"mySelectedString"
options:nil];
This is all you need to do: when the action selector is fired the property stored at the keyPath you passed in as the third argument will already have been updated. This means that you can (i) get rid of the setSelectedKey method entirely, (ii) remove exposeBinding line, and (iii) remove the code within valueChanged: - Cocoa has already done this bit.
The example below implements just two methods, but, if I've understood your intentions, they should be all you need:
- (void)awakeFromNib {
self.btn.target = self;
self.btn.action = #selector(popUpActivity:);
[self.btn bind:#"selectedValue"
toObject:self
withKeyPath:#"mySelectedString"
options:nil];
// I've added a couple of additional bindings here; they're
// not required, but I thought they'd be instructive.
[self.btn bind:#"content"
toObject:self
withKeyPath:#"myItems"
options:nil];
[self.btn bind:#"selectedIndex"
toObject:self
withKeyPath:#"mySelectedIndex"
options:nil];
// Now that you've set the bindings up, use them!
self.myItems = #[#"Snow", #"Falling", #"On", #"Cedars"];
self.mySelectedIndex = #3; // "Cedars" will be selected on startup
// no need to set value of mySelectedString, because it will be
// updated automatically by the selectedIndex binding.
NSLog("%#", self.mySelectedString) // -> "Cedars"
}
- (void)popUpActivity:(id)sender {
NSLog(#"value of <selectedIndex> -> %#", self.mySelectedIndex);
NSLog(#"value of <selectedString> -> %#", self.mySelectedString);
}
A final point worth making is that none of the above should be a part of an NSPopUpButton subclass. It looks like you can - and therefore should - do everything you need to do without a custom subclass of this control. In my demo-app the code above belongs to the ViewController class, you should try doing this also.

How to keep data in a NSMutableArray

AAA.m:
- (void)keepCurrentArray:(id)object
{
_currentTest=[[NSMutableArray alloc]init];
[_currentTest addObject:#"one"];
[_currentTest addObject:#"two"];
[_currentTest addObject:object];
NSLog(#"My Array is:%#",_currentTest);
}
Class BBB.m is passing objects to class AAA.
Right now if i'm passing X to the above method so the array will be: one,two,X . Then i'll send it Y and the array will be one,two,Y instead of what i want to accomplish: one,two,x,one,two,y.
Is that because I'm alloc and init _currentTest every time? How can I solve it?
Update:
I had a few suggestions on how to solve this and none of them worked for me. I've created a new project with just the code in the answers and i'm still getting the same result when I try to add the second object i get: one, two, test instead of one,two,test,one,two,test
Yes, it's because that you're alloc and init-ing every time you run that method. Instead, put _currentTest = [[NSMutableArray alloc] init]; in AAA.m's init method.
AAA.m
-(id)init
{
if ((self = [super init]))
_currentTest = [[NSMutableArray alloc] init];
return self;
}
- (void)keepCurrentArray:(id)object
{
[_currentTest addObject:#"one"];
[_currentTest addObject:#"two"];
[_currentTest addObject:object];
NSLog(#"My Array is:%#",_currentTest);
}
_currentTest=[[NSMutableArray alloc]init]; in a method is never a good thing!!!
As per naming convention it seems to be a property to the AAA Class. So for property, the alloc+init should be either in init or awakeFromNib. So that if is initialized just once.
However in some situations init is called more than once then your previous values are lost and new set are added.
So what you can do is make another class and put this _currentTest Array there and make it static and use it here. I hope this will work fine. And make sure in the init method of that class it is initialized just once, as :
//**this is not compiled and checked may contains typo and errors**
#implementation Storage
static NSMutableArray *yourStaticArray;
-(id)init{
self = [super init];
if (self) {
if (!yourStaticArray) {
yourStaticArray=[NSMutableArray new];
}
}
return self;
}
-(void)addYourStaticArray:(NSString *)val{
[yourStaticArray addObject:val];
}
-(NSArray *)yourStaticArray {
return yourStaticArray ;
}
#end
Well you need to have a property for that _currentTest if you want to be able to keep it around between method call.
Put this in your .h file
#property (nonatomic, copy) NSMutableArray * currentTest;
And this in hour .m file
- (NSMutableArray *)currentTest
{
if (!_currentTest)
_currentTest = [[NSMutableArray alloc] initWithCapacity:11];
return _currentTest;
}
- (void)keepCurrentArray:(id)object
{
[self.currentTest addObject:#"one"];
[self.currentTest addObject:#"two"];
[self.currentTest addObject:object];
NSLog(#"My Array is:%#", self.currentTest);
}
I Just try the code you've put on drop box and it's working exactly as it is suppose to, the array keeps it's value and everything,
BUT
Exactly as it is suppose to is not what you are trying to achieve
Your problem is not in AAA.m, your problem is in BBB.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
ViewController *kios = [ViewController new];
[kios keepCurrentArray:#"Test"];
[kios keepCurrentArray:#"Test2"];
}
I took the liberty of adding the #"test2" to the code you've send. If you run it you will see that your array still exist when the second call is made.
The REAL problem here is that you are creating a NEW ViewController each time. A brand new one, it is normal that it is empty (clean), it's a new one.
If I buy a note pad monday and fill it up, I don't expect when I'm buying an other one on friday to be already fill with the stuff I've wrote on monday in the previous one.
But this is exactly that behaviour that you are expecting from your ViewController.
You need to store your NSMutableArray in an other object that doesn't
get destroy and created over and over again.
This is happening because you are creating a new array every time that your method is called. Basically, you need to see if it has already been created, and only create it if needed. You can change your method to:
- (void)keepCurrentArray:(id)object
{
if (!_currentTest)
{
_currentTest=[[NSMutableArray alloc]init];
}
[_currentTest addObject:#"one"];
[_currentTest addObject:#"two"];
[_currentTest addObject:object];
NSLog(#"My Array is:%#",_currentTest);
}
EDIT:
In addition to the above problem, you also have this code which needs to be corrected (comments removed):
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
ViewController *kios = [ViewController new];
[kios keepCurrentArray:#"Test"];
}
This code creates a new instance of ViewController every time that you click on a row in the table. Because you are creating a new instance instead of reusing the old one, you start with an empty array each time. In order to keep adding to the same array, you need to keep using the same view controller.
In order to do this, you need to add a declared property to your .h file, similar to your currentTest declared property:
#property (strong,nonatomic) ViewController *kios;
Then, change your action so that you only create a new view controller if needed (the first time) and then reuses it after that:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (!_kios)
{
_kios = [ViewController new];
}
[_kios keepCurrentArray:#"Test"];
}

Setting Actions for PopUpButton

I have created an NSPopUpButton programmatically and I made an array for my choices, how can I create a setAction for each individual array choice? Thanks!
NSRect buttonRect = NSMakeRect(1705, 145, 78, 50);
//Button Array. When I pick the choice it closes the diologue box
NSArray *newArray;
NSString *color1 = #"Blue Color";
NSString *color2 = #"Green Color";
NSString *color3 = #"Clear Color";
newArray = [NSArray arrayWithObjects: color1, color2, color3, nil];
NSPopUpButton *button = [[NSPopUpButton alloc] initWithFrame:buttonRect pullsDown:YES];
[self addSubview:button];
[button addItemsWithTitles:newArray];
//want my action for each individual string
[button setAction:#selector(changeFilterColor)];
-(void) changeFilterColor
{
NSLog(#"colorChanged");
}
You need to add the NSMenuDelegate protocol to your interface (.h file):
#interface MyClass : NSObject <NSMenuDelegate>
Then:
[[button menu]setDelegate:self];
after you create the NSPopUpButton. Also, remove the line with setAction:.
Copy this delegate method:
-(void)menu:(NSMenu *)menu willHighlightItem:(NSMenuItem *)item
{
if ([item.title isEqualToString:#"Blue Color"]) { ... } //etc
}
Add the necessary if statements to complete the comparisons.
Another option for this is the use the setAction method you originally had in your code. But then for the selector you choose to call set it up to receive a sender object. Something like this:
-(void)method:(NSMenuItem *)sender
Then you can verify that the sender object is valid and get the title from that instead. I'm a little wary of using NSMenuDelegate for this.

Using NSString value to refer to UILabel

Have mercy, newbie here.
I have a NSString value that I construct on the fly, which is the name of a UILabel instance. I want to send the label a message to update its text. But, the two data types don't match. Here's enough code (I think):
In header file:
IBOutlet UILabel *Clue1; // IBOutlet and IBAction are IDE flags
IBOutlet UILabel *Clue2; // IB = interface builder
IBOutlet UILabel *Clue3;
In implementation file:
- (IBAction) newPuzzle:(id)sender { // Clear all fields & get new clue
[Clue1 setText:#""]; // Clear the fields
[Clue2 setText:#""];
[Clue3 setText:#""];
// Send up a randomly chosen new clue
NSArray *clues = [NSArray arrayWithObjects:#"222", #"333", nil];
NSInteger randomIndex = arc4random()%[clues count];
NSString *aClue = [clues objectAtIndex:randomIndex];
// The clue will be split into component digits and each piece sent to a different label
for (NSInteger charIdx = 0; charIdx < aClue.length; charIdx++) {
NSString *cluePos = [NSString stringWithFormat:#"Clue%d", charIdx + 1];
NSLog(#"%#", cluePos); // works
[cluePos setText:#"test"]; // Xcode notes the type mismatch
}
}
There are some similar questions on SO, but none are close enough for me to recognize that they apply to my case, at least as far as I can tell. Using the terminology of another language (R), I need to "coerce" the class of cluePos from NSString to UILabel. I'm on Xcode 4.2.1 and OSX 10.7.2.
TIA.
You can't coerce a string into a label because they are fundamentally different. The string doesn't have any knowledge of your view controller class or it's properties (some of which happen to be labels).
You can however use the valueForKey: method to get a property of an object by name, where the name is specified as a string. So to get a property called Clue1 on my view controller I'd say:
UILabel *label = [self valueForKey:#"Clue1"];
Or in your case, this:
NSString *cluePos = [NSString stringWithFormat:#"Clue%d", charIdx + 1];
UILabel *label = [self valueForKey:cluePos];
label.text = #"test";
(I'm assuming 'self' in this case refers to the view controller, but you can call this on any object that has properties.)
Another way to do this is to turn your string into a selector using NSSelectorFromString. That would look like this:
SEL selector = NSSelectorFromString(#"Clue1");
UILabel *label = [self performSelector:selector];
For your purposes either solution works equally well, however the advantage of using the selector is that you can pass arguments to the method call (so you could call a method that returns an object, not just access a property or IBOutlet).
Note that both of these methods will raise an exception if you try to access a property or call a method that doesn't exist. You can test if the property exists before calling it by saying:
SEL selector = NSSelectorFromString(#"Clue1");
BOOL labelExists = [self respondsToSelector:selector];
if (labelExists)
{
UILabel *label = [self performSelector:selector];
label.text = #"test";
}
else
{
//do something else
}

Objective C unable to update UILabel more than once

I have a method which I created that appends some new text to a UILabel. I've tried two ways of doing this (one is commented out) but both of them only update the label the first time. Any more calls to this method do not update the label.
- (void) updateLog: (NSString*) text
{
/*
NSMutableString *newText = [logLabel.text mutableCopy];
[newText appendString: text];
logLabel.text = newText;
*/
logLabel.text = [logLabel.text stringByAppendingFormat:#"%#", text];
}
I am calling the method like this (the method is in the viewController):
[viewController updateLog: #"\nStarting...\n"]; // Works
[viewController updateLog: #"Test\n"]; // Does not work
I have searched everywhere for an answer, what am I missing? Thanks!
UILabel, unless set up otherwise, only displays a single line of text.
Change the numberOfLines property if you want more.
I actually figured this out. Turns out the string WAS being successfully updated, but the label size was too small, so the text was hidden.