iOS5 using ARC: Implicit conversion of int to NSDictionary - ios

i´m using ARC to update my old project.
I have a "Filehelper" class in which i use c-functions e.g. for methods i need in almost every projects. (eg.load plist, etc..)
ViewController
NSDictionary* dictionary = getDictionaryFromPlistWithName(#"TestFile", #"plist");
Filehelper.m
#pragma Returns content of plist as NSDictionary
NSDictionary* getDictionaryFromPlistWithName(NSString* fileName, NSString* pathExtension) {
NSString *path = [[NSBundle mainBundle] pathForResource:fileName ofType:pathExtension];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:path];
if(fileExists){
NSDictionary* dictionary = [NSDictionary dictionaryWithContentsOfFile:path];
return dictionary;
}
else{
[NSException raise:#"File not found" format:#"path %#", path];
return nil;
}
}
I get this error:
*error: Automatic Reference Counting Issue: Implicit conversion of 'int' to 'NSDictionary ' is disallowed with ARC
Any ideas how to fix it to use it with iOS 5?
I´ve read something that i need to use (__bridge NSDictionary*), but that didn´t help.
PS.
What´s your workflow for classes which you already need? Use C-functions, too?=
What´s the best way?

The most likely problem here is that you forgot to #include your header file. I bet there are further warnings that you're ignoring, particularly one that says something like "unknown signature for getDictionaryFromPlistWithName, assuming it returns int". Read through your warnings and never ignore them (I strongly recommend -Werror for all ObjC projects).

Related

Implicit conversion of a non-Objective-C pointer type 'SEL' to 'NSString * _Nonnull' is disallowed with ARC [duplicate]

This question already has answers here:
What's the difference between a method and a selector?
(3 answers)
Closed 4 years ago.
I read 5 other related questions with the same error or syntax. As far as I understood non had anything related to my question.
-(void) createCopyOfDBIfNeeded{
NSFileManager *fileManager= [NSFileManager defaultManager];
BOOL isDatabaseInCache = [fileManager fileExistsAtPath:#selector(getDBFile)];
if (isDatabaseInCache) {
return;
}
}
//getDBFile Method:
-(NSString *) getDBFile {
NSArray * paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString * DBPath = [paths firstObject];
NSString * DBFile = [DBPath stringByAppendingPathComponent:#"productDBFile.db"];
return DBFile;
}
It seems the error is related to #selector(getDBFile).
If I use [self getDBFile] instead everything works, but I want to learn how and where to use #selector appropriately and what the error/warning means here.
I ALSO get a warning: Incompatible pointer types sending 'SEL' to parameter of type
EDIT: This is question is fundamentally a duplicate of What's the difference between a method and a selector?
You can only pass a selector to a method that takes a selector. fileExistsAtPath: takes an NSString *, not a SEL.
It looks like you want to pass the return value of getDBFile to fileExistsAtPath:, not getDBFile's selector.
If so, just call getDBFile instead of taking its selector:
BOOL isDatabaseInCache = [fileManager fileExistsAtPath:[self getDBFile]];

CSV to NSString results in empty null object

I'm trying to retrieve content of a csv file to NSString. Thats what I do:
NSString *strBundle = [[NSBundle mainBundle] pathForResource:#"socs" ofType:#"csv"];
NSLog(#"bundle path: %#",strBundle);
NSString *file = [NSString stringWithContentsOfFile:strBundle
encoding:NSUTF8StringEncoding
error:nil];
if ([[NSFileManager defaultManager]fileExistsAtPath:strBundle]) {
NSLog(#"file is there!!!");
}else {
NSLog(#"no file");
}
NSLog(#"file: %#",file);
NSArray *allLines = [file componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
NSLog(#"lines: %lu",(unsigned long)[allLines count]);
file manager shows that the file is there. When i try to log the NSString or number of files it says null. I even created NSData object with the content of exactly the same file and when I logged the NSData object, I clearly saw that there is some data. Then when I tried to create NSString with the content of NSData, I had the same result as before - null. Maybe the problem is somewhere in the formatting of the file?
Any help will be appreciated :)
I see 3 issues:
You are passing a nil argument to the error: parameter in your stringWithContentsOfFile: line. If there's a possibility something might go wrong (and apparently there is), you should pass a real argument there so you can figure out what went wrong.
You can use componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet], but that has a tendency to produce blank "components" between every line. Plain old #"\n" works better in virtually all cases I've run into.
You should be checking fileExistsAtPath before you try to load it into the NSString
If you were truly able to create an NSData object from the path it doesn't necessarily mean it's correct data. But let's say it is, if you were not able to convert it to a NSString then you need to check your encoding parameter.

iOS: Read data from .plist in dictionary

I would like to retrieve data from a plist in my .app directory.
I can not figure out how to get sub-dictionary data. For instance, I would like to get the MemoriesDictionary/Memory1/Event1/EventName value.
I am able to get the MemoryCount value into iMemCount just fine with:
int iMemCount;
//Do file searching/getting for plist
NSString *plistDirectory = [[NSBundle mainBundle] pathForResource:#"memoryDetails" ofType:#"plist"];
NSLog(#"array: %#",plistDirectory);
NSFileManager *fileManager = [NSFileManager defaultManager];
if ([fileManager fileExistsAtPath: plistDirectory]) //4
{
NSLog(#"exists");
NSMutableDictionary *savedStock = [[NSMutableDictionary alloc] initWithContentsOfFile: plistDirectory];
iMemCount = [[savedStock objectForKey:#"MemoryCount"] intValue];
} else {
NSLog(#"Does Not Exist");
iMemCount = 0;
}
NSString *string = savedStock[#"MemoriesDictionary"][#"Memory1"][#"Event1"][#"EventName"];
Edit
You could also rewrite:
int iMemCount;
iMemCount = [[savedStock objectForKey:#"MemoryCount"] intValue];
as
NSInteger iMemCount;
iMemCount = [savedStock[#"MemoryCount"] integerValue];
You really should be taking into account the possibility of your iOS code running on a 64-bit processor and use the appropriate platform safe types (NSInteger, CGFloat, CFIndex, etc)
Note also that using an NSMutableDictionary here may not do what you expect: the top-level dictionary will be mutable but all the sub-objects (arrays, dictionaries) will be immutable and throw an exception if you try to access them.
In general I’d caution against doing lookups several levels deep in dictionaries, because it’s usually a sign that you’re doing something the hard way. The pattern I like to follow is create classes that can read and write themselves to dictionaries, and then when I read in a file create instances that can be queried directly.
Dealing with a bunch of mutable dictionaries with a bunch of string keys is a recipe for heartache and disaster. You lose compile-time type checking and compile-time variable name checking and readability.
Also, I don’t know if this is a contrived example file, but I wouldn’t write the count to the file explicitly—just calculate it as needed. Duplicating data leads to data being out of sync. And it seems like MemoriesDictionary really wants to be an array, if the names of the memories are inside the sub-dictionaries, and the keys are used to keep the memories in order.

Cocos2d: .plist file giving me a SIGABRT error

Hello I am making a side scrolling cocos2d app. I am using a .plist file for most of the data in my game. When I run the code it immediately gives me a SIGABRT error. I am new to objective c and cocos2d and I am not experienced with .plist files. This is the .plist file.
This is the code that I am pretty sure is causing the problem.
NSString *path = [[NSBundle mainBundle] bundlePath];
NSString *finalPath = [path stringByAppendingPathComponent:#"GameData.plist"];
NSDictionary *plistData = [NSDictionary dictionaryWithContentsOfFile:finalPath];
NSMutableArray* characterArray = [NSMutableArray arrayWithArray:[plistData objectForKey:#"Characters"]];
NSDictionary *theCharacterDict = [NSDictionary dictionaryWithDictionary: [characterArray objectAtIndex:0]];
NSDictionary* characterDict = [NSDictionary dictionaryWithDictionary:[theCharacterDict objectForKey:#"PlayerProperties"]];
character = [Character createWithDictionary:characterDict];
[self addChild:character z:kCharacterLevel];
I do not know if this is the code that is causing the problem. I will post more code if needed.
Okay I don't know if this is what is causing the error, but I immediately spotted an error in your code. NSMutableArray* characterArray The asterisk should be immediately before characterArray.
As I read further, there are several minor errors in the code you posted. Asterisks are in the wrong places are there are too many spaces in certain areas. My suggestion is to read through your code line by line to help catch such errors.

How to add and get the values from .plist in iOS

I am implementing a application based on web services. In that I need to add a string as property in .plist and I need to get the value from the .plist whenever I need in the code.
Here is a code sample:
NSString *path = [[NSBundle mainBundle] pathForResource: #"YourPLIST" ofType: #"plist"];
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile: path];
id obj = [dict objectForKey: #"YourKey"];
NSBundle* mainBundle = [NSBundle mainBundle]; 
 
// Reads the value of the custom key I added to the Info.plist
NSString *value = [mainBundle objectForInfoDictionaryKey:#"key"];
//Log the value
NSLog(#"Value = %#", value);
// Get the value for the "Bundle version" from the Info.plist
[mainBundle objectForInfoDictionaryKey:#"CFBundleVersion"];
// Get the bundle identifier
[mainBundle bundleIdentifier];
NSURL *url = [[NSBundle mainBundle] URLForResource:#"YOURPLIST" withExtension:#"plist"];
NSArray *playDictionariesArray = [[NSArray alloc ] initWithContentsOfURL:url];
NSLog(#"Here is the Dict %#",playDictionariesArray);
or you can use following also
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"Sample.plist"];
Get from plist is very simple.
NSString *path = [[NSBundle mainBundle] pathForResource:#"SaveTags" ofType:#"plist"];
if (path) {
NSDictionary *root = [NSDictionary dictionaryWithContentsOfFile:path];
}
If you want to add something to a plist, maybe you can find the answer here:
How to write data in plist?
But if you only want save some message in you app, NSUserDefaults is the better way.
You can not do this. Any Bundle wether it is iOS or Mac OS is readonly, you can only read to it and you can't create files, write or do anything with the files in a bundle. This is part of the Security features of apple. You can use the NSDocumentsDirectory to writr and read your stuff you need for your app
Swift
I know this was asked 12+ years ago. But this was the first SO question to come up via google. So to save time for everyone, here is how to do this in swift:
struct Config {
// option 1
static var apiRootURL: String {
guard let value = (Bundle.main.object(forInfoDictionaryKey: "BASE_URL") as? String), !value.isEmpty else {
fatalError("Base URL not found in PLIST")
}
return value
}
// option 2
static var databaseName: String {
guard let value = (Bundle.main.infoDictionary?["DB_NAME"] as? String), !value.isEmpty else {
fatalError("DB NAME not found in PLIST")
}
return value
}
}
Notice the 2 functions use slightly diffrent methods to access the plist. But in effect they are almost the same.
In theory there might not be a plist. Hence infoDictionary is optional. But in this case the first method will also return an unexpected value, resulting in an error.
One actual difference as noted by Apple:
Refering to Bundle.main.object(forInfoDictionaryKey: "BASE_URL")
Use of this method is preferred over other access methods because it returns the localized value of a key when one is available.

Resources