iOS media picker does not show up - iphone

I am currently working on an audio application on iPhone. It is based on apple's SpeakHere sample code with a user-defined input file from iPod library.
Here is the event raised by the button:
- (IBAction) btn_PickSong_Clicked:(id)sender{
[self showMediaPicker];
//code importing tracks from library
}
And in showMediaPicker method:
//Yup the program does reach this method but the picker does not show up
- (void)showMediaPicker {
MPMediaPickerController* mediaPicker = [[[MPMediaPickerController alloc] initWithMediaTypes:MPMediaTypeMusic] autorelease];
mediaPicker.delegate = self;
[self presentModalViewController:mediaPicker animated:YES];
}
The problems are:
The library import feature works fine in a separate program, but the media picker does not show up anymore when I put the code into SpeakHereController.mm.
Also if I place the showMediaPicker method in another class and call it, it does not work either.
Something I find it might be relevant:
The original code is in an obj-C file (xxx.m), and now it's transferred into an obj-C++ file (xxx.mm).
I have also modified the base class of SpeakHereController.h from NSObject to UIViewController<MPMediaPickerControllerDelegate> otherwise it will throw a warning that the base class does not contain the required delegate. But in the interface builder it is still displayed as an object (Please refer to SpeakHere sample code).
It seems that it's illegal to convert the built-in xxxViewController.m file to obj-C++ file (.mm extension). In this case a lot of errors will show up if I attempt to do so. Is it true? If so, how to include C++ code in a pure obj-C file?
=============
So how can I make the media picker show up in this case? Any insight will be appreciated.
Thank you very much!
Cheers,
Manca

In order for
[self presentModalViewController:mediaPicker animated:YES];
to work, self needs to be a viewcontroller. I'm worried that you have just changed the base class to avoid compiler errors as this suggests you are not actually instantiating 'self' correctly.
So how are you initialising the SpeakHereController? As a view controller, this would normally be via the designated initialiser, which for a UIViewController is of course initWithNibName:bundle:
You may find the documentation for UIViewController helpful.
With regards to the C++ issue. Although you can mix objective-c and c++ in the way you suggest, I would recommend that you encapsulate your c++ code in it's own class rather than sprinkling it around your viewcontroller code. That will make it more maintainable for the future.

Related

What's the purpose of the AppDelegate and ViewController files that Xcode generates?

I have written a few functioning iPhone applications, but mostly by following tutorials that tell you where to write the code. As a result I have gone without understanding what these files are actually designed to hold.
I made an app with code that is in the application method of the AppDeleagte file, so it gets called when the program runs. I wanted to make this code run on a button press instead, so I added a button, but when I came to put the code in the relevant IBAction, I realised all the variables and methods i needed were in the AppDelegate file, so I couldn't use them in the ViewController file.
So my immediate question is "how should I organise my code so that I can have it run on a button press?", but an explanation of the concepts behind it would be great too, becuase then I can do it without asking next time.
In short, the AppDelegate deals with application level events. Example: application becomes inactive, application starts etc. So whatever you need to setup when the application starts can go in there. As for your problem, I would suggest moving the variables to perhaps a singleton class or have another class that just contains variables and methods as a member in your appdelegate and do like madhu suggests. Having variables and methods directly in your app delegate works, but it can become big and nasty after a while.
import "AppDelegate"
in implementation file of viewcontroller
AppDelegate *app=(AppDelegate*)[[UIApplication sharedApplication]delegate];
[app inappDelegateDeclaredFunctionname];

How do you transfer data between UIViewControllers?

Currently I am making a game for iPhone, and want each level to be on a different uiviewcontroller (I have tried putting them all on the same view controller, but this just makes it jumpy). However, I need a way to get a high score in the level's view controller and send it back to the menu view controller. I am using the code:
SecondLevelViewController *screen = [[SecondLevelViewController alloc] initWithNibName:nil bundle:nil];
screen.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:screen animated:YES];
[screen release];
to get to the viewcontroller and
[self dismissModalViewControllerAnimated:YES];
to get back. I am familiar with NSUserDefaults, which are what I am using currently to get high scores. However, I know this code resets the level's view controller, that is still fine and even great because i want the level to reset-- but if just i could get data back that would be helpful.
Please put things in simple words, because I am very new to programming.
Thanks in advance!
Steve Becker
PS I am using xcode 4.0...
--------------------------------------------ALSO!!!-------------------------------------
The code I am using, I can only figure out how to get transitions "FlipHorizontal", "CoverVertical", and "CrossDissolve"...But I have seen many other cool transitions on the iPhone--like the page corner flipping like a page in a book. If you know how to do these other transitions, please tell me!!!! Greatly appreciated!!!!!
It's much more standard to have all of the levels on the same UIViewController unless the logic is so different that it's like playing different games. However, you could use a whole slew of different methods to achieve this. For example, you could use the NSNotificationCenter, NSUserDefaults, or a plist.
You will want to use delegation or NSNotifications for this.
Think about the different view controllers like the mafia: every view controller is operating on a need-to-know basis.
Look at this answer I gave before.
you could also use a singleton class to modify and access the sharable data in any class of your projects,
Here is the good SO post on singleton class in objective - C
Singleton shared data source in Objective-C
Edited:
What should my Objective-C singleton look like?
Edited: for Curl page animation : below is the link to blog tutorial and the source code.
http://blog.steventroughtonsmith.com/2010/02/apples-ibooks-dynamic-page-curl.html

Load XIB from Custom Bundle via Static Library

I want to load a XIB from a CFBundle, via some code in a Static Library.
Example:
MyViewController * foo = [[Static Library] instance] getMyViewController];
So I have a MyViewController .xib in a CFBundle I manually create, in it's Resources dir.
But if I try to load it via [[MyViewController alloc] initWithNibName:#"MyViewController" bundle:MyBundlePointer] in getMyViewController I get NSInternalInconsistencyException.
Any idea? I am more or less stumped on this one. Not sure it is even possible to do this.
I'm currently having exactly the same issue with Monotouch and that's why I found your question.
I get the very same exception as you do. This makes me assume that I'm not facing a Monotouch issue but a basic (mis)behavior of XIBs/Cocoatouch.
So the answer is: no, it is not possible. Very sad though.
René
this may not be your specific issue, but it is potentially an issue:
CFBundle is not toll-free-bridged with NSBundle. since you used the term CFBundle in your description, i am wondering if you're passing a CFBundle, rather than an NSBundle.
these are two distinct types and you'll need to explicitly create an NSBundle instance because you can't just cast a CFBundleRef as a NSBundle as you can with CF/NS-String, Array, Data, etc.

iPhone: Access a class from another class

I want to make a program that parses an XML file and then updates labels on 2 different tab bar views. On both of these views, I have a refresh button to update the results. What I'd like to do is update both of the views labels from either view. I figure the AppDelegate is probably a good choice to make this happen, but I tried creating classes that the AppDelegate can access but since they're instances of a class they contain no values. I get no errors but the labels don't update even though the data changes. This is the method in my AppDelegate that is called after the XML is parsed:
-(void)callUpdateValues {
NSLog(#"Calling Update from AppDelegate");
home *homeController;
data *dataController;
[homeController updateValues];
[dataController updateValues];
}
One of the update methods looks like:
- (void)updateValues {
NSLog(#"Call Home");
[label1 setText: [[[[totalData objectAtIndex:0] objectForKey:#"nodeChildArray"] objectAtIndex:7] valueForKey:#"nodeContent"]];
[label2 setText:[[[[totalData objectAtIndex:0] objectForKey:#"nodeChildArray"] objectAtIndex:1] valueForKey:#"nodeContent"]];
}
So the view calls the AppDelegate method "callUpdateValues" and then that method should call the individual "updateValues" methods in each view. I am not an expert on this by any means, and I'm really just trying to get an idea of how programming on the iPhone works. I'm probably just not understanding something here, and if someone could give me some sort of answer I'd appreciate it.
Cocoa has a number of classes available for notifying interested parties of changes. Directly calling methods as you describe makes things much more closely coupled than you need to.
In your method that generates the update you'd have:
[[NSNotificationCenter defaultCenter] postNotificationName:#"IGotSomeNewData"
object:newData
userInfo:nil];
And in the classes that want to hear about updates you'd register for the notification:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(newStuff:)
name:#"IGotSomeNewData" object:nil];
And then implement the method that gets called when something happens:
- (void) newStuff: (NSNotification *)notification {
id newData = [notification object];
// Do stuff
}
There's some really great stuff getting done by Apple for XML on the iPhone: XML Reading Material
The first snippet is out of place. I think what you're missing is that you need to create your instances within the AppDelegate.h, expose them using properties (and synthesizing them in the .m). Then you're update structure should fit better.
If you're just picking up iPhone programming, start digging into the guides that apple provides, and even if you're not into that, start pulling down at least 5 sample code projects a day. The beauty of them is that you can build them (even onto your iphone) and if you like a feature, you can see how it's done. Alternatively, get the grapefruit book from APRESS. Beginning iPhone.
Hope this helped.
In the example you gave, homeController and dataController are not properly initialized. If I understand your project correctly, you would have created instances of the homeController and dataController classes in your main XIB file, and connected them up to the appropriate views (label1 and label2). Your AppDelegate should, then, look something like this:
...
#class homeController;
#class dataController;
#interface AppDelegate
{
IBOutlet homeController * home;
IBOutlet dataController * data;
}
...
#end
With this in place, you would add (in your application XIB file), links from your homeController and dataController instances to the appropriate outlets (labeled home and data) in your application delegate.
Then, you could simply reference them by name in your callUpdateValues method:
-(void)callUpdateValues {
NSLog(#"Calling Update from AppDelegate");
[home updateValues];
[data updateValues];
}
On a side note, Cocoa coding standards usually specify that class names are capitalized. This is, of course, up to your personal taste, but if you're just getting started in Cocoa, it may be worth drinking one more cup of kool-aid at this point, just so your code will "fit in" with what most other developers are doing. Again, totally up to you!

Do I always have to call [super viewDidLoad] in the -viewDidLoad method?

In Apple's scrollView example they don't call that. I always thought that's a must. Why should I call that anyways?
If you are overriding the method you should still call the method in the super. Even if the super class is not doing anything with it today, Apple might one day change the implementation and your code will mysteriously stop working. If you really don't need to do anything in that method, leave it out of your code entirely, and the super's method will run as usual, without any intervention on your part.
No, you don't need to call [super viewDidLoad]. Edit: But read below, because I think you definitely should.
Let's be real here: Apple is not going to break thousands of apps, including those based on their published sample code, by deciding an event they're not currently handling suddenly needs to do something that developers may or may not want to stop and it's critical that if you don't need different behavior you not stop the event.
Edit: Having watched how Apple handles compatibility for an extra year, I now recommend learning and using the correct pattern. While I doubt your application binary will ever suddenly stop working, it's clear that the iPhone detects which SDK your binary was built against and modifies some OS behaviour based on this.
Apple might one day require a particular pattern be followed on some future SDK. This would not affect you until you rebuild with the latest Xcode + SDK, but then you'd get these breaks without any source code changes. Learn and follow the pattern to be safe.
As Markus says, UIViewController doesn't do anything in its viewDidLoad method, so you don't have to call it. However, it's a good habit to get into, in case you change your inheritance structure and suddenly the class that used to inherit from UIViewController now inherits from something that does do something in the viewDidLoad method.
Lets say you have 2 class, a Parent and a Child. Child inherits from Parent. They have a method called greet which returns a string.
Here is what the parent method looks like:
Code:
-(NSString *)greet {
return #"Hello";
}
We want the child to learn from his parents. So we use super to say greet how Mommy would greet, but with our own little additions too.
Code:
// Inherits from Parent
-(NSString *)greet {
NSString *parentGreeting = [super greet];
return [parentGreeting stringByAppendingString:#", Mommy"]
}
So now Parent greets "Hello", and the Child greets "Hello, Mommy". Later on, if we change the parent's greet to return just "Hi", then both classes will be affected and you will have "Hi" and "Hi, Mommy".
super is used to call a method as defined by a superclass. It is used to access methods that have been overriden by subclasses so that the class can wrap its own code around a method that it's parent class implements. It's very handy if you are doing any sort of inheritance at all.
Apple's documentation for viewDidLoad does NOT state that you should call [super viewDidLoad], so I would go with what Apple's says. Note, however, that for other similar methods like viewDidAppear, you must call [super viewDidAppear].
You don't have to call the [super viewDidLoad]
As far as I know, the viewDidLoad in the superclass (UIViewController) is only an empty function that gets called when the ViewController gets initialized with a nib-file.
So if you need to do any initializing, you should override this function and put your code there.
Just noticed that the static analyzer of Xcode 6 issues a warning if you do not call super in these functions. So it seems Apple now definitely wants us to call it.
Although in xCode 7 Beta/Swift 2 super.viewDidLoad won't compile. The error says it's only available in osx 10.10 and the auto-fix does this
if #available(OSX 10.10, *){
super.viewDidLoad()}
else
{
// Fallback on earlier versions
}
// My code
}