I notice that a object pass between two view controllers has the same address in those two controllers. And if I change the value in controller B, the value of object in controller A is changed automatically.
That inspire me to consider the object is a singelton..For singelton design pattern, the advantage is using a global valuable to saving the system resource and keep the consistency of the object.What I am thinking is right? Is there any difference?
An object passed between two view controller can be the same object if
you use strong property.It also can be two different objects if
you use copy property.
If you use a singleton.It will be the same instance of one
class.When using singleton,you should be carefully manage the life
circle of it.
It is about design.
When using object pass between viewControllers,only the two viewControllers can access the object.
But,when using singleton,every place of your application can access the instance.
The Singleton design pattern ensures that only one instance exists for a given class and that there’s a global access point to that instance. It usually uses lazy loading to create the single instance when it’s needed the first time.
Apple uses this approach a lot. For example: [NSUserDefaults
standardUserDefaults], [UIApplication sharedApplication], [UIScreen
mainScreen], [NSFileManager defaultManager] all return a Singleton
object.
For more about Singleton design pattern go through the Link
In Objective-C or swift all what you call as "Object" is a pointer to object. It is not a object in C++ terms, it is a pointer in the C++ terms.
Because variable it is pointer, then you use a variable to call functions, the pointer is copied but not a pointed object.
But in Objective-C exist a C objects (structures (CGSize for example) and simple variables (int, float ...)), these variables will be copied if you will use them to call functions.
About properties: property it is methods (set and get, if property not readonly).
If property have parameter strong (retain):
#property (strong) NSObject* a
then it property can be implemented like a function:
- (void)setA:(NSObject*)a
{
_a = a;//or [_a release]; _a = [a retain]; if no ARC
}
If property have parameter copy:
#property (copy) NSObject* a
then it property can be implemented like a function:
- (void)setA:(NSObject*)a
{
_a = [a copy];//or [_a release]; _a = [a copy]; if no ARC
}
Property it is a method!
You can create many instances of any object classes:
NSObject* a = [[NSObject alloc] init];
NSObject* b = [[NSObject alloc] init];
a and b its pointers to different objects in a memory.
But if you not allocate b object:
NSObject* a = [[NSObject alloc] init];
NSObject* b = a;
a and b its pointers to one object in the memory.
About singleton: the singleton pattern is a design pattern that restricts the instantiation of a class to one object.
Related
In Objective-C one can make a singleton that does not have a sharedInstance or similar class call simply by making the -init method reference the status singleton variable, like so
static MyObject *sharedObject;
/*
* The init will return the actual singleton instance if called directly.
* The first time called it will create it and intialize it.
*/
- (instancetype)init
{
static dispatch_once_t once;
dispatch_once(&once, ^{
id myself = [super init];
if (nil != myself) {
[self initialize];
sharedObject = myself;
}
});
return sharedObject;
}
So a user could call this MyObject *myObject = [[MyObject alloc] init]; as many times as he wanted and would get the same object back each time. But it is not obviously, from syntax, a singleton.
I am trying to get a similar functionality in Swift, where I can return the same object each time (an NSObject subclass) but so that it is not obviously a singleton.
I would call it var myObject = MyObject() or when bridging to Objective-C as above but they would all reference the same object.
I am familiar with the normal sharedInstance method of singleton in Swift.
Suggestions on how to do this would be appreciated.
This is not the same as the dispatch_once in Swift answers as that still uses a sharedInstance
In Objective-C an initialiser is just like any other method that is called on an instance
[[alloc SomeClass] init]
You first alloc an instance and then explicitly invoke its initialiser.
init is able to return any object; returning self is just a convention that can be ignored in special cases, such as the one you have shown.
In Swift, init is special. An initialiser is invoked implicitly as part of the allocation
let x = SomeClass()
A Swift init implicitly returns self (or it can return nil in the case of failable initialiser that has failed). As a result, you cannot implement a "hidden singleton" in Swift by returning some other object.
I think you can do something similar to what you're looking for using Objective-C's associated objects. You can see a blog post about how to use it in Swift here: http://en.swifter.tips/associated-object/
I don't really understand the purpose of this though, necessarily- I think it would be desirable to make a singleton look like a singleton.
You can technically use these associated objects to create a function that always returns the same associated object, eg, func giveMeTheSameObjectEveryTime() -> AssociatedObjectType, which would be similar in syntax to init() -> AssociatedObjectType, but I think you're getting a similar effect to a singleton, since you'll have to create some boilerplate variables to hold the association, which is quite a bit more work than a simple static let sharedInstance property.
I have a few questions about this code:
#import "ViewController.h"
#interface ViewController ()
#property (copy, nonatomic) NSArray *myArray;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.myArray= #[#"one", #"two", #"three", #"four"];
}
I know the self keyword means that's method will be sent to the receiver of that message, and I know when and how to use it if i was creating a simple command utility code, but when learning about creating an iPhone app and using the storyboard every time I see the self keyword it confuses me, I don't know which object is the receiver
2nd question, I know that #[#"object", #"object"];is quick way to create an NSArray object, but "myArray" is a property not an NSArray object. please explain, thank you.
myArray is. The name of a property, as you say. By default, the compiler will create an instance variable called _myArray that's used by that property. In any case, because you've declared the property to be of type NSArray * (and not readonly) you can assign an array to it.
The self keyword is simply a pointer to the "current" object, some instance of the class that you're writing code for when you type "self". If you assign something to self.myArray, the class in which you make that assignment needs to have a myArray property. In your code example, self is a pointer to the particular instance of ViewController that just loaded its view. None of that changes when you're writing an iPhone apportion using a storyboard. self is always the object receiving the method in which self is used. (Note: when used in a class method, i.e. one that starts with +, the object receiving the method is the class itself, not an instance of the class. Don't worry about this if it sounds confusing -- it doesn't come up all that often.)
If you find an expression like self.myArray confusing, it may help to know that property syntax is just shorthand for a method call. Also, self in an expression like that isn't special at all. The syntax is foo.bar where foo can any object pointer (including self) and bar can be any property of the object pointed to by foo. The expression translates directly to either [foo bar] or [foo setBar:...], depending on whether you're reading or assigning a value to the property. So,
self.myArray = #[a, b, c];
means exactly the same as:
[self setMyArray:#[a, b, c]];
self always corresponds to the self class. So every instance of a class will have its own self.
In your case myArray is a property of Class ViewController. Here you can refer to the property by using self.myArray or _myArray.
In the following statement you are creating an array with four strings and adding it to myArray.
self.myArray= #[#"one", #"two", #"three", #"four"];
Your wordings in the question :
I know the self keyword means thats method will be sent to the
receiver of that message
is valid for a method call where you use it as :
[self aMethod];
Even in this you are calling a method which is a part of the class. If you call any method which is not of the current(self) class then you call it by using that class' object name as:
SomeClass *someClassObject = ...
[someClassObject itsMethod];
"self" is a pointer to object to which the method belongs. In your case you may have many instances of ViewController and each of them can call viewDidLoad and in that method "self" is the pointer to the instance itself. To look at it from the C perspective you could create a method using pointer to function where you would also send own pointer to the function called "self", for instance void foo(MyClass *self); to call it then myClassInstance->foo(myClassInstance); this procedure kind of simulates methods but you always need to send instance pointer as well (self). So there should be no confusion as to what "self" is except it is more commonly known by "this" keyword. It is just a reference to the object on which the method is being called.
The property is just a convenience of usually 2 methods called getter and setter. When creating a property #property NSArray *myArray you will actually generate a pointer usually NSArray *_myArray; then a getter:
- (NSArray *)myArray {
return _myArray;
}
And a setter
- (void)setMyArray:(NSArray *)myArray {
_myArray = myArray;
}
How getters and setters are created depends on property attributes (strong, weak, readonly...). You may even override any of these methods or both. So as you stated "but "myArray" is a property not an NSArray object" a property can have truly any type.
If we replace a NSDictionary instance variable with a NSMutableDictionary that we create, can we later use it again as a NSMutableDictionary by casting it as a NSDictionary?
Example:
create and store the NSMutableDictionary into the NSDictionary slot
NSMutableDictionary *muta = [[NSMutableDictionary alloc] initWithObjects:NSArray forKeys:NSArray];
Object.nsDictionary = muta;
Get the dictionary later
NSMutableDictionary *muta2 = (NSMutableDictionary*) Object.nsDictionary;
//Do stuff like Add objects with it
[muta2 setObject:id forKey#"key"];
Do we have to recreate a NSMutableDictionary from the NSDictionary we pull from the object or does it retain it's "mutability"? Can you please tell me why a subclassed object will or will not retain its specific methods and properties when replacing a generic super class?
If your property is declared as NSDictionary then you shouldn't make any assumptions about whether it is actually mutable or not.
The proper code should be:
NSMutableDictionary *muta2 = [Object.nsDictionary mutableCopy];
This works regardless of what type of dictionary is actually stored in the property.
In your question you are confusing two different things: you refer to assigning to an instance variable but show code which shows assigning to a property. These are not the same. You are also appear to be misunderstanding assignment by referring to it as replacing an object.
In Objective-C (and many other, but not all, languages) an object is referred to by a reference. It is these references which are assigned into variables. So for example in:
NSMutableDictionary *a = [NSMutableDictionary new];
NSMutableDictionary *b = a;
The right hand side of the first assignment is an expression which creates a new object and returns a reference to that object. This reference is then stored into the variable a. The second line copies the reference, not the object, stored in a and stores into into the variable b.
After these two lines one object and two variables have been created, and both variables reference exactly the same object. Assignment of a reference to an object does not change the object it refers to. So if we now change the code to:
NSMutableDictionary *a = [NSMutableDictionary new];
NSDictionary *b = a;
We still have one object and two variables created, and both still refer to exactly the same object. The assignment in this case is allowed as NSMutableDictionary is a subclass of NSDictionary - that is an object of type NSMutableDictionary is also of type NSDictionary, it provides all the same behaviour as the latter.
From your question "Can you please tell me why a subclassed object will or will not retain its specific methods and properties when replacing a generic super class?" you need to read up on inheritance and understand how subclassing works.
Once you've stored a reference to a subclass into a superclass typed variables, a into b in the above code, while you haven't changed the referenced object in anyway you have lost the immediate knowledge that the reference is in fact to an object of the subclass - all you can immediately state about a reference stored in b above is that it refers to an object which is at least an NSDictionary, but may be of any subclass of NSDictionary.
If you are absolutely sure, or just like writing programs that break, you can tell the compiler to trust you that b contains a reference to an NSMutableDictionary by using a cast:
NSMutableDictionary *c = (NSMutableDictionary *)b;
Do this and the compiler trusts you, but if b does not contain a reference to an NSMutableDictionary then your subsequent usage of c will probably be invalid and your program will break.
What you need to do is to test whether the reference refers to an NSMutableDictionary or not, and you do this with the method isKindOfClass::
if ([b isKindOfClass:NSMutableDictionary.class])
{
// b refers to an NSMutableDictionary
NSMutableDictionary *c = (NSMutableDictionary *)b;
// do something with c
}
else
{
// b does not refer to an NSMutableDictionary
// handle this case
}
Back to properties: a property is two methods (assuming read-write, you can have read-only properties), a getter and a setter, which combine to provide an abstraction of a variable - you can "read" and "assign" to them using dot notation in expressions. However as they call a method, rather than performing direct reads or assignments to a variable, that method can change was is read or assigned. In particular an object typed property declared with the copy attribute will make a copy of the object that is reference. For example:
#property (copy) NSDictionary *c;
...
NSMutableDictionary *a = [NSMutableDictionary new];
NSDictionary *b = a;
self.c = a;
then a & b both refer to the same object which is an instance of NSMutableDictionary; while, due to the copy attribute,crefers to a *distinct* object which is an instance ofNSDictionary`.
You can now see why using instance variable and property interchangeably in your question is not right - what is assigned can be different depending on whether the assignment is to a variable or a property.
You should read up on objects, object references, inheritance and properties.
HTH.
In my child view controller, I have a property defined as:
#property (nonatomic, copy) NSString *name;
In view controller A, the Parent, I have the following:
NSString *temp = currency.name; //This is because currency is a Core Data Managed Object.
//I wanted to make sure it wasn't a confounding factor.
childViewController.name = temp;
if(childViewController.name == temp)
NSLog(#"I am surprised");
The problem is that if statement finds equivalency and the "I am surprised" is printed. I thought that == should be checking if they're the same object, and that the use of copy in the property declaration should ensure the setter is making a copy. I checked in the debugger and they are both pointing to the same string. (Which I believe is immutable, which may be why this is happening?)
The same thing happens even if I write childViewController.name = [temp copy];, which I find shocking!
Can anyone explain what is going on here?
Edit: I removed a bit here on worrying about a circular reference which I realized wasn't a concern.
This is an optimization.
For immutable objects, it's superfluous to create an actual copy, so - copy is often implemented as a simple retain, i. e.
- (id)copy
{
[self retain];
return self;
}
Try assigning a mutable object (e. g. NSMutableString) to the property, and you will get the "expected" behavior.
Class name MyData has 75+ properties that are needed in throughout 7 Scenes.
Currently, I pass the the instance of MyData file with the code below:
in SceneOne:
MyData *myData = [[MyData alloc]init];
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
UIViewController *destinationViewController = segue.destinationViewController;
SceneTwo *sceneTwo = [destinationViewController isKindOfClass:[SceneTwo class]] ? (SceneTwo*)destinationViewController : nil;
sceneTwo.myData = self.myData;
}
This allows me to access any properties as myData.anyProperty
When the 7th Scene is dismissed, I set myData = NULL, and the app returns to SceneOne and a new instance of MyData is initialized.
I'm trying to accomplish above via sharedInstance.
MyData.h
#import <foundation/Foundation.h>
#interface MyData : NSObject {
#property (nonatomic, retain) NSString *someProperty;
// 74 other properties
+ (id)sharedData;
#end
MyData.m
#import "MyData.h"
#implementation MyData
#synthesize someProperty;
+ (id)sharedData {
static Mydata *sharedData = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedData = [[self alloc] init];
});
return sharedData;
}
#end
Question 1: Will the code above work to access the same instance with the code below in any of the Scenes:
MyData *myData = [MyData sharedData];
Question 2: Can I still access the files as myData.anyProperty ?
Question 3: How do I trigger a new instance of MyData and delete the current instance?
Question 4: I'm downloading a myData file off the web that's a duplicate of MyData class but the properties contain data, and I want Singelton to provide a new instance with the data from the downloaded file, what would be the code for that? i.e myData = [newDownloadedFile copy];
Question 5: Is there an advantage of using Singleton Method Vs. my current method?
Yes
Yes
You don't. Why do you believe this is necessary? Can you instead add a reset method to MyData?
You shouldn't mix the singleton pattern with a multiple-instance usage case. If you truly want a singleton, think about adding an additional layer to your data set. For example, you may have a local data and remote data configuration. If this is what you want, you may have to change the interface (header) of MyData to make this possible.
A singleton is a single instance of a class across a process. When you want to access the same collection of data from multiple locations in your code, a singleton object is one way you can accomplish this. Otherwise you need to instantiate an object and pass its address to all interested classes so they are each accessing the same instance. That's an oversimplification but I believe it addresses your question.
Regarding your comment for number 3, if you have a singleton, you don't want to reset the data for the entire app if you simply don't need the data in one place anymore. So consider the impact that would have. If you no longer need the MyData object, simply don't use it anymore. Singleton objects typically persist for the lifetime of an app, so it is not common to release/dispose of the object.
For number 4, say you currently have a property called player with a method declaration like this:
- (Player *)currentPlayer;
If you have multiple configurations available, you would add a parameter to your method interface and implementation like this:
- (Player *)currentPlayerForConfiguration:(NSInteger)configuration;
You could decide to use a number, string, or something else to differentiate between different configurations of your data. If you use a number, 0 could be local, 1 could be remote, 2 could be either (for example, check local data first, and if not there, then check remote). If you only have two options, you could use a BOOL and define your method like this:
- (Player *)currentPlayerUsingLocalData:(BOOL)useLocalData;