I have two view controllers: FirstViewController and SecondViewController. The project is to record a video and attach it to an email. I can record it and have it able to email, I just need to attach it. I am able to get a URL for the video in FirstViewController, but passing it isn't working.
FirstViewController -
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];
if ([mediaType isEqualToString:#"public.movie"])
{
// Saving the video to phone / // Get the new unique filename
NSString *sourcePath = [[info objectForKey:#"UIImagePickerControllerMediaURL"]relativePath];
UISaveVideoAtPathToSavedPhotosAlbum(sourcePath, self, /*#selector(video:didFinishSavingWithError:contextInfo:)*/nil, nil);
self.movieURL= [[NSURL alloc] initFileURLWithPath: sourcePath];
NSLog(#"movieURL");
NSLog(self.movieURL.absoluteString);
SecondViewController *sendMovie = [[SecondViewController alloc] initWithNibName:#"ViewController" bundle:nil];
sendMovie.movieU = [[NSURL alloc] initFileURLWithPath: sourcePath];
[[self navigationController] pushViewController:sendMovie animated:YES];
NSLog(#"movieU");
NSLog(sendMovie.movieU.absoluteString);
}
[picker dismissViewControllerAnimated:YES completion:NULL];
}
SecondViewController to attach to email -
NSLog(#"1st print");
NSLog(self.movieU);
[controller addAttachmentData:[NSData dataWithContentsOfURL:self.movieU] mimeType:#"video/MOV" fileName:#"defectVideo.MOV"];
NSLog(#"2nd print");
NSLog(self.movieU.absoluteURL);
[self presentViewController:controller animated:YES completion:nil];
SecondViewController.h property of NSURL
#property(nonatomic) NSURL *movieU;
The movieURL is a property in the FirstViewController, but I don't believe is needed.
I can see the URL in the FirstVC, but it appears nil in the SecondVC.
Solutions -
1) define NSURL *movieU as a extern instead of property.
2) else define it as a property of AppDelegate and access it.
3) or else synthesize property movieU and do allocate like -
in your FirstViewController -
SecondViewController *sendMovie = [[SecondViewController alloc] initWithNibName:#"ViewController" bundle:nil];
NSURL *url = [[NSURL alloc] initFileURLWithPath: sourcePath];
sendMovie.movieU = url;
[[self navigationController] pushViewController:sendMovie animated:YES];
And NSLog it in your SecondViewController.
Hope this helps!
There is nothing wrong with the way you are going about passing information. Try this:
// In you code where you create the second view controller.
SecondViewController *sendMovie = [[SecondViewController alloc] initWithNibName:#"ViewController" bundle:nil];
// SecondViewController viewDidLoad method being called (movieU is still nil)
sendMovie.movieU = [[NSURL alloc] initFileURLWithPath: sourcePath];
// Do a nil test here
if (!sendMovie.movieU) {
NSLog(#"%#",#"It's nil here!"); // If this is the case something is wrong with "sourcePath"
} else {
NSLog(#"%#",#"It's not nil here!");
}
[[self navigationController] pushViewController:sendMovie animated:YES];
// SecondViewController viewWillAppear method being called (movieU is NOT nil)
// SecondViewController viewDidAppear method being called (movieU is NOT nil)
This test will tell you a lot. If its nil here then the problem is not with setting the second view controller's property but with actually creating the NSURL object. It could be a lot of things like you are overwriting it somewhere in the second view controller (e.g. viewWillAppear method). Just follow the trail using break points, logging, etc. to follow its life time.
Edit - Debugging Procedure
Set break points where you create Second VC, set its property, push it, and finally view it (clicking on the tab). Set break points throughout the lifecycle of the second VC (viewDidLoad, viewWillAppear, viewDidAppear, etc). This will allow you to step through the entire lifecycle of your VC. If you haven't utilized those methods go ahead and define them anyway including a call to super. As you step through these break points keep checking the value of movieU. You will see it is nil at first, then you set it (we know this from your comments), its not nil, then it becomes nil, again, etc. If you are patient and systematic you will find it and learn a whole lot about the lifecycle of VCs. If you don't systematically step through you may miss something. For instance maybe your code is creating a whole new Second VC when you click on the tab to actually look at it. Stepping through your code this way will show that.
Edit
Make sure you are testing in the viewWillAppear/viewDidAppear methods or later so that the property has actually been set. See comments in my code.
Edit
A property of retainable object pointer type which is synthesized without a source of ownership has the ownership of its associated instance variable, if it already exists; otherwise, [beginning Apple 3.1, LLVM 3.1] its ownership is implicitly strong. Prior to this revision, it was ill-formed to synthesize such a property.
From: http://clang.llvm.org/docs/AutomaticReferenceCounting.html#property-declarations
According to this (unless you are specifying weak on the ivar - unlikely) it should be strong by default.
Good luck.
use this
self.movieURL = [NSURL fileURLWithPath:sourcePath];
instead of
self.movieURL= [[NSURL alloc] initFileURLWithPath: sourcePath];
hope this work
I got it fixed! I decided to use a singleton which uses a shared instance through another class. I created a whole new class called Singleton and only contained the sharedinstance method:
+ (id)sharedInstance {
static id sharedInstance = nil;
if (sharedInstance == nil) {
sharedInstance = [[self alloc] init];
}
return sharedInstance;
}
Singleton.h
#property NSURL *movieU;
+ (id)sharedInstance;
Make sure to import the singleton class to both First and Second VC.
SecondVC.m
Singleton* single = [Singleton sharedInstance];
[controller addAttachmentData:[NSData dataWithContentsOfURL: single.movieU] mimeType:#"video/MOV" fileName:#"defectVideo.MOV"];
FirstVC.m
Singleton* single = [Singleton sharedInstance];
NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];
if ([mediaType isEqualToString:#"public.movie"]){
// Saving the video / // Get the new unique filename
NSString *sourcePath = [[info objectForKey:#"UIImagePickerControllerMediaURL"]relativePath];
UISaveVideoAtPathToSavedPhotosAlbum(sourcePath, self, /*#selector(video:didFinishSavingWithError:contextInfo:)*/nil, nil);
self.movieURL = [[NSURL alloc] initFileURLWithPath: sourcePath];
NSLog(#"movieURL");
single.movieU = self.movieURL;
By doing this, it successfully would pass the url containing the information for the recorded video to be attached to the email.
Related
Trying to create simple test for following function:
-(void)presentWithString:(NSString *)name
{
CustomVC *customVC = [[CustomVC alloc] initWithName:name];
UINavigationController *nav = [[UINavigationController alloc] init];
nav.viewControllers = #[customVC];
dispatch_async(dispatch_get_main_queue(), ^{
[self.vc presentViewController:nav animated:YES completion:nil];
});
}
I can split this into chunks with dependency injection, but don't know how to write proper test either way. What would be the best practice for this example?
What do you want to test? There are 3 things happening in your method :
CustomVC is created with name passed.
CustomVC is embedded inside navigation controller.
The navigation controller is presented on self.vc.
You can write a test that checks the whole flow :
- (void)testPresentWithString_shouldPresentCustomVC_withPassedName {
// Arrange
NSString *expectedName = #”name”;
XCTestExpectation *exp = [self expectationWothDescription:#”presentVC called”];
TestClass *sut = [[TestClass alloc] init];
id vcMock = OCMClassMock([UIViewController class]);
sut.vc = vcMock;
OCMExpect([vcMock presentViewController:OCM_ANY animated:YES completion:nil]).andDo(^(NSInvocation *invocation) {
UINavigationController *nav = nil;
[invocation getArgument:&nav atIndex:2];
CustomVC *custom = nav.viewControllers.firstObject;
// Assert
XCTAssertNotNil(nav);
XCTAssertTrue([nav isKindOfClass:[UINavigationController class]]);
XCTAssertEqual(nav.viewControllers.count, 1);
XCTAssertNotNil(custom);
XCTAssertTrue([custom isKindOfClass:[CustomVC class]]);
XCTAssertEqual(custom.name, expectedName);
[exp fulfill];
});
// Act
[sut presentWithString:expectedName];
// Assert
[self waitForExpectationsWithTimeout:1 handler:nil];
OCMVerifyAll(vcMock);
// Cleanup
[vcMock stopMocking];
}
This code checks everything that happens in your method - that a method got called with specific arguments, that the first of these arguments was a navigation controller with only CustomVC embedded and that this CustomVC had name set. Obviously I’ve made assumptions that vc property on tested class can be set from outside and that the name on CustomVC can be read. If not, it may be trickier to test some parts of this.
Personally I wouldn’t unit test this. I would test the initialization of CustomVC separately, and put the whole presentation under a UI test.
Let me know if everything is clear!
—
Side note : I wrote this on mobile from memory, so there might be small mistakes in the code. I will update it when I have a chance to check it with Xcode.
I am having trouble getting MFMessageCompose to work with Unity3D iOS Plugin.
I got an alert window to pop up with buttons but I am having an error when accessing the MFMessageComposer. Can't seem to get the method to pop up the window properly.
Here is my iOSBridge.h (linked file if you want):
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import <MessageUI/MessageUI.h>
#interface Delegate : NSObject <UINavigationControllerDelegate, MFMessageComposeViewControllerDelegate>
#end
And my iOSBridge.mm file:
#import "iOSBridge.h"
#implementation Delegate
//Trying to still understand the meaning behind this line. Why???
-(id)init
{
return self;
}
//RATE US Button Numbers
//Not entirely sure What I did here but it still bring it up. This section has nothing to do with SMS
-(void) alertView: (UIAlertView*)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
//Give back the number of the button
NSString *inStr = [NSString stringWithFormat:#"%d", (int)buttonIndex];
const char *cString = [inStr cStringUsingEncoding:NSASCIIStringEncoding];
UnitySendMessage("Popup", "UserFeedBack", cString);
NSLog(#"%li", (long)buttonIndex);
} // RATE US button number end
-(void)SMS:(id)sender{
MFMessageComposeViewController *controller = [[MFMessageComposeViewController alloc] init];
[controller setMessageComposeDelegate:self];
if([MFMessageComposeViewController canSendText]){
[controller setRecipients:[NSArray arrayWithObjects:nil]];
[controller setBody:[NSString stringWithFormat:#"Text"]];
//WHYYY do you not work
//[self presentViewController:controller animated:YES];
Delegate *appDelegate = UIApplication.sharedApplication.delegate;
[appDelegate.window.rootViewController presentViewController:controller animated:YES completion:nil]
}
}
#end
static Delegate* delegateObject;
extern "C"
{
//A method for unity can run
void _AddNotification(const char* title,
const char* body,
const char* cancelLabel,
const char* firstLabel,
const char* secondLabel)
{
//Don't have a full grasp of this delegateObject thing yet.
if(delegateObject ==nil){
delegateObject = [[Delegate alloc]init];
}
//iOS Alert Pop up view RATE OUR GAME
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle: [NSString stringWithUTF8String:title]
message:[NSString stringWithUTF8String:body] delegate:delegateObject
cancelButtonTitle:[NSString stringWithUTF8String:cancelLabel]
otherButtonTitles:[NSString stringWithUTF8String:firstLabel],[NSString stringWithUTF8String:secondLabel], nil];
[alert show];
} //End of _AddNotification
//SMS Method for Unity to use
void _SMSGO(const char* Mbody){
MFMessageComposeViewController *controller = [[MFMessageComposeViewController alloc] init];
if([MFMessageComposeViewController canSendText]){
NSString *s = [NSString stringWithFormat:#"%s", Mbody];
controller.body = s;
//Suppose to Brings up the SMS view not sure why it isnt working or how to make this work
//If this can work its major progress
[delegateObject presentViewController:controller animated:YES];
}
}
}
So these:
-(void) alertView: (UIAlertView*)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
NSString *inStr = [NSString stringWithFormat:#"%d", (int)buttonIndex];
const char *cString = [inStr cStringUsingEncoding:NSASCIIStringEncoding];
UnitySendMessage("Popup", "UserFeedBack", cString);
NSLog(#"%li", (long)buttonIndex);
}
-(void)SMS:(id)sender{
MFMessageComposeViewController *controller = [[MFMessageComposeViewController alloc] init];
[controller setMessageComposeDelegate:self];
if([MFMessageComposeViewController canSendText]){
[controller setRecipients:[NSArray arrayWithObjects:nil]];
[controller setBody:[NSString stringWithFormat:#"Text"]];
//WHYYY do you not work
//[self presentViewController:controller animated:YES];
Delegate *appDelegate = UIApplication.sharedApplication.delegate;
[appDelegate.window.rootViewController presentViewController:controller animated:YES completion:nil]
}
}
Code blocks are actually not being accessed at all through your bridge. So nothing in this will be touched at all.
The - (id) init is the initializer of the class. So in order to access anything in that file from anything else, you have to init it first. An easier way to think of this is:
extern.c is a separate file.
static Delegate *delObj;
extern "C"
{
void _callMain (const char *hello) {
/**
* delObj is a static so it "Will be once it is" so it will be
* in memory (mallocated) the moment you tell it to be something.
*/
if (!delObj) {
In this case, we want that static object to be an instance of Delegate (not a particularly good name to set your class to, it will lead to much confusion). We "start" or initialize this class by calling init and we tell it this is an object we need, chuck it on the heap read this.
delObj = [[Delegate alloc] init];
}
// Now we can call the function in the next file
[delObj helloWorld];
}
Delegate.m - Think of this as a different file. You can access this file from extern.c because (in reality) it's just included in the same file. But this of this as a separate entity entirely. You have to access this "file" from extern.c
#implementation Delegate
// This is the function we call with [[Delegate alloc] init];
-(id) init {
// It simply returns itself - saying hey this is the object memory chunk in the heap you want to talk to.
return self;
}
// This is the function we call with [delObj helloWorld];
- (void) helloWorld {
NSLog("Hello World"); // This will show up in your console.
}
So the above code has two functions, one that says "this is the memory object your looking for" - one that says "I'm a function, lets execute something".
Now with all that laid out, you're not calling:
-(void) alertView: (UIAlertView*)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
OR
-(void)SMS:(id)sender{
Via your extern "C". The reason why _AddNotification works is because you have code in there calling UIAlertView AFTER making sure your delegateObject is in memory. In you _SMSGO function, you're not putting your object into memory. So when you call delegateObject in [delegateObject presentViewController:controller animated:YES]; it says "Oh I know what delegateObject is but it's equal to nothing. In fact it does not have memory to execute anything!" Thats why you probably don't get any errors or exceptions. The code knows there is a static object, but it hasn't been set to anything yet.
SOLUTION:
First, void methods don't need :(id)sender thats more of a IBAction thing unless you actually want to send something - so change -(void)SMS:(id)sender{ to - (void) SMS { (with the pretty spacing, too. It's mo' better for eyes).
Second, swap everything in SMS with:
- (void) SMS {
MFMessageComposeViewController *controller = [[MFMessageComposeViewController alloc] init];
[controller setMessageComposeDelegate:self];
if([MFMessageComposeViewController canSendText]){
[controller setRecipients:[NSArray arrayWithObjects:nil]];
[controller setBody:[NSString stringWithFormat:#"Text"]];
// We now know why we work!
[self presentViewController:controller animated:YES];
}
}
But WAIT! And do not copy and paste. Be sure to understand each line of code you write.
This line allocates an object into memory, in this instance, the MFMessageComposeViewController object. Then initializes it.
MFMessageComposeViewController *controller = [[MFMessageComposeViewController alloc] init];
This line sets the delegate of the object we just made (controller). But why can it do this? Because we have MFMessageComposeViewControllerDelegate set in the iOSBridge.h file. This tells everything in your .mm file "hey if we happen to have a MFMessage object somewhere, it may access delegate properties if you want."
[controller setMessageComposeDelegate:self];
if ( [MFMessageComposeViewController canSendText] ) is human readable.
Same with [controller setRecipients:[NSArray arrayWithObjects:nil]]; and [controller setBody:[NSString stringWithFormat:#"Text"]];
But now [self presentViewController:controller animated:YES]; is were we need to dive in.
So in Unity, they said "hey, we don't need to deal with every single possible native function being called" - so they created access to the extern capability for you. This allows you to talk to Objective-C from the UnityScript side of things. Objective-C is just a superset of C, so thats common ground. Everything in here should ONLY call functions in Delegate. The example of this is above in the fake extern.c code block. The only thing that is doing is creating delegateObject and calling a function. Now for the next step. Swap everything in _SMSGO with:
void _SMSGO (const char *mBody) { // I prefer char *name vs char* name but it doesn't matter
[delegateObject SMS]; // add mBody as a parameter when you're ready. Handle the stringWithUTF8String on the Objective-C side of things. Yes, this is not the Obj-C side, this is the C side.
}
"But wait... you just delegateObject needs to be a thing" - Yes it does. Create another method in your extern "C" section called _init and run this one time from Unity in the Awake or Start function of your class. This will set your static object one time and never mess with it again. Simply make it:
void _init() {
if ( !delegateObject ) {
delegateObject = [[Delegate alloc] init];
}
}
!delegateObject is the same thing as delegateObject == nil but cleaner code. Both say "We don't know what dat is" - Ok now we have our delegateObject, we are free to make our next calls with delegateObject as much as we'd like.
Now when you call [delegateObject SMS] it goes to - (void) SMS. And when you call self presentViewController it knows that self is referring to an iOS Native Object. If you call presentViewController in extern "C" it says "... um, hmm. I haven't got the foggiest notion what that means" - for this reason, we have use everything in your extern "C" section as a crossover to your Delegate object. That is the whole purpose of the extern thing, just to call things in your Obj-C stuff.
Hope this helps.
I have a project I am working on, to learn some more about JSON and restkit. It all is working great, however I am having trouble with an array losing it's values.
This is the last method that is executed in my network request.
SHRetrieveStoresWS.m
- (void)objectLoader:(RKObjectLoader *)objectLoader didLoadObjects:(NSArray *)objects
{
self.stores = [[NSArray alloc] initWithArray:objects];
StoresViewController *viewController = [[StoresViewController alloc] init];
[viewController didLoadObjects:objects];
for (Store *aStore in stores) {
NSLog(#"%#", [aStore longName]);
}
}
Which calls this method in my view controller.
StoresViewController.m
#property (strong, nonatomic) NSArray *data;
- (void)didLoadObjects:(NSArray *)aArray
{
NSLog(#"%d", aArray.count);
self.data = [[NSArray alloc] initWithArray:aArray];
NSLog(#"%d", data.count);
[self.tableView reloadData];
}
The values are correct when I ask for the values within this method, but the array shows 0 objects immediately afterwards. Am I missing something here?
I am later checking the value with this method.
- (IBAction)pushMe:(id)sender
{
NSLog(#"Data: %d", self.data.count);
}
You should pass the data in the segue...
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([segue.identifier isEqualToString: #"MY_IDENTIFIER"]){
StoresViewController *viewController = segue.destinationViewController;
[viewController didLoadObjects: objects];
}
}
That should work for you! Just change MY_IDENTIFIER to whatever the identifier of your segue is.
StoresViewController is initialised as a local variable which is only accessible in the method that it was declared (aka objectLoader). After objectLoader has completed, the local variable is no longer valid.
The problem is most likely that you're creating multiple instances of StoresViewController instead of giving your network controller a reference to the original instance.
You can demonstrate it to yourself by printing out self in -viewDidLoad and again in didLoadObjects:. You'll see that the pointer addresses are different.
This line is the culprit:
StoresViewController *viewController = [[StoresViewController alloc] init];
Instead of instantiating StoresViewController again, add a property to your SHRetrieveStoresWS class and use it to hold a reference to your view controller.
#property (strong) StoresViewController *viewController;
You'll need to set that property before -didLoadObjects: is invoked.
BookingDocumentsViewController *bdVc = [self.storyboard instantiateViewControllerWithIdentifier:#"BookingDocs"];
bdVc.orId = rl_id;
bdVc.docsArray = self.documentsArray;
[self.navigationController pushViewController:bdVc animated:YES];
I have Above code snippet. I'm trying to load a new viewcontroller and assign its Mutable Array (docsArray) object to current view's mutableArray (documentsArray <=this is not nil)
Whenever I execute above code I get EXC_BAD_ACCESS error.
but if I comment the 3rd line. It works but I can't get my array to the new view. I even tried with [[NSMutableArray alloc] initWithArray:self.documentsArray]; this doesnt work either.
But if I use bdVc.docsArray =[[[NSMutableArray alloc] init]; it works but again I can't get my mutable array to the new view.
Edit:
However 2nd line has NSString values. And they can be passed without a problem.
What am I doing wrong here?
I'm not getting any errors in console, instead I get this.
Maybe consider using a Segue. It instantiates the destination viewcontroller for you. Then in your source view controller implement
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
Get a reference to your destination viewcontroller and set its data.
BookingDocumentsViewController *bdVc = [segue destinationViewController];
bdVc.docsArray = self.documentsArray;
in BookingDocumentsViewController.h
#property(nonatomic, retain)NSmutableArray *docsArray;
You do can do in your BookingDocumentsViewController.m:
#synthesize docsArray;
- (void)viewDidLoad
{
NSmutableArray *array = [NSmutableArray alloc]initWithArray:docsArray];
[super viewDidLoad];
}
then when you are pushing the view
BookingDocumentsViewController *bdVc = [self.storyboard instantiateViewControllerWithIdentifier:#"BookingDocs"];
bdVc.orId = rl_id;
bdVc.docsArray = self.documentsArray;
[self.navigationController pushViewController:bdVc animated:YES];
[bdVc Release];
I think I found the issue. A very basic mistake. In bdVc's viewDidLoad I had the following line,
NSLog(#"Booking Documents viewDidLoad : %#",self.docsArray.count);
This was causing the error. that %# instead of %d. I wonder why xcode didn't show proper reason for the error.
Thank you all for the help. :)
I've been following a tutorial on iOS development - specifically drill-down UITableViews. I have my own custom plist established, but I can't seem to get the DetailViewController to populate with my plist information. I could really use some help here, I'm a bit over my head!
edit: Here's some details...
The app works through a plist-populated RootViewController, which is a UITableView. When there aren't any children left in the plist, it changes to a Detail view:
AppDelegate.m
NSDictionary *tempDict = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"Data" ofType:#"plist"]];
self.data = tempDict;
RootViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
if(CurrentLevel == 0) { // At the 'root' of the plist
//Initilalize our table data source
NSArray *tempArray = [[NSArray alloc] init];
self.tableDataSource = tempArray;
AppDelegate *AppDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
self.tableDataSource = [AppDelegate.data objectForKey:#"Rows"];
self.navigationItem.title = #"PedalTome";
}
else
self.navigationItem.title = CurrentTitle;
}
later on...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
//Get the dictionary of the selected data source.
NSDictionary *dictionary = [self.tableDataSource objectAtIndex:indexPath.row];
//Get the children of the present item.
NSArray *Children = [dictionary objectForKey:#"Children"];
if([Children count] == 0) {
DetailViewController *dvController = [[DetailViewController alloc] initWithNibName:#"DetailView" bundle:[NSBundle mainBundle]];
[self.navigationController pushViewController:dvController animated:YES];
}
else {
//Prepare to tableview.
RootViewController *rvController = [[RootViewController alloc] initWithNibName:#"RootViewController" bundle:[NSBundle mainBundle]];
//Increment the Current View
rvController.CurrentLevel += 1;
//Set the title;
rvController.CurrentTitle = [dictionary objectForKey:#"Title"];
//Push the new table view on the stack
[self.navigationController pushViewController:rvController animated:YES];
rvController.tableDataSource = Children;
}
}
My DetailViewController.m is empty, with the exception of a placeholder self.navigationController.title.
If I'm understanding correctly, I need to pass information from RootViewController to DetailViewController - the location and implementation of the plist, the index level (is that what it's called) in the plist, and the string inside that index level (under the key Detail).
At this point, any progress is amazing progress. Thanks in advance.
You can pass whatever information you need to your DetailViewController by setting up a synthesized property in your DetailViewController, and then passing your data to it inside your if-block.
For example, in your DetailViewController.h you would have the following (without ARC):
#property (retain, nonatomic) NSDictionary *myAwesomeDictionary;
Or, with ARC enabled:
#property (strong, nonatomic) NSDictionary *myAwesomeDictionary;
Then in DetailViewController.m you would have the following:
#synthesize myAwesomeDictionary;
Then you would change your code block to the following:
if([Children count] == 0) {
DetailViewController *dvController = [[DetailViewController alloc] initWithNibName:#"DetailView" bundle:[NSBundle mainBundle]];
[dvController setMyAwesomeDictionary:dictionary];
[self.navigationController pushViewController:dvController animated:YES];
}
This assumes that the NSDictionary called dictionary that you created a few lines above is the data that you'd like to show in your DetailViewController.
Then in your DetailViewController's viewDidLoad: method you can access that dictionary using self.myAwesomeDictionary and do whatever you need to do with it.
Disclaimer:
Two things seem to go against Apple's code style standards in your code:
Your AppDelegate stores your model (your plist). - Apple says that you shouldn't crowd your AppDelegate with global data/logic. In general, only write code that pertains specifically to a class, in that specific class.
You aren't parsing your plist into custom objects. - This makes it hard to code because you constantly have to figure out what your generic Array and Dictionary objects represent, and make your code totally unreadable for other people.
Some of your instance variable names are capitalized. For example, NSArray *Children should be NSArray *children and CurrentLevel should be currentLevel. Only Class names have the first letter capitalized.
Check out http://jlawr3nc3.github.com - specifically my CompanyRecords example code for information on how to make a class and FunWithArrays for how to parse a plist into custom objects. MusicLibraryiOS then delves into how to take a plist, parse it into custom objects, and then display it in a UITableView along with a detail view.
Table View Specifier May do what you need.
Specified Table View is an iOS table view that has its contents specified
via a plist file. Its purpose is largely demonstrative but is also designed
to be used in a live product (useful for credits pages). Can be used with
iOS version 4.2 and above.
A dig through their code will most likely be enlightening.