sharing objects in Objective-C - iphone

This is a noob question. If I have a ViewController and inside that class I have an object called UserInfo and other ViewController, lets just call it X,Y,Z, etc..etc.
What do I need to do so that those X,Y,Z can use the information of UserInfo?
Well I can have another info called UserInfo inside X,Y,Z and pass UserInfo inside, but I don't think this is good OOP technique. I think inheritance is needed here... but I don't think that it is right too, as the only commonality they have is only the UserInfo

View controllers are just objects, you have to remember that.
If you're in your first view controller and it has a property NSString *aString to pass it to the next view controller you just make the second view controller's NSString *aString property equal to the first one.
Basically do this:
MyNextViewController *viewControllerTwo = [[MyNextViewController alloc] initWithNibName:nil bundle:nil];
[viewControllerTwo setAString:self.aString];
if you subclass all you inherit are the properties, and not their values.

Related

Beginner confused about allocation notation

I was reading the Apple Documentation and came across this line:
SKView *spriteView = (SKView *) self.view;
I'm not confused about SKView, but rather the notation that is used. I have never seen it before and do not know what its called or how it works. Normally, if I wanted to create a view, I would do something like:
UIView *view = [UIView alloc]init];
Can someone explain the differences between the two notations or breakdown the first notation? I've seen this used in UIColor a lot as well. I don't know what this is called so I'm not exactly sure what I would have to search.
Normally, if I wanted to create a view...
The notation you're asking about, self.view, doesn't create a view directly. Dot notation is a simple way to access an object's properties. It's exactly the same as [self view]. The object that is self in your example is probably a view controller, and therefore has a view property which is accessed via a -(NSView*)view method and set via -(void)setView:.
Now, view controllers are lazy about loading their views -- they don't load (or create) the view they manage until it's needed. So, the -(UIView)view accessor looks something like:
-(UIView)view
{
if (_view == nil) {
[self loadView];
}
return _view;
}
So it's not the dot notation that creates the view, it's the fact that you're calling the -view method. Of course, since the view property is declared as a UIView* but your view controller manages an instance of SKView, you need to cast the value to SKView*.

pass int variable to UITableView Through UINavigationController

I'm trying to pass int variable to UITableView through UINavigationController (I'm using xcode 4.3) So I created 2 classes (PartsTableViewController that is "UITableViewController" and PartsNavController that is "UINavigationController"), I want to pass the variable from my current class to PartsTableViewController and then open that table with its Navigation controller that contains the title bar , so I wrote in my current class the following code:
PartsNavController *partsNav = [self.storyboard instantiateViewControllerWithIdentifier:#"partsNav"];
partsNav.groupId = myGroupp.bg_id;
[self presentModalViewController:partsNav animated:YES];
and in the PartsNavController class I wrote in viewDidLoad:
PartsTableViewController *parts = [self.storyboard instantiateViewControllerWithIdentifier:#"Parts"];
parts.groupId = groupId;
[parts.tableView reloadData];
and in PartsTableViewController I wrote in viewDidLoad:
NSLog(#"This is group: %d", groupId);
but when run, it generates the output 2 times,
This is group:1
This is group:0
first time is the value that I sent and the second time it outs 0 , I just want the value that I sent, not 0
how can I prevent this and get just the value that I sent ????
I want to pass from (MaktabatyTableViewController) to (PartsTableViewController) without using segue
The better way to do what you want is to push second TableViewController in existing UINavigationController. The easiest way to do that is to create that NavContr in StoryBoard and than to TableViews and connect it's cell with leading view controller with segue. And than use method below:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
UIViewController *destViewController = segue.destinationViewController;
destViewController.integerValue = value;
}
I want to pass from (MaktabatyTableViewController) to
(PartsTableViewController) without using segue
There are (at least) two strategies you can choose from:
Direct communication: People often ask how to communicate between two objects, and it almost always boils down one of the objects having a reference to the other (and sometimes vice versa). To send a message to an object, you need a pointer to that object; if you've got the pointer, there's no mystery about how to communicate. Thinking about it in those terms helps you think about the issue a little differently: instead of the immediate "how do I send a message to that object?" you can instead focus on the relationship between the two objects. How was each one created? Is one of the objects the parent of the other? Is there some common parent object that can provide a pointer? How should the objects be related, if at all?
Indirect communication: Sometimes instead of having two objects communicate directly, it's more appropriate to route the communication through some intermediate object. For example, your MaktabatyTableViewController might send a message to its delegate, and the delegate could then pass the information on to PartsTableViewController. A much more general solution is to use notifications: MaktabatyTableViewController could post a notification that PartsTableViewController listens for. The intermediate object in this case is the notification center. Either way, the advantage that you get with indirect communication is that neither object has to know about the other. That reduces coupling between the two classes and makes them both more flexible and more reusable.
From what I can see in your question, I'd suggest using notifications.

Objective-C (iOS) Access UITextField's text from another class

this question is extremely basic and I apologize if the answer should be staring me in the face.
So: I have a UITableView and another viewController. I'm updating some information for CoreData in the UITableView's .m file. In order to do this I need the text in a text field in the other viewController.
So being rather inexperienced, I tried:
[entity setName:[NSString stringWithFormat:#"%#", viewController.entityNameInputField.text]];
I've renamed a few things for clarity. Entity is my entity (no kidding), the attribute I'm setting is called Name, viewController is where the textField is and the text field is called entityNameInputField.
I'm a lot more interested in why this sort of thing doesn't work than what the solution to my problem might be. Why can't I just get the text from the text field in this way?
I suppose to word everything differently:
If I'm in Class A and I want to access the value of say, an NSString in class B, why can't I just use ClassA.TheString or [ClassA TheString] .... from what I've managed to understand, I'm sending these objects getter methods and I can't seem to see why this doesn't work...
Any help would be appreciated :)
Some more code would be useful to see what might be causing your confusion, but if you have declared properties in your classes the associated instance variables (or have manually declared accessors) then you will be able to access the associated ivars.
So, something like this (below) will work fine.
MyClassA * instanceOfA = [[myClassA alloc] init];
MyClassB * instanceOfB = [[myClassB alloc] init];
instanceOfA.myProperty = instanceOfB.myProperty;
As far as I understand, this is not a problem of accessing values from another class. Assuming that both view controllers are retained in memory, you can always call each other's getters/setters.
I assume that you've got a UITableViewController named A and then you're presenting a custom UIViewController named B with a text field. The user taps something in the text field and you want this text to go back to your table view controller. If inside B you have a valid reference to A, you can then call it's setter for the appropriate variable, and then dismiss the custom controller.
For example, in B's header you could have:
#interface MyViewController : UIViewController {
id tableViewController;
}
#property (nonatomic, retain) id tableViewController;
then in A, when you're creating B:
MyViewController *B = [[MyViewController alloc] init];
B.tableViewController = self; // this passes a reference to A
so when you're in B and the user has entered input in the text field, you could do something like
[self.tableViewController setVarname:textField.text];
assuming there's a varname variable in A, and a textField in B.
You can also gain access to A without having to create a separate variable, by calling
[self parentViewController]
if that suits you better.

Setting ivar in objective-c from child view in the iPhone

Maybe a FAQ at this website.
I have a TableViewController that holds a form. In that form I have two fields (each in it's own cell): one to select who paid (single selection), and another to select people expense is paid for (multiple selection).
Both fields open a new TableViewController included in an UINavigationController.
Single select field (Paid By) holds an object Membership
Multiple select field (Paid For) holds an object NSMutableArray
Both vars are being sent to the new controller identically the same way:
mySingleSelectController.crSelectedMember = self.crPaidByMember;
myMultipleSelectController.crSelectedMembers = self.crSelectedMembers;
From Paid for controller I use didSelectAtIndexPath method to set a mutable array of Memberships for whom is paid:
if ([[tableView cellForRowAtIndexPath:indexPath] accessoryType] == UITableViewCellAccessoryCheckmark) {
[self.crSelectedMembers removeObject:[self.crGroupMembers objectAtIndex:indexPath.row]];
//...
}
else {
[self.crSelectedMembers addObject:[self.crGroupMembers objectAtIndex:indexPath.row]];
//...
}
So far everything goes well. An mutable array (crSelectedMembers) is perfectly set from child view.
But...
I have trouble setting Membership object.
From Paid By controller I use didSelectAtIndexPath to set Membership:
[self setCrSelectedMember:[crGroupMembers objectAtIndex:indexPath.row]];
By NSlogging crSelectedMember I get the right selected member in self, but in parent view, to which ivar is pointed, nothing is changed.
Am I doing something wrong? Cause I CAN call the method of crSelectedMembers, but I can't change the value of crSelectedMember.
If I understand your question, the most likely cause is an improper property declaration.
If you want to pass values from one object to another using each objects properties, then you need to make sure to use assign to ensure the properties in one object are pointing at the same instances as the property in the other object.
So in your topViewController you have a property:
#property (nonatomic,retain) NSString crSelectedMember;
Then in your child view controllers you have:
#property (nonatomic,assign) NSString crSelectedMember;
This forces the value into the exact object in the parent controller.
However, this is a very fragile way to pass data between viewControllers. As your app becomes more complicated, it will be impossible to track all the passed data. (Worse, if you run into memory limitations, the parent view controller may unload and not even exist when you try to pass data to it.)
Instead, you should have a single custom object devoted to holding your data. Each view controller should query that object for the data it needs and should write any changes back to that object. The view controllers never communicate directly. This technique allows you to control the data in one specific location instead of spreading it out all over your code and it scales well. You can add an arbitrary number of view controllers to you app without having to worry about tying them all together.
See this post for details: iPhone: How to Pass Data Between Several Viewcontrollers in a Tabbar App

Count method of subclass of NSMutableArray crashes app

This seems to be a common problem, but I can't figure out anything from the answers I've seen so far. I have an iPhone app that uses a subclass of NSMutableArray to store objects, plus some additional properties. The subclass is skhCustomArray. The subclass initializes fine, with no objects in the skhCustomArray, and I assign it to the the property of my view controller, which is a pointer to an skhCustomArray.
prescriptionListVC* newPrescList = [[prescriptionListVC alloc] initWithNibName:#"PrescriptionList" bundle:nil];
newPrescList.curPersonPrescriptions = [personDetails objectAtIndex:0];
That works fine. Yet when I push my view managed by my view controller onto the navigation controller stack, the count method in the numberOfRowsInSection method crashes the app, see below.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
return [curPersonPrescriptions count];
}
What could be causing this? How can a valid custom array, with no objects, not return a valid count? Where am I going wrong? Thanks.
Subclass of NSArray? You're aware that NSArray is a class cluster, and is therefore somewhat difficult to subclass, right? In fact, it's so fraught with danger that the NSArray documentation has a whole section dedicated to what you need to do in order to subclass it.
I'll bet that that's the source of your woes.
You almost certainly don't need to subclass NSMutableArray in this situation. Instead, make a new class which has an array as a property, along with the extra properties you desire.
When you subclass NSMutableArray, you need to implement some mandatory methods like count, addObject:, insertObjectAtIndex etc. This is what we call as class cluster.
If you want to add some more feature/behavior to already implemented object then you can write a "category" instead of "subclassing" it.
If you want to subclass it, then you have to implement all those methods which your are going to use so better write a category of NSMutableArray and extend the feature what you want and use the NSMutableArray object only. This will solve your problem and also this is the easy and almost right way to add new behavior to already existing class.