Accessing parent view controller (custom) properties - objective-c

I have written a UITabBarController subclass (called MainViewController) and added a few instance variables, specifically a venue of type Venue. Each tab of the MainViewController needs to access the venue variable of the MainViewController. In the first tab, a UIViewController subclass named HomeViewController, I wrote my viewDidLoad method and tried to output to NSLog with both...
NSLog(#"%#", self.parentViewController.venue.name);
and
NSLog(#"%#", self.tabBarController.venue.name);
But XCode gives the error
error: request for member 'venue' in something not a structure or union
I can access the venue property from within MainViewController just fine so have ruled out an error there. The iPhone simulator does see both self.parentViewController and self.tabBarController as an instance of MainViewController. The line...
NSLog(#"%#", self.tabBarController);
outputs...
2009-06-05 17:54:46.502 Venue[29729:20b] <MainViewController: 0x536600>
Since it's seen as a MainViewController instance, I doubt using casting would help. Is my only other option to initialize the HomeViewController with a copy of the venue or am I just doing something completely wrong with 'self.parentViewController.venue.name'? Thanks, Rob

You're doing something completely wrong. parentViewController is declared as a UIViewController. NSLoging it outputs its real type due to the wonders of polymorphism.
UIViewController doesn't have a Venue member. Your MainViewController does. Casting it is, in fact, the right answer. Make sure to import MainViewController.h as well.
#import "MainViewController.h"
[...]
NSString *name = ((MainViewController *)self.parentViewController)).venue.name;
Also make sure, of course, that venue is declared as a #property of MainViewController, and name is a #property of Venue.

int currentVCIndex = [self.navigationController.viewControllers indexOfObject:self.navigationController.topViewController];
//previous view controller
AccountViewController *account = (AccountViewController *)[self.navigationController.viewControllers objectAtIndex:currentVCIndex - 1];
account.property = object;
[account doSmthng];

Your NSLog() statement is "seeing" it as a MainViewController because that's what the object actually is. The problem you're having though, is that the compiler doesn't actually realize this because the parentViewController property is declared as a plain old UIViewController. Even though you're actually returning a subclass of it, as far as the compiler knows you're trying to call that method on a UIViewController, and it's going to complain. Casting it to a MainViewController will solve the issue.

Related

How do I view Obj-C subclass variables from Swift in the Xcode debugger?

I've got a mixed Obj-C / Swift project. Whenever I hit a breakpoint in a Swift class, the Obj-C object variables view just shows values for parent classes, but not the subclass itself.
For instance, if I have the following Obj-C class:
#interface CameraPlayerCell
#property (nonatomic, strong) Camera* camera;
#end
When I hit a breakpoint in my Swift CollectionViewController implementation, the Xcode debugger values view shows:
Searched for this for about an hour, but apparently I don't know how to ask Google what I'm looking for (or they're just being Google & showing me what they think I want rather than what I actually want...)
I know there is a way to add an expression to the Variables View so that it will show the member variables for CameraPlayerCell. I've read an article somewhere and have done this before, but for the life of me I cannot remember how to do it.
Have you tried frame variable?
From Apple:
"You use the frame variable (f v) command to get a list of all the variables in the stack frame."
Example:
Cast the value:
po (CameraPlayerCell *)cell
Then you can access the subclass properties:
po ((CameraPlayerCell *) cell).camera
Works fine on my machine. Keep in mind that an Objective-C property is merely a shorthand for accessor methods for an ivar; it is the ivar that will appear in the variables list. (I assume that yours is automatically synthesized.)

NSWindowController subclass will not release in ARC

I'm encountering a strange situation with NSWindowController. I want the window controller to be released but it will not. It doesn't seem to be following my expectations for ARC behavior.
I've created a simple window controller subclass, PlainWindowController. Its interface and implementation are empty:
#import <Cocoa/Cocoa.h>
#interface PlainWindowController : NSWindowController
#end
#implementation PlainWindowController
#end
I created with it a default windowController xib named PlainWindowController.xib, which has a window with delegate and windowController connections already set.
In a test, I've written this code:
PlainWindowController *strongWindowController = [[PlainWindowController alloc] initWithWindowNibName:#"PlainWindowController"];
__weak PlainWindowController *weakWindowController = strongWindowController;
[strongWindowController showWindow:nil];
strongWindowController = nil;
STAssertNil(weakWindowController, #"The window controller should have been deleted, wasn't");
When this test runs, the weak reference is not nil.
If I leave out the showWindow it is nil. If I use init instead of initWithWindowNibName, it is nil.
Does anyone know what's going on here? Thank you in advance for any guidance.
There’s no guarantee that an object under ARC hasn’t been added to the autorelease pool, in which case it won’t be freed until the end of the current event.
In your case, I strongly suspect somewhere within initWithWindowNibName: the controller gets retained and autoreleased.
If you really want to ensure your object is being freed, just subclass the -dealloc method and add an NSLog to it or break on it.
You generally shouldn't harbor "expectations" about when objects are deallocated if they've ever been passed to other code which you don't control.
Cocoa might have retained and then autoreleased the controller. Cocoa may retain the window controllers of any windows which are showing.
In general, when it comes to Cocoa memory management, you are supposed to make sure your own code follows the rules (which ARC largely does for you) and you should assume that other code follows the rules, but you can't assume that other code doesn't retain objects beyond where your interest ends. You should basically not care about what the other code is doing with respect to memory management.
If you really want to know what's happening, run your app under the Allocations instrument and explore the retain/release/autorelease history of your object after the point where you expected it to have been deallocated.
I had a similar issue when first using ARC. I unfortunately don't remember the details as this was more than a year ago. I eventually tracked it down as a circular retain problem using Instruments to monitor retain values, although not without losing a lot of hair.
I think the actual problem was with the delegate which I fixed with #property (unsafe_unretained) id delegate;
I ran into a similar issue yesterday with an ARC based project - a NSWindowController subclass would not deallocate, nor did -dealloc fire. I worked with Zombies, Allocations to no avail. The problem was very simple. There was a subclassed control within the window, and in that controls subclass .h header file a property was defined as:
#property id delegate;
correcting it to
#property (nonatomic, weak) id delegate;
fixed the issue.

Passing variable

Hi I've got an question about passing variables via NSobject into the rootviewcontroller.
I've got 2 .h and .m files ( called viewcontroller.m/h and secondviewcontroller.m/h ).
Underneath a little example for what I'm trying to do.
secondviewcontroller.m
-(NSString *) mystring{
return #"this is a string";
}
secondviewcontroller.h
#interface SecondviewController : NSObject
-(NSString *) mystring;
#end
How am I be able to pass this variable into viewcontroller.m ?
I've read a lot on google but most of the implementations where wrong or my research is just bad xD
How am I be able to pass this variable into viewcontroller.m ?
You actually haven't shown us any variables; -myString returns a constant string. Also, remember that viewcontroller.m is just an implementation file. It's probably better to think about the objects communicating with each other than one piece of source code communicating with another. I communicate with you, but my DNA doesn't communicate with your DNA.
Anyway, it sounds like you're asking about how one object can communicate with another, and the answer is simply that at least one of the objects in the conversation needs to know about the other. So, an instance of your viewcontroller class might get a pointer to an instance of secondviewcontroller from some other object, or it might create a new instance itself. Some part of the code in viewcontroller.m might look like:
secondviewcontroller *svc = [[secondviewcontroller alloc] initWithNibName:nil bundle:nil];
NSString *someString = [svc myString];
That's not a particularly realistic example, but neither is the sample you provided. The lesson is the same, though -- objects communicate by sending messages to each other, and an object needs a reference to another object in order to send that message. Figuring out which objects should know about which others, how they find out about each other, and what messages they send to each other is exactly the business of object oriented programming. In OOP, the truly important thing isn't so much the objects themselves but how they relate to each other. It's all about the structure that you create using objects as building blocks.

Need some clarity on NIB file objects

I have a MainViewController class set up with a simple nib. On the nib i have only these few objects. I have set the popoverViewController's file owner to the MainViewController.
I have set the popoverViewController class to my PVController class so that i can put buttons/code/labels etc.
The Popover works fine, but somethings are is puzzling me which i need help to understand.
That newly created PVController class has an init method that is never called when the popover is loaded. Yet the popover still works? If i put break points in the -(IBAction) buttons however, they are called when i click the buttons for them. But the init is never called. If I however, go to the file owner (MainViewController) and do --> PVController *pv = [[PVController alloc] init], only then it is called. So my first question is, will there be any problems if i do not alloc/init an IBOutlet in FileOwner, since it seems to work without it (altho the PVController's init method isnt called)? And why isnt it called?
If i did decide to create that IBOutlet in FileOwner for the Popover View Controller's referencing outlet, do i make it as strong? or weak? My noobish instincts tells me weak because it is already owned by the NIB, but when i put weak, I get a yellow error next to the init of the IBOutlet saying message
So my first question is, will there be any problems if i do not alloc/init an IBOutlet in FileOwner
NO, there will not be any problem. Infact IBOutlets are never alloc+init manually.

Shared object with others classes?

I just started learning objective c. I have this little problems and questions, hope you guys could help me.
I have a ViewController, I called it: GameViewController.
This GameViewController, will call a model class, "PlayerModel"(NSObject) and this PlayerModel contains "PlayerProfile" object (its a NSObject).
The viewDidLoad in GameViewController will call and initiate model class:
playerModel = [[PlayerModel alloc] initWithInt:playerID];
Then, in my PlayerModel initWithInt method, I populate PlayerProfile data by fetching the data from online database. I manage to populate the data, but when I want to call it in gameViewController
// This is gameViewController.m
....
playerModel.playerProfile.name;
But i got this error message: "Property name not found on object of type PlayerProfile"
I NSLog the playerProfile in gameViewController, its "(null)", whereas when I NSLog in the playerModel, it has some values. How do I pass this values and make it universal, so that others classes can make use (set the value) of it?
Regarding the "Property name not found," I assume that's a compile error. You probably have failed to #import PlayerProfile.h in GameViewController.
If gameViewController is nil in GameViewController then either you have not actually initialized it, or playerModel is nil. Are you sure that you're checking it after viewDidLoad actually runs? This can be later than you think.