Looping Through NSArray - mpmovieplayercontroller

This is suppose to play all the songs in the NSArray but it only plays one and stops. What am I doing wrong? The array contains a whole bunch of links to different .mp3 formatted songs.
NSArray *array = [myString componentsSeparatedByString:#"\n"];
int nextTag = 1;
for (soundPath in array) {
NSURL *url = [NSURL URLWithString:soundPath];
asset = [AVURLAsset URLAssetWithURL:url options:nil];
yourMediaPlayer = [[MPMoviePlayerController alloc] initWithContentURL:url];
yourMediaPlayer.controlStyle = MPMovieControlStyleNone;
yourMediaPlayer.currentPlaybackTime = 0;
yourMediaPlayer.shouldAutoplay = FALSE;
[yourMediaPlayer play];
nextTag++;
}

Instead of trying to get MPMoviePlayerController play a list of items use AVQueuePlayer instead. It has a convenient advanceToNextItem method.
You can create a player already loaded with items (class AVPlayerItem) either with initWithItems or queuePlayerWithItems. Then just call play on it (inherited from AVPlayer) and it should play the items one after the other.
See:
AVQueuePlayer docs
AVPlayer docs
AV Foundation Programming Guide
AVPlayerItem docs

Related

How do I add background music to my spritekit file

Could someone give me a quick easy step by step to adding background m4a music once my app has loaded. It is a sprite kit Xcode file, and the music is in m4a format. Thanks
Try with this:
#import AVFoundation;
...
AVAudioPlayer * backgroundMusicPlayer;
NSError *error;
NSURL * backgroundMusicURL = [[NSBundle mainBundle] URLForResource:#"song" withExtension:#"m4a"];
backgroundMusicPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:backgroundMusicURL error:&error];
backgroundMusicPlayer.numberOfLoops = -1; //-1 = infinite loop
[backgroundMusicPlayer prepareToPlay];
[backgroundMusicPlayer play];
and to stop simply
[backgroundMusicPlayer stop];
note: I don't use SKAction to play background music because you can't stop it when you want
You can use AVAudioPlayer for this purpose:
In your .h:
#import <AVFoundation/AVFoundation.h>
and add the following to interface
AVAudioPlayer *player;
In .m, initialize player with audio oath url:
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle]
pathForResource:#"bg_music"
ofType:#"mp3"]];
player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
player.numberOfLoops = -1;
and when you need to play the audio, you can call:
[player play];
Note:
"numberOfLoops" is the number of times that the sound will return to the beginning upon reaching the end.
A value of zero means to play the sound just once.
A value of one will result in playing the sound twice, and so on...
Any negative number will loop indefinitely until stopped.
Keep Coding................ :)

Scaling a QTMovie before appending

Using the QTKit framework, I'm developing a little app.
In the app, I'm trying to append a movie after a other movie, which in essence is already working (most of the time), but I'm having a little trouble with the appended movie. The movie is which I'm appending to is quite big, like 1920x1080, and the appended movie is usually much smaller, but I never know what size it exactly is. The appended movie sort of stays its own size in the previous 1920x1080 frame, as seen here:
Is there anyone familiar with this? Is there a way I can scale the movie which I need to append to, to the size of the appended movie? There is no reference of such a thing in the documentation.
This is are some relevant methods:
`QTMovie *segmentTwo = [QTMovie movieWithURL:finishedMovie error:nil];
QTTimeRange range = { .time = QTZeroTime, .duration = [segmentTwo duration] };
[segmentTwo setSelection:range];
[leader appendSelectionFromMovie:segmentTwo];
while([[leader attributeForKey:QTMovieLoadStateAttribute] longValue] != 100000L)
{
//wait until QTMovieLoadStateComplete
}
NSDictionary *exportAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], QTMovieExport,
[NSNumber numberWithLong:kQTFileTypeMovie], QTMovieExportType, nil];
NSString *outputFile = [NSString stringWithFormat:#"%#.mov", onderwerp];
NSString *filepath = [[#"~/Desktop" stringByExpandingTildeInPath] stringByAppendingFormat:#"/%#", outputFile];
BOOL succes = [leader writeToFile:filepath withAttributes:exportAttributes error:&theError];
Leader is initialized like this:
NSDictionary *movieAttributes = [NSDictionary dictionaryWithObjectsAndKeys:path, QTMovieFileNameAttribute, [NSNumber numberWithBool:YES], QTMovieEditableAttribute, nil];
leader = [QTMovie movieWithAttributes: movieAttributes error:&error];
This contained all the information I need, although without using the QTKit framework. QTKit - Merge two videos with different width and height?

Call phone number from UIButton

I've searched through all the questions and can't seem to find my answer.
I have the following IBAction. This is crashing every time you tap on the phone number. I have gone back to the DB and formatted the phone numbers to 5551235555 instead of (555)-123-5555.
- (IBAction)callPhone:(UIButton *)sender{
Bar *items = self.detailItem;
NSURL *pn = [NSURL URLWithString:[NSString stringWithFormat:#"tel:%#", items.barPhone]];
[[UIApplication sharedApplication] openURL:pn];
}
- (void)setCallButton:(UIButton *)callButton{
Bar *items = self.detailItem;
[callButton setTitle:items.barPhone
forState:UIControlStateNormal];
}
Any code guidance would be appriciated.
Bar *items = self.detailItem; is not initiated, so that is why it is returning nil. Try the following:
Bar *items = [[Bar alloc] init];
items = self.detailItem;
Or what you should have done is make items an ivar for this particular class. Then you can initiate items once and use it throughout your class.

Find out if .png file is a screenshot?

When I get the attributes of a specific file with the following code:
NSFileManager *fileManager = [NSFileManager defaultManager];
NSDictionary *attributes = [fileManager attributesOfItemAtPath:p error:nil];
Is there an attribute to know if it's a screenshot or not?
Right now I'm using this awkward piece of code:
if ([fileExtension isEqualToString:#"png"]) {
NSMutableArray *separatetFilename;
separatetFilename = [NSMutableArray arrayWithArray:[fileName componentsSeparatedByString:#" "]]; /* screenshots have multiple spaces in their names, I split them up to use the information */
if ([separatetFilename count] == 4) { /* screenshots names have 4 parts when splittet by spaces */
if ([[separatetFilename objectAtIndex:0] isEqualToString:#"Bildschirmfoto"]) { /* Bildschirmfoto = Screenshot in German */
/* Do Something */
}
}
}
With this solution I would have to put in localized Strings for the "Screenshot" string... I searched the documentary but didn't find anything. Is there a "isScreenshot" flag or something I could read?
Your question "Is there a "isScreenshot" flag or something I could read?" and the answer is "YES".
I know of two ways to get the answer:
a) ask the NSFile~Manager
b) ask for metadata.
You already used:
NSFileManager *fileManager = [NSFileManager defaultManager];
NSDictionary *attributes = [fileManager attributesOfItemAtPath:p error:nil];
If you now have a look at the keys of this dictionary e.g. with
NSLog( #"the keys: %#", [attributes allKeys] );
you will find the key #"NSFileExtendedAttributes*". The value of this key is a dictionary with keys like com.apple.metadata:kMDItemIsScreenCapture or com.apple.metadata:kMDItemScreenCaptureType or .... This is what you asked for. The corresponding values are NSData-objects with a binary property list. Evaluating these plist give something like 1 (it is a screenshot) and window for a window screenshot or selection for a part of the window.
Looking at the metadata can be done with:
MDItemRef item = MDItemCreate( kCFAllocatorDefault, (CFStringRef)p );
If you only need the above mentioned values create a list (an NSArray) with the corresponding keys:
NSArray *ary = [NSArray arrayWithObjects:
#"kMDItemIsScreenCapture", #"kMDItemScreenCaptureType", nil];
NSDictionary *dict =
(NSDictionary *)MDItemCopyAttributes( item, (CFArrayRef)ary );
and test what it returns;
NSLog( #"the metadata are %#", dict );
In this case the returned values are __NSCFBoolean (i.e. NSNumber) and __NSCFString (i.e. NSString) which is a bit simpler to work with than a binary plist.

NSArray to Core Data items

I have an method that reads an xml file and stores the xml nodes at a certain XPath-path in an NSArray called *nodes. What I want to do is take each one of the items in the array and add it to a core data entity called Category with the attribute of "name".
I have tried a number of different ways of creating the entity but I'm not sure about the correct way to do this effectively. This is the code used to create the NSArray, any ideas on how to implement this? (ignore the NSError, I will fix this in the final version)
- (IBAction)readCategories:(id)sender
{
NSString *xmlString = [resultView string];
NSData *xmlData = [xmlString dataUsingEncoding: NSASCIIStringEncoding];
NSXMLDocument *xmlDoc = [[NSXMLDocument alloc] initWithData:xmlData options:nil error:nil];
//XPath
NSError *err=nil;
NSArray *nodes = [xmlDoc nodesForXPath:#"//member[name='description']/value/string" error:&err];
}
EDIT - My loop code
NSArray *nodes = [xmlDoc nodesForXPath:#"//member[name='description']/value/string" error:&err];
int arrayCount = [nodes count];
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSXMLElement *categoryEl;
NSString *new = [catArrayController newObject];
int i;
for (i = 0; i < arrayCount; i++)
{
[categoryEl = [nodes objectAtIndex:i]];
[new setValue:[categoryEl stringValue] forKey:#"name"];
[catArrayController addObject:new];
}
[pool release];
Here's how I'd write it:
for (NSXMLElement *categoryElement in nodes) {
NSManagedObject *newObject = [catArrayController newObject];
[newObject setValue:[categoryElement stringValue] forKey:#"name"];
[catArrayController addObject:newObject];
[newObject release];
}
First, I'm using the Objective-C 2.0 for-each syntax. This is simpler than using index variables. I eliminated i and arrayCount.
Next, I took out your NSAutoreleasePool. None of the objects in the loop are autoreleased, so it had no effect. (The newObject method returns a retained object which is, by convention, what methods with the word new in their name do) This is also why I release newObject after adding it to the array controller. Since I'm not going to be using it any more in this method, I need to release it.
Also, you had defined new (which I renamed newObject) as an NSString. Core Data objects are always either an instance of NSManagedObject or a subclass of NSManagedObject.
Your line [categoryEl = [nodes objectAtIndex:i]] won't compile. That's because the bracket syntax is used to send a message to an object. This is an assignment statement, so the bracket syntax is not needed here. (This line is also not necessary any more because of I've changed the loop to use the for-each syntax) But, for future reference, categoryEl = [nodes objectAtIndex:i]; would have worked.
What part are you having trouble with? There shouldn't be much more to it than looping through the array, creating a new managed object for each entry, and setting the correct attributes. You can create the managed object with NSEntityDescription's -insertNewObjectForEntityForName:inManagedObjectContext: method.

Resources