So I'm still very new to this whole objective C think and I ran into a problem I'm not sure the root cause for.
My h file looks basically like this :
#interface DrinkDetailViewController : UIViewController<UITextFieldDelegate>
{
UITextField* nameTextField;
UITextField* activeView;
}
#property (nonatomic,retain) IBOutlet UITextField* nameTextField;
In my m file i'm implementing the delegate function :
-(BOOL) textFieldShouldBeginEditing:(UITextField*) textField
{
activeView = textField;
return YES;
}
The thing is that if i'm declaring activeView to be a property as well (meaning adding property, synthesize and the all deal), then when i'm leaving the view (it's a navigation based project) my app crashes. However, if I live it as a non property everything seems to work fine. Why is that ???
because it's a property you need to call it this way:
self.activeView = textField;
That way the correct memory management rules will be applied and also the KVO notifications will be done for you.
are you synthesing activeView in your implementation file:
#synthesize activeView;
Related
I have two views, and i'm trying to show text that i getting from first view in UITextField of another . Second view shown by - (source) so methods ViewWillAppear and ViewDidLoad won't work. And viewDidLoad method of second view is runs when app is started.
I'm tried to make method of second class
secondClass.h:
#property (strong, nonatomic) IBOutlet UITextField *itemName;//all hooked up in storyboard
-(void)SetName:(NSString *)name;
secondClass.m:
-(void)SetName:(NSString *)name{
NSLog(#"%#",name);
itemName.text = name;//itemName - textField
}
and use it in first one:
secondViewConroller *secondView = [[secondViewConroller alloc]init];
[secondView SetName:#"Bill"];
NSlog shows "Bill" but textField.text won't change anything.
My guess that app shows UITextField without changes because it shows second view that it gets from viewDidLoad method and i need to update it somehow
My question: What is the best approach to change attributes of UI elements from different classes?
Easiest way:
secondViewConroller.h :
#property NSString * conversationName;
secondViewConroller.m :
#synthesize conversationName;
-(void)SetName:(NSString *)name{
NSLog(#"%#",name);
itemName.text = conversationName
}
On alloc:
secondViewConroller *secondView = [[secondViewConroller alloc]init];
conversationName = #"Set this text";
[secondView SetName:#"Bill"];
I would suggest you to read about Protocols after that.
Easiest way:
in
secondViewConroller.h :
#property (nonatomic, retain) NSString *stringName;
secondViewConroller.m :
#synthesize stringName;
and in viewDidLoad method you write this line
itemName.text = stringName
On alloc:
secondViewConroller *secondView = [[secondViewConroller alloc]init];
secondView.stringName = #"Set this text";
guess there is something wrong with your itemName variable if it appears to get to the nslog.
did you create a referencing outlet in the interface builder for the textfield?
otherwise you can get the right textfield by tag, in IB put for instance tag 1 on the textfield and do in code:
UITextField *tf=(UITextField*)[self.view viewWithTag:1];
tf.text=name;
(replace self.view for the view holding the textfield, if not directly in the main view)
So i found a solution: There's was something wrong with calling method SetName: with parameters that i getting from first UIViewController.
Basically the solution is : create NSObject and put in there value from first UIViewConroller and then use it in second.
This TUTORIAL helped me to resolve the problem.
I'm building an app that has a main view which consists of a Map View. A second view has some necessary configuration options (config view). I segue to this config view using a partial curl segue.
The problem I'm having is the state of my config view is not being maintained.
For example,
I will segue into the config view, make some changes to the settings and return to the main Map View. Once I return to the config view again the values are back to their default values. The value in question is distanceFilterValue.
Here's the implementation of my config view controller:
#interface SimpleConfigViewController()
//private interface inside implementation
#property (weak, nonatomic) UISlider * distanceFilterSlider;
#property (strong, nonatomic) NSNumber *distanceFilterValue;
#end
#implementation SimpleConfigViewController
#synthesize distanceFilterLabel = _distanceFilterLabel;
#synthesize distanceFilterSlider = _distanceFilterSlider;
#synthesize distanceFilterValue = _distanceFilterValue;
- (NSNumber *)distanceFilterValue {
if (!_distanceFilterValue) {
_distanceFilterValue = [NSNumber numberWithFloat:250.0];
}
return _distanceFilterValue;
}
- (IBAction)distanceSliderValueChanged:(UISlider *)sender {
self.distanceFilterValue = [NSNumber numberWithFloat:sender.value];
//update GUI
self.distanceFilterLabel.text = [NSString stringWithFormat:#"%.f m", sender.value];
}
#end
It seems to me that because I keep a strong pointer to distanceFilterValue, this value should be correct when I return back to config view. I'm clearly missing something here.
Thanks in advance for your help.
I could be wrong, but I guess the config view is unloaded, and loaded again from the XIB when it's pushed the second time.
You should store your values in a model object anyway and not in a controller!
I think that Erik is right, everytime you call viewDidLoad for your configView it will reset. You could use a Singleton or NSUserDefaults to solve this.
I have an custom UIVIewController that is the base class for other controllers and has an instance of a custom UIView variable that is accessed by inherited the classes.
BaseViewController.h
#interface BaseViewController : UIViewController {
UIView *_vwHeader;
}
#end
BaseViewController.m
#import "BaseViewController.h"
#implementation BaseViewController
-(void)loadView {
[super loadView];
_vwHeader = [[UIView alloc] init];
}
#end
CustomViewController.h
#import "BaseViewController.h"
#interface CustomViewController : BaseViewController
#end
CustomViewController.m
#import "CustomViewController.h"
#implementation CustomViewController
- (void)loadView
{
[super loadView];
[_vwHeader setHidden:NO];
}
#end
The problem is that when I am running it on the simulator everything works perfectly fine, but when I change to the device I have an error on the [_vwHeader setHidden:NO]; line which says: '_vwHeader' undeclared (first use in this function)
I already tried to do:
Comment this line of code, but then it gives me an error in another class using a variable from the base class the same way (It only returns one error at a time), so it seems that it is not an specific error in the view or the controller class as the error occurs in other clases with different types, such as UIView and NSObject types
Change target compiler configuration, such as: architectures (all of them), base sdk (all above 4.0) didn't change anything
What seem to solve the problem, but not completely
Creating a property for _vwHeader and accessing it by self._vwHeader or super._vwHeader seems to work, but having to create a property just to access a variable does not make me confortable, specially because I would have to do it for all variables in the same situation inside my project.
changed C/C++ compiler version: using Apple LLVM Compiler 2.1 makes the compilation error goes away, but gives a bunch of other problems with other libraries being used in the project. So, it is not a definitive solution, but might be a clue of what the problem is.
EDIT:
I tried to create another variable that is not a pointer, a BOOL instead of the UIView * and then used it in the inherited class: the problem also occurs
EDIT (2):
I have no properties whatsoever in any of my classes and I still get the error.
I just added the properties for test porpouses, to see if a property in a parent class caused the same behaviour, and apparently it doesn't.
Something that is also weird is that when I get the error in the variable, I checked with my intellisense and it finds it...
In order to refer to an instance variable within any object other than self, including super, you must use the structure pointer operator (->). The default scope of an instance variable is protected, which means it can only be accessed within the class it is defined in or a subclass of that class. Since CustomViewController is a subclass of BaseViewController, this scope is sufficient to access the variable using self->_vwHeader, but if the second class you were trying to do this from is not a subclass you will also need to change the scope to either #public or #package.
In summary, change your method call to:
[self->_vwHeader setHidden:NO];
and it should work for any subclasses of the base view controller.
Do a clean and build, and also make sure you are not specifying a specific framework search path in the build settings. If you leave it empty you should get the correct libraries.
well I don't know, should work.
BaseViewController.h
#interface BaseViewController : UIViewController {
UIView *_vwHeader;
}
#property(nonatomic,retain)UIView *_vwHeader;
#end
BaseViewController.m
#synthesize _vwHeader;
CustomViewController.m
#import "CustomViewController.h"
#implementation CustomViewController
- (void)loadView
{
[super loadView];
[self._vwHeader setHidden:NO];
}
#end
I faced similar problem as you. In my case the reason was (strangely!) wrong synthesization of properties in subclass.
Example:
In .h file of subclass you have following declaration
BOOL _flag;
...
#property (nonatomic, assign) BOOL flag;
while in you synthesize the property in the wrong way:
#synthesize flag;
instead of
#synthesize flag = _flag;
Strangely, the compiler does not complain about the wrong synthesization (the properties even work fine!), but raises an error, when I try to access protected fields declared in base class.
Detailed explanation
Here is what my code look like
I have base class (excerpt):
#interface BaseEditionModalController : NSObject
{
DataContext *_dataContext;
}
And I have subclass of it (excerpt):
#interface LocationModalController : BaseEditionModalController
{
MCLocation *_readLocation;
LocationCommModel *_oldLocationCommModel;
}
//This is MCLocation for reading only - from the main application context
#property (nonatomic, retain) MCLocation *readLocation;
#property (nonatomic, retain) LocationCommModel *oldLocationCommModel;
#end
And in the LocationModalController.m I have following wrong declarations:
#implementation LocationModalController
#synthesize readLocation;
#synthesize oldLocationCommModel;
Trying to access _dataContext in LocationModalController produced the error that _dataContext is undeclared.
Changing the synthesization of properties to:
#implementation LocationModalController
#synthesize readLocation = _readLocation;
#synthesize oldLocationCommModel = _oldLocationCommModel;
MAGICALLY SOLVES THE PROBLEM!
Regards
I just stumble upon your method declaration
-(void)loadView { ... }
In a view the first point you can rely that everything is fully initialized is after -(void)viewDidLoad was called. Maybe your code works on the simulator because your Mac is fast enough to cope this speed issue - but your mobile device isn't.
Maybe try this coding:
Your BaseViewController.h file:
#interface BaseViewController : UIViewController {
UIView *_vwHeader;
}
#end
Your BaseViewController.m file:
#import "BaseViewController.h"
#implementation BaseViewController
-(void)viewDidLoad {
[super viewDidLoad];
_vwHeader = [[UIView alloc] init];
}
Your CustomViewController.h file:
#interface CustomViewController : BaseViewController {
}
#end
Your CustomViewController.m file:
#import "CustomViewController.h"
-(void)viewDidLoad {
[super viewDidLoad];
[_vwHeader setHidden:NO];
}
Now your CustomViewController can rely on every instance variable in BaseViewController is correctly instantiated.
The error says that _vwHeader undeclared.
So try by modifying the code in:
CustomViewController.m
#import "CustomViewController.h"
#implementation CustomViewController
- (void)loadView
{
[super loadView];
if(!_vwHeader)
{
_vwHeader = [[UIView alloc]init];
}
[_vwHeader setHidden:NO];
}
#end
It is possible that when you compile for target and for simulation the data members are either protected or private. Probably for target are private by default and this seems to cause the problem. Try out playing with the #private and #protected keywords.
However, I strongly suggest that you use properties even between your super/sub-classes. Having a complex structure is a bit hard to debug. Setting up a property will transfer the access to the data through the getter/setter methods (a breakpoint on #synthesize also works) and you will be able to see in the call stack who is accessing what.
Especially, the syntax #synthesize propertyName = prefixDataNameSufix; allows you to easily adjust your class interface style without having to modify your coding habits.
I had the exact same problem and it turns out that I did not remove an unused iVar/property in the SUBCLASS. Let's call it session. I removed _session from the iVar but I forgot to remove it from the properties, then in the .m file I had this synthesize session = _session. Once I removed them all, I can compile for iOS device without problems.
If you think your superclass is fine, look into your subclass, check your iVars and properties and synthesize section in the .m file
I had this exact problem.
In my case, I was relying on ivar synthesis of a property. That is, I did NOT declare UITextView *textView_, but I did #synthesize textView = textView_;
This builds fine on my iOS Simulator. However, my iOS device build fails, regardless of whether I use llvm or gcc.
When I add the declaration back to my interface:
#interface MyTableViewController : BaseTableViewController {
#private
UITextView *textView_; // this line is important!
}
Everything works fine!
See the answer from tc above. This is a bug in the compiler shipped with sdk 4.2.
Specifically I have seen the same error and if on the same machine I have sdk 4.2 and sdk 4.3 installed the error disappears (even if I compile for 4.2).
If anyone is having this issue after upgrading their tools and devices to iOS10, I had it and found that declaring them as weak, nonatomic in the .h file was the issue. I had never encountered this when doing so before but after removing (weak, nonatomic) from the property declaration, everything worked fine again.
I am curious about conforming a class to UITextFieldDelegate, in the past I have always added it to enable access to methods defined within the protocol. However this last time I forgot to add it, only realising later that it was missing. My question is why does it work with or without, I thought it was needed to correctly access the protocol methods?
#interface MyController : UIViewController <UITextFieldDelegate> {
UITextField *text_001;
}
#property(nonatomic, retain) IBOutlet UITextField *text_001;
#end
OR:
#interface MyController : UIViewController {
UITextField *text_001;
}
#property(nonatomic, retain) IBOutlet UITextField *text_001;
#end
WITH:
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
NSLog(#"Return: ... ");
[textField resignFirstResponder];
return YES;
}
Cheers Gary
Delegate declarations are really just there as compiler hints; obviously, you still have to implement the underlying methods. However, the main purpose is to let the compiler double check you when assigning them. If you try to manually (in code, as opposed to IB) assign a delegate which wasn't declared as such, you'll frequently get a compiler warning.
Since Objective-C uses duck-typing for most stuff (if it walks like a duck and quacks like a duck; if it responds to -textFieldShouldReturn:, etc), you're pretty safe.
I'm reasonably new at the iPhone SDK, so please forgive me if this answer's ridiculously obvious.
I have a ViewController connected to a .xib file (they are called FirstViewController)
I also have a custom class called MyCustomClass. In this class, I have a method like this:
- (void)setTheText {
[myLabel setText:#"foo"];
}
I want to call this method to set the text in a label in FirstViewController.xib
So far, I have done this:
Dragged in an "Object" into Interface Builder, and set the class to: MyCustomClass
Connected up the IBOutlet 'myLabel' from MyCustomClass to a UILabel in the view.
However, when I run the program, and press the button to set the label (which is in FirstViewController.m), something like:
- (IBAction)doSomething:(id)sender {
MyCustomClass *customClass = [MyCustomClass alloc] init];
[customClass setTheText];
}
This doesn't set though. NSLog(#"%#",[myLabel text]); returns (null)
Xcode shows no errors or warnings, what could be wrong?
Thanks,
Michael
Additional Info:
Interface to MyCustomClass.h:
#import <UIKit/UIKit.h>
#interface MyCustomClass : NSObject {
UILabel *myLabel;
}
#property (nonatomic, retain) IBOutlet UILabel *myLabel;
- (void)setTheText;
#end
You don't want to create a new instance of your custom class in your action method.
There are a couple of ways to do what you want.
Option 1 is to give your view controller a reference to your custom object. To do this, create an outlet of type MyCustomClass * in your view controller, connect that outlet to the new object that you created in your XIB file, and then get rid of the allocation in your action method:
- (IBAction)doSomething:(id)sender {
[customClass setTheText];
}
Option 2 is to let your CustomClass handle both the label and the action method. To do this, you can simplify things even further. Put an outlet for the UILabel into your CustomClass, and then simply convert your setTheText method into an action:
- (IBAction)setTheText:(id)sender {
[myLabel setText:#"foo"];
}
Now, connect that action up to your button, and everything should work like a charm.
Note: You should probably use a method name that does not start with "set", since those are commonly used for property setters as part of Cocoa's KVC/KVO system. Instead, I would call it something like changeLabel, or equivalent.
Your instance of customClass here is completely unrelated to the NIB. You've instantiated a new object using +alloc. If you want to modify the specific MyCustomClass in your NIB, then FirstViewController needs an IBOutlet that points to it.
UILabel also have a property called text to set the value, you might find that easier.
myObject.myLabel.text = #"Your text";
well you called your label two things, first a non-ibaction then an ibaction in the property.