My problem is that I want to give a object back from child view (controller) to a parent view (controller). I pass the object with a call like this:
parentView.someObject=objectFromChild;
Everything is okay until the child view gets deleted (because it is poped up and no pointer shows on it) but then the object passed from child view to parent view gets also deleted. Can anyone tell me how to make it possible to save my object(even if the view which created it, is deleted)? With NSString my method works very well...but with objects I always get EXC_BAD_ACCESS
Make sure the parent object is retaining it.
Sounds like there are a couple of challenges here and I'll try to give some simple tips.
Passing Data
If you want to pass an object upward from a child to a parent, design your Child class so that the object or variable is a public property. Then, any other object (like Parent objects that own the Child) can access that property.
Keeping Data Alive
Usually EXC_BAD_ACCESS means the object has already been deleted by the system. Tell the system you want to hang on to the object by setting 'strong' in the property declaration, and this will take care of your EXC_BAD_ACCESS problem.
Take a look at the following code for an example of how to implement a very simple parent/child data relationship and retain data.
//****** Child.h
#interface Child : NSObject
// Child has a public property
// the 'strong' type qualifier will ensure it gets retained always
// It's public by default if you declare it in .h like so:
#property (strong, nonatomic) NSString *childString;
#end
//****** ParentViewController.h
#import <UIKit/UIKit.h>
#import "Child.h"
#interface ParentViewController : UIViewController
#property (strong, nonatomic) Child *myChild;
#end
//****** ParentViewController.m
#implementation ParentViewController
#synthesize myChild;
- (void)viewDidLoad {
[super viewDidLoad];
// create child object
self.myChild = [[Child alloc] init];
// set child object (from parent in this example)
// You might do your owh setting in Child's init method
self.myChild.childString = #"Hello";
// you can access your childs public property
NSLog(#"Child string = %#", self.myChild.childString;
}
Related
This question already has answers here:
Objective-C declared #property attributes (nonatomic, copy, strong, weak)
(4 answers)
Closed 6 years ago.
I was trying to pass a custom object to the next view controller and I encountered this error -[ClassName copyWithZone:] unrecognized selector sent to instance
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"attemptDetails"])
{
ResultsVC *vc = segue.destinationViewController;
vc.selectedEntry = selectedEntry;
}
}
#property (nonatomic, retain) ClassName *selectedEntry; //Why is it retain and not copy?
I'm still very confused with property attributes and why certain types use certain attributes, like NSString uses (nonatomic, copy) and CLLocationCoordinate2D uses (nonatomic, readonly).
Could someone explain or link a reference to me how each property attribute works? Much thanks!
There are lots of descriptions for property attributes explanation,
Reference links,
Objective-C ARC: strong vs retain and weak vs assign
https://stackoverflow.com/a/4511004/4294543
#property and retain, assign, copy, nonatomic in Objective-C
Short & simple my understanding is like,
retain : It's working on the created object, and it just increase the reference count.
Here in your case you have already model class object so not need to copy in the second vc property,you just need to retain it to second vc property.
copy : The value you assigned to property can be copied & used for other purposes too(create shallow copy of object & need when object is mutable & need to release after finish with it).
nonatomic : Thread access is faster but you can't simultaneously access & change your property.
readonly : You can't directly assign the property new value.
Even i have run your case in the my project,
#import "ViewController.h"
#import "TestViewController.h"
#import "CustomClass.h"
#interface ViewController (){
CustomClass *classT;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
classT = [[CustomClass alloc]init];
classT.test = YES;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)btn:(id)sender {
TestViewController * vc = [self.storyboard instantiateViewControllerWithIdentifier:#"TestViewController"];
vc.className = classT;
[self presentViewController:vc animated:YES completion:nil];
}
#end
#import <UIKit/UIKit.h>
#import "CustomClass.h"
#interface TestViewController : UIViewController
#property (nonatomic,retain) CustomClass *className; // Work as i said
//#property (nonatomic,copy) CustomClass *className; // Makes a copy of an object, and returns it with retain count of 1. If you copy an object, you own the copy. This applies to any method that contains the word copy where “copy” refers to the object being returned thats why here you will get crash
#end
I have read couple of good article for memory management. According to rypress
Retain Attribute : The retain attribute is the Manual Retain Release version of strong, and it has the exact same effect: claiming ownership of assigned values. You shouldn’t use this in an Automatic Reference Counted environment.
Copy Attribute : The copy attribute is an alternative to strong. Instead of taking ownership of the existing object, it creates a copy of whatever you assign to the property, then takes ownership of that. Only objects that conform to the NSCopying protocol can use this attribute.
Even I went through some good link of stackoverflow as well. Joshua Nozzi's answer gave good explanation for retain vs copy.
Retain vs. Copy - Declared properties use retain by default (so you can simply omit it altogether) and will manage the object's reference count automatically whether another object is assigned to the property or it's set to nil; Use copy to automatically send the newly-assigned object a -copy message (which will create a copy of the passed object and assign that copy to the property instead - useful (even required) in some situations where the assigned object might be modified after being set as a property of some other object (which would mean that modification/mutation would apply to the property as well).
Also found good example here.
Code :
NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:#"First",#"Second", nil];
NSMutableArray *copiedArray = [array mutableCopy];
NSMutableArray *retainedArray = [array retain];
[retainedArray addObject:#"Retained Third"];
[copiedArray addObject:#"Copied Third"];
NSLog(#"array = %#",array);
NSLog(#"Retained Array = %#",retainedArray);
NSLog(#"Copied Array = %#",copiedArray);
Output :
array = (
First,
Second,
"Retained Third"
)
2013-12-19 17:15:49.380 RetainVsCopy[2876:c07] Retained Array = (
First,
Second,
"Retained Third"
)
2013-12-19 17:15:49.381 RetainVsCopy[2876:c07] Copied Array = (
First,
Second,
"Copied Third"
)
See, both array and Retained Array are having same contents. This is because both are pointing to same memory/instance/object. Where as contents of Copied Array are different. This is because copy created a separate instance.
In Objective C you will find that each class actually has a structure behind it. The properties are shortcuts which create the value in structure, a getter and a setter. For instance:
#interface MyClass
#property id myValue;
#end
Will create:
#interface MyClass {
id _myValue;
}
#property id myValue;
#end
#implementation
- (id)myValue {
return _myValue;
}
- (void)setMyValue:(id)myValue {
_myValue = myValue;
}
#end
Now these flags such as retain and copy add additional logic to the setters and getters. Using copy will actually create a setter as:
- (void)setMyValue:(id)myValue {
_myValue = [myValue copy];
}
Which means that the value must have the copy method implemented. Since your object does not it crashes.
Why to use copy is for safety. This is rarely important for something as strings but it is important for something like an array. So for instance you create a property #property NSArray *myArray; which expects an un-mutable array but the problem is that you can set a mutable array as well: myClassInstance.myArray = [[NSMutableArray alloc] init];. Now 2 modules have the access to the same mutable array. So if the first object starts modifying the array while the other one expects the array to always be the same you may find some issues. For instance MyClass instance may use it as a data source for the table view and at some point the array is mutated but the cells are not added/removed and the table view will cause a crash.
To be honest you can simply leave all of these as default and modify them only when you really need to. The case like above is highly unlikely anyway.
Let say, I have the code below
self.customObj = self.assembly.customObj() as? NSObject
let temp3 = self.assembly.customObj() as NSObject
If I use TyphoonScopeObjectGraph for customObj, it should return the same instance.
But when I debug, the customObj properties are not the same as shown:
As far as I understand, customObj and temp3 should be the same instance. But as you see in the image, customObj and temp3 have the same ObjectiveC.NSObject address but all of its properties (_shortFormatter, _longFormatter) have different address. What happen? How we can get the same instance for customObj and temp3. An example is very helpful.
Thanks.
You can get the project source code from here
In the example above if you want self.customObj and temp3 to be the same instance, then you need either TyphoonScopeSingleton or TyphoonScopeWeakSingleton.
The way TyphoonScopeObjectGraph works is that during resolution if two instances declare that they depend on another component called context, then the same shared instance of context will be returned. However these are not retained by Typhoon. So you can load a whole object graph (eg a view controller, along with dependencies) and then discard it when done, rather than use singletons, as you might otherwise. TyphoonScopeObjectGraph is also useful for having circular dependencies, such a a controller and view, that has a delegate property pointing back to the controller.
It helps to explain with an example: Let's say we have:
#interface MyViewController : UIViewController
#property(nonatomic, strong, readonly) InjectedClass(ShoppingCart) cart;
#property(nonatomic, strong) InjectedClass(MyView) view;
#end
#interface MyView : UIViewController
#property(nonatomic, strong, readonly) InjectedClass(ShoppingCart) cart;
#end
//ShoppingCart has object-graph scope
#interface ShoppingCart
#end
Now if we ask Typhoon to give us an instance of of MyViewController, then a controller will be returned where both MyViewController and MyView will have the same instance of ShoppingCart
If TyphoonScopePrototype was used, then each would have a different instance of ShoppingCart
If TyphoonScopeSingleton was used, then each would have the same instance of shopping cart, but there'd be no way to release the memory.
. . so you see TyphoonScopeObjectGraph loads an object graph with shared instances, but allows that whole object graph to be discarded after the use-case.
I notice that Apple has what seems to be duplicate variable names:
2 properties and two ivars. Why does Apple do this?
//.h file
#interface TypeSelectionViewController : UITableViewController {
#private
Recipe *recipe;
NSArray *recipeTypes;
}
#property (nonatomic, retain) Recipe *recipe;
#property (nonatomic, retain, readonly) NSArray *recipeTypes;
And they then update the recipe instance below. Why have two variable with the same name?
Will one affect the recipe variable of the parentViewController since that recipe variable was set when presenting this view controller the code was in from the parentViewController?
//.m file
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// If there was a previous selection, unset the accessory view for its cell.
NSManagedObject *currentType = recipe.type;
if (currentType != nil) {
NSInteger index = [recipeTypes indexOfObject:currentType];
NSIndexPath *selectionIndexPath = [NSIndexPath indexPathForRow:index inSection:0];
UITableViewCell *checkedCell = [tableView cellForRowAtIndexPath:selectionIndexPath];
checkedCell.accessoryType = UITableViewCellAccessoryNone;
}
// Set the checkmark accessory for the selected row.
[[tableView cellForRowAtIndexPath:indexPath] setAccessoryType:UITableViewCellAccessoryCheckmark];
// Update the type of the recipe instance
recipe.type = [recipeTypes objectAtIndex:indexPath.row];
// Deselect the row.
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
UPDATE 1
This code is from Apple's iPhoneCoreDataRecipes core data example:
First have a look at the RecipeViewController's didSelect delegate method, which will present the TypeSelectionViewController (child) view controller. Then have a look at that viewcontroller's didSelect delegate method where you will find the code implementation.
The reason I started looking at this is because I was interested how the parent's tableView cell got updated based on the selection in the ChildViewController in editing mode.
To see this for yourself, do the following:
Run the application
Select the Recipes tab
Click on a recipe - Chocolate Cake.
Click the edit button on the top right
Make note of the current category - should be on desert - then click on it.
Then you will be taken to the child view controller
Click on a different category, then click back and you will notice that the category button for that recipe has magically been updated. And I don't know how that's happening.
Does it have something to do with the private ivars and properties? which affects the parentViewController's cell?
My question i Guess is, how does selecting a category type in the child view controller's table affect the cell.text in the Parent View Controller's table? I can't see where the managedObjectcontext is saved in the child view controller for it to automatically update the parent View controller's cell text.
What you're seeing here is relatively old code, and there's not much need to do this anymore, thanks to Objective-C auto-synthesis.
Nowadays, when you issue a #property (nonatomic) NSArray *foo;, you implicitly get a #synthesize foo = _foo; in your implementation file and an instance variable declaration in your header. You don't see this, the compiler "inserts" it automatically. foo is the property and _foo is the instance variable. (In your above example, the #property and backing instance variable are both the same name, which could get confusing very quickly. With the foo property, you couldn't accidentally say self._foo, that doesn't exist. There's self.foo and _foo. With your example recipe is the ivar and self.recipe is the property. Very easy for one to quickly confuse the two when reading code.
Before the auto-synthesis, there was an intermediate step where you still needed a #synthesize, but you the backing instance variable was generated for you. These new features help you remove boilerplate code.
Answering Update 1
The code doing what you're wondering is in tableView:cellForRowAtIndexPath. There's nothing magical here. When you selected a new Category via the TypeSelectionViewController, the NSManagedObject is updated. Back in the RecipeDetailViewController, cellForRowAtIndexPath pulls the lasted information from CoreData. text = [recipe.type valueForKey:#"name"];
You might be getting confused about what an #property really is. It's just syntactic sugar. A #property these days automatically creates accessor and mutator methods and a backing ivar. Properties themselves aren't areas to store data, it's just a quick way of generating some methods and backing ivars.
Example
#interface MyClass
{
NSUInteger _foo;
}
#end
#implementation MyClass
- (NSUInteger)foo
{
return (_foo)
}
- (void)setFoo:(NSUInteger)newFoo
{
_foo = newFoo;
}
#end
is equivalent to:
#interface MyClass
#property (nonatomic, assign) NSUInteger foo;
#end
You save a lot of typing. When you get into things like NSString properties and different property modifiers like strong or copy, the amount of code you save (and memory management mistakes you avoid) in the mutators becomes much greater.
Your .h file should be your public api. You can re-declare your properties in your .m, implementation file, which are also considered private. For example
.h
#interface MyViewController : UITableViewController
#property (readonly) NSString *name;
#end
.m
#implementation MyViewController
#property (readwrite) NSString *name
#end
Here we are declaring a public name property that is readonly and in your implementation you 're re-declaring the property so that you can use the setter accessor.
I have an app where I have a long routine to draw out a pdf document. I need to access this from a number of view controllers but I am not sure how. As the moment the code is copied into each of the VC's .m file which I know is ridiculous. One of the problems is that each VC has a large number of variables that need to be sent to the MakePdf routine and sending data between VCs appears to be problematic (or at least that is what I am beginning to understand).
Any pointers?
This is what I would like:
You should make a class, with a singleton methods (like "+sharedObject") with all the code.
Then you access it with this code :
[[MyClass sharedObject] mySharedMethodForPdf];
http://www.johnwordsworth.com/2010/04/iphone-code-snippet-the-singleton-pattern/
You could make all your view controllers that need access to this method (and any others) a subclass of a class which implements this function. They would then all inherit the make pdf code.
I'd definietly create an abstract UIViewController class that holds the common characteristics, or a protocol at least, something like <PDFMakerDataSource>.
The PDFMaker singleton could be fine, define an activeViewController property on PDFMaker.
So when the VC appears, I'd set that property, then you can call make on PDFMaker, that will use the currently bound VC as data source.
Anyway, why singletons? Why don't just create a PDFMaker object? You can create it with every VC, so every VC should have an instance of it.
Something like:
#interface PDFMaker : NSObject
+(id)pdfMakerWithDataSource:(id<PDFMakerDataSource>) dataSource;
-(void)makePDFwithCompletion:(void(^)(id PDF)) completionBlock;
#end
And the data source, like:
#protocol PDFMakerDataSource <NSObject>
#optional
-(NSString*)fileName;
-(UIImage*)coverImage;
-(NSString*)whateverData;
#end
So in every VC of the world can be now PDFMaker compilant, like:
#interface SomeViewController : UIViewController <PDFMakerDataSource>
#property (nonatomic, strong) PDFMaker *pdfMaker;
#end
#implementation SomeViewController
-(void)viewDidLoad
{
[super viewDidLoad];
self.pdfMake = [PDFMaker pdfMakerWithDataSource:self];
}
// PDFMaker data source implementation (bind to UI for example)
-(NSString*)fileName
{ return self.fileNameTextField.text; }
-(NSString*)coverImage
{ return self.coverImageView.image; }
...
// Make That PDF
-(IBAction)makePDF
{
[self.pdfMaker makePDFwithCompletion:^(id PDF)
{ NSLog(#"Shiny PDF just made: %#", PDF); }
}
#end
I have parent UIViewController A which has some properties. And I have child UIViewController B,C,D which are inheriting from A.
My question is:
In the B, I change Parent properties value. How can C,D know Parent value is changed from B?
Basically I want to share properties between children.
Thanks in advance.
Code example;
#interface A : UIViewController{
NSString *string1; //This is just example
}
#property (nonatomic, strong) NSString *string2;
#end
Child B
#interface B : A
#end
#implementation B
//here I change string1 and string2;
#end
Child C
#interface C : A
#end
#implementation C
//here I want to get changed string1 and string2 by Child A;
#end
Child D
#interface D : A
#end
#implementation D
//here I want to get changed string1 and string2 by Child A;
#end
At the moment, I am using Singleton to store all the value and It is working well, but I think there should be better way in such situation?
I guess that the simplest thing that you can do is have the property that is inherited, but override the getter and setter in the parent view so that it read/write to a static variable.
#interface A : UIViewController
#property (nonatomic, strong) NSString *sharedString;
#end
#implementation A
static NSString* _sSharedString;
- (NSString*) sharedString {
return _sSharedString;
}
- (void) setSharedString: (NSString*) aString {
_sSharedString = aString;
}
#end
You may wish to synchronize the property.
This, thinking out of the code, will change the value for all children. I understood that that was what you needed (only value sharing), but if you also need a notification when the value changes you could add some method that notifies children (instances) whenever value changes.
You could have the parent class send a message when its properties change. Subclasses could implement a method for that message, and in it do whatever they have to do to adapt to the change.
I seem to remember something like this already being built in to Cocoa though...
Ahh. Here it is. Look into Key-Value Observation. Cocoa will automatically send messages when a property changes, as long as the properties are KVC compliant. You just have to implement a method in the child to handle them, and subscribe to the change events.
So in your child class, you'd say something like
[self addObserver:self
forKeyPath:#"thePropertyName"
options:NSKeyValueObservingOptionNew
context:nil];
and have a method like
-(void) observeValueForKeyPath:(NSString*)keyPath
ofObject:(id)observee
change:(NSDictionary*)change
context:(void*)context
{
// here's where the magic happens
}
keyPath will be the name of the property that changed, and change will contain the new value under a certain key with a constant name (the name's NSKeyValueChangeNewKey, no quotes). (You can generally just look up the new property as well.)
If there will be a lot of properties to watch, this might get cumbersome for each child to subscribe to each property's changes. How you'd handle that depends on how exactly everything's related, but eh. Having to care so much about the parent is kind of a smell in itself...