I have a singleton I implement in this way:
PhotoViewController* sharedSingleton = [PhotoViewController sharedManager];
I know that to launch a method I have to do [sharedSingleton method];
but what if I want to change an integer declared in the PhotoViewController.h file as NSInteger* tagNumber, hoe can I do that? I tried this:
[sharedSingleton.tagNumber = 1];
but it doesn't work!
EDIT:
error: property tagNUmber not found on object of type photoViewController
#interface PhotoViewController : UIViewController{
BOOL newMedia;
UIPopoverController *popoverController;
DBRestClient *restClient;
NSInteger* tagNumber;
}
+ (PhotoViewController *) sharedManager;
#end
Singletons are regular objects. The only difference is that only one instance will be created from the class.
If you aren't able to set the tagNumber it is likely that some other type of coding error is happening... perhaps the tagNumber property was declared in a class extension, making the accessor/mutator methods private?
If you edit your question with how the tagNumber is declared, and also include the error message you are getting, I'll be able to edit this answer and give you more specific advice.
EDIT: ...and yes, definitely double check to make sure you didn't declare the NSInteger to be a pointer... an NSInteger is a scalar type (so it takes a direct value, and doesn't use the dereference '*' operator).
I suggest using properties instead of accessing the instance variables directly:
#interface PhotoViewController : UIViewController
#property (nonatomic, assign) BOOL newMedia;
#property (nonatomic, strong) UIPopoverController *popoverController;
#property (nonatomic, strong) DBRestClient *restClient;
#property (nonatomic, assign) NSInteger tagNumber;
+ (PhotoViewController *) sharedManager;
#end
Then set the variable without the brackets as:
sharedSingleton.tagNumber = 1;
Related
I'm trying to implement a Dynamic property in my project
This is my code.
MyClass.h
#interface MyClass : UIView
#property (strong, nonatomic) NSString *name;
#end
MyClass.m
#implementation MyClass
#dynamic name;
-(void)setName:(NSString *)name{
self.name = name;
}
#end
But when I run my app has crashed.
When I use an ivar had this error.
A property is just a bundle of two methods: a getter and a setter. So, when you write
#property (strong, nonatomic) NSString *name;
what you are really saying is
- (NSString *)name;
- (void)setName:(NSString *)name;
After that, each time the compiler encounters an expression of the form obj.name, it translates it to [obj name]. And each time you see a statement like obj.name = #"hello";, the compiler translates it to [obj setName:#"hello"].
The next thing is you have to make sure the property behaves properly. You have many options:
Write getters and setters manually, referring to an iVar
Synthesize getter and setter
Autosynthesize getter and setter
Write custom getters and setters
Use #dynamic to avoid compile time warnings, because you intend to do runtime magic. (Really, that's not what you want to do, because you need to understand the basics first.)
Write getters and setters manually, referring to an iVar
#interface MyClass : UIView {
NSString *_name;
}
#property (strong, nonatomic) NSString *name;
#end
and in the implementation
#implementation MyClass
- (NSString *)name {
return _name;
}
- (void)setName:(NSString *)name {
_name = name;
}
#end
Synthesize getter and setter
The last section is basically equivalent to this
#interface MyClass : UIView {
NSString *_name;
}
#property (strong, nonatomic) NSString *name;
#end
#implementation MyClass
#synthesize name = _name;
#end
Autosynthesize getter and setter
In practice, you would just use "autosynthetisation".
#interface MyClass : UIView
#property (strong, nonatomic) NSString *name;
#end
#implementation MyClass
#end
This means,
if you just declare a property
don't call #synthesize or #dynamic
don't implement any custom getter and setter
the code above will just create an iVar named _name and a getter and setter that looks exactly like the one in the first example.
This means that the the first two and this sections are equivalent, because they produce the same code.
Write custom getters and setters
This is what the term "dynamic property" really means. For example, you may want the name to be always uppercase. So you may write a property like this.
#interface MyClass : UIView {
NSString *_name;
}
#property (copy, nonatomic) NSString *name;
#end
#implementation MyClass
- (NSString *)name {
return _name;
}
- (void)setName:(NSString *)name {
_name = [name uppercaseString];
}
#end
(in the code above, I changed strong to copy - don't worry, this is just a comment anyways. And it's a true one, because the uppercaseString will never be the same, it will always be a copy of the original.)
This is maybe the only really interesting case! For example, this kind of property is what UIKit uses all the time, e.g. the text property of UILabel is a dynamic property like that. It doesn't just set some iVar, but it also makes sure that the visible text on the screen changes too.
#dynamic properties
they are really tricky to get right, and most of the time they are not worth the hassle IMHO.
Note: I simplified some things and left out details which are only detectable when using objc runtime inspection APIs
This StackOverflow answer: https://stackoverflow.com/a/1160545/7833793 does a good job of explaining what the differences between #synthesize and #dynamic are. Typically you use #dynamic if you're delegating the task of implementing the accessors (get, set). It seems to me like you would want to use #synthesize here. But with modern objective c, you shouldn't even need to specify and the iVar will be created for you automatically.
i.e.:
MyClass.h
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
#interface MyClass : NSObject
#property (strong, nonatomic) NSString *name;
#end
NS_ASSUME_NONNULL_END
MyClass.m
#import "MyClass.h"
#implementation MyClass
- (void)setName:(NSString *)name {
_name = name;
}
#end
Your solution leads to recursion, you are getting crash since you are not using ivar in setter, try this instead:
-(void)setName:(NSString *)name{
_name = name;
}
I have surfed quite a lot about this. But the results that I've got tells me that either I should use appDelegate or singleton etc.
All of which produces the same result. i.e I am able to share a variable in different ViewControllers but as soon as the ViewController gets changed , the variable looses it's value.
For example I used a variable named myVar of type int. I declared it in AppDelegate and then I'm able to use it in all the ViewControllers with the help of AppDelegate. But as soon as I move from A ViewController to B ViewController the value of the myVar variable gets "0" again. I don't want that . I want the variable to hold it's value. And I don't want to pass this data with the help of pushViewController etc. Please suggest me a good solution.
AppDelegate.h
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (strong, assign) int myVar;
#end
FirstViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
AppDelegate* app = (AppDelegate*)[UIApplication sharedApplication].delegate;
app.myVar = 1;
NSLog(#"%d",app.myVar); //Shows "1" in Log
}
SecondViewController.m
- (IBAction)pressButton:(id)sender{
AppDelegate * app = (AppDelegate*)[UIApplication sharedApplication].delegate;
NSLog(#"%d",app.myVar); // Shows "0" in Log (But I want it to show "1" as I have already set "myVar" value as "1" in my FirstViewController)
}
Your #property (strong, assign) int myVar; is declaring both strong and assign. As an int, it should only be assign, not strong. strong would be used for Objective-c objects, assign for primitive C properties.
I think what you want is the following:
#property (assign, nonatomic) int myVar;
First of all check your code there are some error
AppDelegate.h
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (nonatomic, assign) int myVar;
And check it gives same value in FirstViewController.m and SecondViewController.m
if your var is a NSString, you can simple use the [copy] protocol. e.g.
NSString *eString = [cString copy];
If it is an object, you need to implement the [copy] protocol for that class.
I'm going through a tutorial on core-data in Objective-C and can't understand the following syntax:
#interface RootViewController : UITableViewController <CLLocationManagerDelegate> {
NSMutableArray *eventsArray;
NSManagedObjectContext *managedObjectContext;
CLLocationManager *locationManager;
UIBarButtonItem *addButton;
}
#property (nonatomic, retain) NSMutableArray *eventsArray;
#property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, retain) CLLocationManager *locationManager;
#property (nonatomic, retain) UIBarButtonItem *addButton;
#end
We have four properties here that are declared in the implementation file, which to my understanding means they are private. What exactly is happening within the curly brackets? Why are these variables put there? And also, is it a class extension? I see () are missing here so probably it is not. What is this kind of syntax called then?
Its not a category.Its just a class named RootViewController which extends UITableViewController and implements protocol CLLocationManagerDelegate.
Coming to your braces ->
generally if you don't create iVars in curly braces, by default they are created with underscore as prefix to them. This is done by compiler.
But here, you explicitly said, that the ivar should be without underscore(_).
Any you should synthesize them as below or else it will give a warning.
#synthesize eventsArray= eventsArray;
It's just a regular definition of a RootViewController class, the #interface doesn't necessarily have to be in a header file, private classes (that shouldn't/don't need to be accessible elsewhere) can also be defined directly in the .m file.
The definitions in the curly braces are just regular instance variables of the RootViewController class.
What you have is called the class interface. It is just the .h file of your program files. .If you want a class category, just do
#interface RootViewController (CategoryName)
and for an extension, inside the .m type
#interface RootViewController ()
#end
#implementation
Variables between curly braces:
{
NSMutableArray *eventsArray;
NSManagedObjectContext *managedObjectContext;
CLLocationManager *locationManager;
UIBarButtonItem *addButton;
}
are just usual variables.
For variable, defined with #property base word:
#property (nonatomic, retain) NSMutableArray *eventsArray;
#property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, retain) CLLocationManager *locationManager;
#property (nonatomic, retain) UIBarButtonItem *addButton;
created accessor and mutator methods. And also you can define options for those variables in bracers. Plus you can get local synonym for them, using base word #synthesize in .m file, like
#synthesize addButton = myLovelyButton;
then you can use myLovelyButton in .m file instead addButton
Both of these definition do not belong to the category.
For define category just type code like:
#interface <#className#> (<#categoryName#>)
{
//optional variables here
int i;
NSString *s;
}
//optional variables here
#property NSString *str;
//optional methods here
-(void)doSomething;
#end
Then you can implement your methods and use these variables:
#implementation <#className#> (<#categoryName#>)
-(void)doSomething
{
int i = 0;
str = #"blah";
s = #"wow";
NSLog(#"%i - %# - %#",i,str,s);
}
#end
Use that for add your methods to existing classes.
Variables inside brackets directly after the #interface or #implementation are instance variables. These are variables associated with each instance of your class, and thus accessible anywhere in your instance methods.
If you don't put the brackets, you declare global variables. Any variable declared outside of any bracket block will be a global variable, wether these variables are before or after the #implementation directive. And global variables are evil and needs to be avoided at all costs (you can declare global constants, but avoid global variables), especially because they are not thread-safe (and may thus generate bugs that are a mess to debug).
#interface YourClass : ParentClass
{
// Declare instance variables here
int ivar1;
}
// declare instance and class methods here, as well as properties (which are nothing more than getter/setter instance methods)
-(void)printIVar;
#end
// .m
int someGlobalVariable; // Global variable (bad idea!!)
#implementation YourClass
int someOtherGlobalVariable; // Still a bad idea
-(void)printIVar
{
NSLog(#"ivar = %d", ivar1); // you can access ivar1 because it is an instance variable
// Each instance of YourClass (created using [[YourClass alloc] init] will have its own value for ivar1
}
Only modern compilers let you declare instance variables (still in brackets) also inside either your class extension (#interface YourClass () in your .m implementation file) or in your #implementation, in addition to the possibility to declare them after the #interface in your .h. The benefits being to hide those instance variables from external users of your classes, by declaring them in the .m file and not in the .h file anymore, because users of your class don't need to be aware of the internal coding details of your class, but only needs to know the public API.
One final advice: instead of using instance variables, Apple more and more recommends to use #property directly, and let the compiler (explicitely using the #synthesize directive, or implicity with modern LLVM compilers) generate the internal backing variable. So that at the end you generally won't need to declare instance variables at all, and thus omit the empty { } after the #interface directive:
// .h
#interface YourClass : ParentClass
// Declare methods and properties here
#property(nonatomic, assign) int prop1;
-(void)printProp;
#end
// .m
#implementation YourClass
// #synthesize prop1; // That's even not needed with modern LLVM compiler
-(void)printProp
{
NSLog(#"ivar = %d", self.prop1);
}
I'm developing an iOS 5.0+ app and I'm creating a Category for an UIButton:
#interface UIButton (NotificationBall)
#property (nonatomic, assign) NSInteger type;
#property (nonatomic, assign) NSInteger index;
#end
And its implementation:
#import "UIButton+NotificationBall.h"
#implementation UIButton (NotificationBall)
#dynamic type;
#dynamic index;
#end
Searching on internet I've found this question, but I haven't found any examples with NSInteger.
Do I need to use NSNumber instead of NSInteger?
If I use, NSNumber, what do I have to do?
Only Objective-C objects can be set as
associated objects, scalars cannot be used directly.
So you could declare the property as
#property (nonatomic, strong) NSNumber *type;
and directly use the code from the answer https://stackoverflow.com/a/5500525/1187415
that you referenced to.
Or you keep the NSInteger property, and wrap/unwrap it to NSNumber
in the getter/setter method like this:
-(void)setType:(NSInteger)type
{
objc_setAssociatedObject(self, &UIB_TYPE_KEY, #(type), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(NSInteger)type
{
return [objc_getAssociatedObject(self, &UIB_TYPE_KEY) integerValue];
}
Remark: "type" and "index" are quite common names. You should consider prepending the property names with some prefix, to
avoid a possible name collision with existing properties of UIButton.
I have faced a problem I can not see the problem to. I am trying to pass a simple NSString to a child variable but it continues to return as null even when I use NSLog to show there is a string in the variable.
The variable finalDate will not pass to the child view.
Parent View
ChangeTimeViewController *ChangeTimeView = [[ChangeTimeViewController alloc] init];
NSLog(#"%#", date);
ChangeTimeView.finalDate = date;
[ChangeTimeView setDelegate:self];
[self.navigationController pushViewController:ChangeTimeView animated:YES];
Child View .H
#import <UIKit/UIKit.h>
#protocol ChangeTimeViewControllerDelegate;
#interface ChangeTimeViewController : UIViewController <UIPickerViewDelegate, UIPickerViewDataSource>
#property (nonatomic, weak) id <ChangeTimeViewControllerDelegate> delegate;
#property (nonatomic) NSString *enteredTime;
#property (nonatomic, strong) UIPickerView *UIPicker;
#property (nonatomic, strong) NSString *finalDate;
#end
#protocol ChangeTimeViewControllerDelegate <NSObject>
- (void)childTimeViewController:(ChangeTimeViewController *)viewController didChooseValue:(NSString *)string;
#end
Child View .M
NSLog(#"%#", self->finalDate);
What you are doing is perfectly fine. You should insert the NSLog in the view(Did/Will)Appear or some similar method and you may use the self.finalDate notation to make sure you don't try to read some uninitialized ivar.
Note: properties synthesize ivars with _ as prefix (_finalDate is the correct storage unless you synthesized it it with some other name)
If you want to make sure that all input parameters are passed to the view controller, then create an init method for it. Similar to this:
- (id)initWithDate:(NSDate*)date delegate:(id)delegate
Pass NSString As ChangeTimeView.finalDate = #"This Is my Simple String"; and use/put NSLog in viewDidLoad method for show is it rich at nextViewController or not ?? Otherwise if your date (NSString) is proper then Your code is correct.
Check what is happening if you set like,
ChangeTimeView.finalDate = #"MyString";
and in view.m log NSLog(#"%#", self.finalDate);