a dynamic way of doing a questionnaire in iphone - iphone

i managed to read my question from my question.plist for question and answer.
self.view.backgroundColor = [UIColor colorWithRed:99.0/255.0 green:162.0/255.0 blue:223.0/255.0 alpha:1.0];
self.title = #"Game"; //Set title.
// Path to the plist (in the application bundle)
NSString *path = [[NSBundle mainBundle] pathForResource:
#"Question" ofType:#"plist"];
NSArray *array = [NSArray arrayWithContentsOfFile:path];
NSDictionary *dict = [array objectAtIndex:0];
questionlabel.text = [dict valueForKey:#"Question"];
a button here to call for QR code scanner, after scanning it will check if the answer is correct or wrong and direct the user to another question in the question.plist(objectAtIndex:1) if is correct if not it will pop up and show is incorrect
i can do it in a static way of creating a few more to xib to create other question statically, however i know this is a troublesome way to do it. anybody know how can i do it in a dynamic way?
thanks in advances
Desmond

What does the QR code scanner have to do with anything? I think it is not strictly relevant to your question, so I'll only cover exactly what you're asking. QR code scanning is not a part of the iOS and is provided by external libraries.
Add an integer i-var to the view controller:
#interface WhateverYouNamedYourViewController : UIViewController {
// ....
int currentQuestion;
// ....
}
// ....
#end
Then, when loading the question and updating the UI, use that i-var to construct the NSString from which you'll load the question.
NSString *questionFileName = [NSString stringWithFormat:
#"Question%d", currentQuestion];
NSString *path = [[NSBundle mainBundle] pathForResource:questionFileName
ofType:#"plist"];
Alternatively, consider storing all questions in a single plist whose root is an array. Then use NSArray's -objectAtIndex: method to grab the current question (simply pass currentQuestion as the first argument).
In any case, the place where you check for answer correctness (in a quiz) or where you record the answer (in a questionnaire) will need to update the current question and update UI:
currentQuestion++;
[self updateUI];
Updating UI reads the next question and updates labels and buttons appropriately.

Related

Check if exists a string inside a plist file

Hello guys i try to check a single line STRING inside my plist file, in my detail view I need to implement a IF like a:
NSString *data = [[NSBundle mainBundle] pathForResource:#"name" ofType:#"plist"];
NSMutableDictionary *dataDict = [[NSMutableDictionary alloc] initWithContentsOfFile:data];
self.myMutableDictionary = dataDict;
if (name.text == [myMutableDictionary objectForKey:#"emittente"]){
UIImage *image = [UIImage imageNamed:#"star_on.png"];
[Star setImage:image];
} else {
UIImage *favImg = [UIImage imageNamed:#"star_Off.png"];
[Star setImage:favImg];
}
But dosent work, i think no reading inside the plist file, any idea or metod for do that?
Thanks.
Actually, your code looks almost fine. Just check the following:
Does your plist contain the key #"emittente" on the top level? If not, you have to descend down your dictionaries or arrays to get to the right level.
Also, you are comparing pointers in your if statement, not strings. Use this instead:
if ([name.text isEqualToString:myMutableDictionary[#"emittente"]) ...
BTW: you should not use uppercase instance variable names.

Pictures put into a array Ios developing

I have a folder with pictures in my project and i like to know how i could put this pictures from the folder into a array
How should i do that?
I tried this to put the images in the array
UIImage*image = [[NSBundle mainBundle]pathsForResourcesOfType:#"jpg" #"jpeg" #"gif" inDirectory:#"Images"];
NSArray*images = [[NSMutableArray alloc]initWithContentsOfFile:image];
You could do the following, getting the array of filenames and then filling another array with the images, themselves (assuming that's what you were trying to do).
NSMutableArray *imagePaths = [[NSMutableArray alloc] init];
NSMutableArray *images = [[NSMutableArray alloc] init];
NSArray *imageTypes = [NSArray arrayWithObjects:#"jpg", #"jpeg", #"gif", nil];
// load the imagePaths array
for (NSString *imageType in imageTypes)
{
NSArray *imagesOfParticularType = [[NSBundle mainBundle]pathsForResourcesOfType:imageType
inDirectory:#"Images"];
if (imagesOfParticularType)
[imagePaths addObjectsFromArray:imagesOfParticularType];
}
// load the images array
for (NSString *imagePath in imagePaths)
[images addObject:[UIImage imageWithContentsOfFile:imagePath]];
As an aside, unless these are tiny thumbnail images and you have very few, it generally would not be advisable to load all the images at once like this. Generally, because images can take up a lot of RAM, you would keep the array of filenames, but defer the loading of the images until you really need them.
If you don't successfully retrieve your images, there are two questions:
Are the files included in my bundle? When you select the "Build Phases" for your Target's settings and expand the "Copy Bundle Resources" (see the image below), do you see your images included? If you don't see your images in this list, they won't be included in the app when you build it. To add your images, click on the "+" and add them to this list.
Are the files in a "group" or in an actual subdirectory? When you add files to a project, you'll see the following dialog:
If you chose "Create folder references for added folders", then the folder will appear in blue in your project (see the blue icon next to my "db_images" folder in the preceding screen snapshot). If you chose "create groups for added folders", though, there will be the typical yellow icon next to your "Images" group. Bottom line, in this scenario, where you're looking for images in the subdirectory "Images", you want to use the "Create folder references for added folders" option with the resulting blue icon next to the images.
Bottom line, you need to ensure the images are in your app bundle and that they are where you think they are. Also note that iOS is case sensitive (though the simulator is not), so make sure you got the capitalization of "Images" right.
If I am understanding your question correctly initWithContentsOfFile doesn't do what you are expecting, per the documentation:
"Initializes a newly allocated array with the contents of the file specified by a given path."
Additionally, pathsForResourceOfType is already creating an array, not a UIImage, you can simply do:
NSArray* images = [[NSBundle mainBundle]pathsForResourcesOfType:#"jpg" #"jpeg" #"gif" inDirectory:#"Images"];
[[NSBundle mainBundle]pathsForResourcesOfType:#"jpg" #"jpeg" #"gif" inDirectory:#"Images"];
already returns an array of these objects. Change your line to this:
NSArray *images = [[NSBundle mainBundle]pathsForResourcesOfType:#"jpg" #"jpeg" #"gif" inDirectory:#"Images"];
Note that this array will only hold the paths for all your images. In order to make images of them you need to call
for(NSString* imagePath in images) {
UIImage* anImage = [[UIImage alloc] initWithContentsOfFile:imagePath];
//do something with your image here.
}
Hope that helps
Read the documentation of initWithContentsOfFile method of NSArray:
The array representation in the file identified by aPath must contain only property list objects (NSString, NSData, NSArray, or NSDictionary objects). The objects contained by this array are immutable, even if the array is mutable.
In your case you need to use NSFileManager to enumerate files in directory. Here is the example of directory enumeration from documentation:
NSFileManager *localFileManager=[[NSFileManager alloc] init];
NSDirectoryEnumerator *dirEnum =
[localFileManager enumeratorAtPath:docsDir];
NSString *file;
while (file = [dirEnum nextObject]) {
if ([[file pathExtension] isEqualToString: #"doc"]) {
// Create an image object here and add it to
// mutable array
}
}
[localFileManager release];
Try this:
NSMutableArray* paths=[NSMutableArray new];
NSFileManager* manager=[NSFileManager new];
NSBundle* bundle= [NSBundle mainBundle];
NSDirectoryEnumerator* enumerator= [manager enumeratorAtPath: [bundle bundlePath] ];
for(NSString* path in enumerator)
{
if([path hasSuffix: #".jpg"] || [path hasSuffix: #".jpeg"] || [path hasSuffix: #".gif"])
{
[paths addObject: path];
}
}
For explanations I suggest that you look at NSDirectoryEnumerator documentation.

Why redefine pListPath in didSelectRowAtIndexPath?

So I've read a ton of SO-questions about plists and how to save to them, and although I don't know, why no iPhone-Dev-Book I've seen so far covered this (they all used the tableView editing function), I managed to REALLY write to a plist by copying it to the documents folder like this:
pListPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
pListPath = [pListPath stringByAppendingPathComponent:#"piggyBanks.plist"];
NSLog(#"Path: %#", pListPath);
// if the file does not exist yet, create it, and copy the plist data into it, that can be found in the bundle
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:pListPath]) {
NSString *sourcePath = [[NSBundle mainBundle] pathForResource:#"piggyBanks" ofType:#"plist"];
[fileManager copyItemAtPath:sourcePath toPath:pListPath error:nil];
}
// make the plist content available for usage
pListContent = [[NSMutableDictionary alloc] initWithContentsOfFile:pListPath];
NSLog(#"pListContent: %#", pListContent);
So far so good, but now, if I wanna change some plist value when a user taps on a tableViewCell (it's a custom one, if that's important), although pListPath, pListContent and others are properties, defined in .h and synthesized in .m, I have to redefine pListPath and pListContent inside didSelectRowAtIndexPath, to get the path to be known in that moment.
Could someone please tell me why? I mean, it's nice, that it works, but I'd like to know, why it has to be like that, or if I did a mistake somewhere else..
Thanks!
If plistPath is a string property of your class, you need to assign it as such:
if (!self.pListPath)
{
NSString *newPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
newPath = [newPath stringByAppendingPathComponent:#"piggyBanks.plist"];
self.pListPath = newPath;
}
Then afterwards, use self.pListPath instead of pListPath.
You are having to re-set it because at the moment, pListPath is being assigned to an autoreleased string which will have been removed by the time you need it again. Setting the property (assuming the property is retained or copied) will retain the string for you.
I googled for class variables in objective C, and found my way through various articles, till i found this blog/blogpost, which explains the self. and _underscore thing really well!
I now always declare my Ivars with an underscore, the properties without. Works out quite well. And to sum it up, why to ALWAYS use self.yourPropertiesName, you are calling a method (setter and getter)! And like any other method you are calling, you need to say, who is calling.
Hope this will help someone else too :)

Get album artwork from ID3 tag/Convert function from Java to Objective-C

I've got the following question to ask:
How do you compile taglib with an iOS application?
I'm a bit confused as I added the folder into my project, tried to compile it, but instead it failed with 1640 errors.
How do I make it successfully compile - the reason why I ask is taglib allows for the extraction of album artwork from a tag.
If anyone knows an Objective-C based album artwork extraction class it would help - I don't know why Apple don't add a way of doing this in Core Foundation - because there are methods for extracting some of the data from an ID3 tag.
I can't see why there isn't some Objective-C way of doing it.
Any help appreciated.
EDIT:
After hours upon hours of trying to do this, I've found a Java function here that seems to do the job fine, but I haven't got a clue on how to convert it to Objective-C (or let alone C++ for that matter), as its types seem to be completely different from those that are in Objective-C/C++. If anyone knows of a way to convert this it would really help, as this seems as my last option as I've tried so many others.
- (void)loadArtworksForFileAtPath:(NSString *)path completion:(void (^)(NSArray *))completion
{
NSURL *u = [NSURL fileURLWithPath:path];
AVURLAsset *a = [AVURLAsset URLAssetWithURL:u options:nil];
NSArray *k = [NSArray arrayWithObjects:#"commonMetadata", nil];
[a loadValuesAsynchronouslyForKeys:k completionHandler: ^{
NSArray *artworks = [AVMetadataItem metadataItemsFromArray:a.commonMetadata
withKey:AVMetadataCommonKeyArtwork keySpace:AVMetadataKeySpaceCommon];
NSMutableArray *artworkImages = [NSMutableArray array];
for (AVMetadataItem *i in artworks)
{
NSString *keySpace = i.keySpace;
UIImage *im = nil;
if ([keySpace isEqualToString:AVMetadataKeySpaceID3])
{
NSDictionary *d = [i.value copyWithZone:nil];
im = [UIImage imageWithData:[d objectForKey:#"data"]];
}
else if ([keySpace isEqualToString:AVMetadataKeySpaceiTunes])
im = [UIImage imageWithData:[i.value copyWithZone:nil]];
if (im)
[artworkImages addObject:im];
}
completion(artworkImages);
}];
}
This is just the answer of #hatfinch above but fixed and now working.
- (void)artworksForFileAtPath:(NSString *)path block:(void(^)(NSArray *artworkImages))block
{
NSURL *url = [NSURL fileURLWithPath:path];
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:url options:nil];
NSArray *keys = [NSArray arrayWithObjects:#"commonMetadata", nil];
[asset loadValuesAsynchronouslyForKeys:keys completionHandler:^{
NSArray *artworks = [AVMetadataItem metadataItemsFromArray:asset.commonMetadata
withKey:AVMetadataCommonKeyArtwork
keySpace:AVMetadataKeySpaceCommon];
NSMutableArray *artworkImages = [NSMutableArray array];
for (AVMetadataItem *item in artworks) {
NSString *keySpace = item.keySpace;
if ([keySpace isEqualToString:AVMetadataKeySpaceID3]) {
NSDictionary *d = [item.value copyWithZone:nil];
[artworkImages addObject:[UIImage imageWithData:[d objectForKey:#"data"]]];
} else if ([keySpace isEqualToString:AVMetadataKeySpaceiTunes]) {
[artworkImages addObject:[UIImage imageWithData:[item.value copyWithZone:nil]]];
}
}
if(block) {
block(artworkImages);
}
}];
}
If you are merely wanting to access the artwork of the music already stored on the device i.e from the iPod application, then check out this article which demonstrates how to do it using existing frameworks provided by Apple, specifically the MediaPlayer framework.
If not, it may be wise to provide a little more information about what you are trying to achieve and also provide examples of the errors you are getting when trying to compile TagLib.
EDIT:
Another solution could be to use an embedded webview and use a JavaScript library such as this one to load, parse and fetch the album artwork?
You could use this: https://github.com/EliaCereda/TagLib-ObjC

Can't read from plist

I have a plist with an array at top level and then a number of items within it.
When I try the following
NSString *path = [[NSBundle mainBundle] bundlePath];
NSString *finalPath = [path stringByAppendingPathComponent:#"Spots.plist"];
spotsArray = [[NSMutableArray arrayWithContentsOfFile:finalPath] retain];
the array spotsArray is empty.
I have tried a number of things and have used plists successfully before. I dont know what the issue is now.
What could be causing the issue, my plist looks like this
It's not an array at the top level it's a dictionary with a single item called 'New Item'.
Try NSMutableArray *mutableArray = [[[NSDictionary dictionaryWithContentsOfFile:finalPath] objectForKey:#"New Item"] mutableCopy] autorelease]
This should mean that your .plist file does not exist or not readable.
Try to create the file with writeToFile at the same path to verify it works. (It can also help you to verify the directory)