Loading NSBundle files iOS - ios

I am attempting to load an executable file from a bundle stored in the apps documents directory. I can create the NSBundle successfully and read the info.plist but whenever I try to load the bundle with [NSBundle load] I always get a similar error no matter how I try to load the bundle:
Cannot find executable for CFBundle 0x..... (not loaded)" or, when using an NSError "The bundle "${PRODUCT_NAME}" couldn't be loaded because its executable couldn't be located
The bundle contains two items, 1) info.plist and 2) Obj-c class header and implementation. I have edited the info.plist to change the Principal class name.
I first copy the bundle into the iPhone simulators documents directory then run the following code after a button press to load the bundle.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *file = [documentsDirectory stringByAppendingPathComponent:#"TestBundle.bundle"];
NSBundle *myBundle = [NSBundle bundleWithPath: file];
[myBundle load];
I understand that you are not supposed to load executables after run time but I have seen a couple of articles/ comments from people who are able to do it, at least on a simulator.
I would basically like to know why i get this error and how to fix it (if possible).
Thanks

Related

Cannot get mainBundle resources (returns null)

I'm trying to access a resource file I added in the app using relative pathing. I've read that I was supposed to use something like this :
NSBundle *mainBundle = [NSBundle mainBundle];
NSString *filePath = [[mainBundle resourcePath] stringByAppendingPathComponent:#"myFile.txt"];
fh = [NSFileHandle fileHandleForReadingAtPath:resourcePath];
Except this isn't working. With NSLog, I am able to confirm mainBundle isn't null and resourcePath returns something like this:
/Users/tom/Library/Developer/CoreSimulator/Devices/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX/data/Containers/Bundle/Application/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX/MyApp_Demo.app/myFile.txt
I've tried many things, such as adding the name of directory where the resource is located, that would be Ressources/myFile, but nothing is yielding any result.
I'm a total beginner with Objective-C but I have to tinker with legacy code and I have to deal with this, so any help is much appreciated.
Side note:
this is what the project structure looks like from Xcode:
Meanwhile, in Finder, the Ressources directory isn't inside the MyApp directory, rather they're on the same level inside the project directory. I wonder if that could be the problem.
Side note 2:
NSString *filePath2 = [[NSBundle mainBundle] pathForResource:#"myFile" ofType:#"txt"];
returns (null) after logging in the console.
It is best to use a simulator for this debugging process
Verification
You should check if the file or Resources folder is actually being copied to the right location or not. If you have added the Resources folder, than check it with the below code
NSString *resourcesFolderPath = [[NSBundle mainBundle] pathForResource:#"Resources" ofType:nil];
NSString *fullFilePath = [NSString pathWithComponents:#[demoToursPath,"filename.txt"]];
NSFileManager *manager=[NSFileManager defaultManager];
NSLog(#"Filepath: %#", fullFilePath);
NSLog(#"File Exist: %#", [manager fileExistsAtPath:fullFilePath]);
Once you have confirmed this, you can update your code to match the location and path it needs to be in order to access the file.
Additional Debug
You can also just print the Document Directory for the application and open a finder window and navigate there to see if the Resources folder is added at the right place (if it was added)
NSString *documentDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0]
NSLog(#"Document Directory: %#", documentDir);
If you update the question with more info, I would be able to help you better

Write to a file. Functional in the simulator and not functional on a real iphone [duplicate]

I am trying to take content from one file and write it into another. I am reading fine, but I am not able to write it into another file.
I have a database of words. I want to separate the words into different files based on the number of letters. All four letter words go into one file, and so on. I added a txt file called "4letter" into my resources and the following is my code:
NSError *error;
//READ
NSString *dbFile = [[NSBundle mainBundle] pathForResource:#"words" ofType:#"txt"];
NSString *test = [NSString stringWithContentsOfFile:dbFile encoding:NSUTF8StringEncoding error:&error];
//convert from string to array
NSArray *lines = [test componentsSeparatedByString:#"\n"];
NSFileHandle *logFile = nil;
logFile = [NSFileHandle fileHandleForWritingAtPath:[[NSBundle mainBundle] pathForResource:#"4letter" ofType:#"txt"]];
//Test if write works
for (int i=0; i<5; i++)
{
NSString *randomAnagram = [[lines objectAtIndex:i] lowercaseString];
[logFile writeData: [randomAnagram dataUsingEncoding: NSNEXTSTEPStringEncoding]];
}
In iOS, you can't write into a file in your app's bundle -- the entire bundle is read-only. Use a path into the Documents folder instead.
See special File System Programming Guide for better understnading.
In iOS, you can't write into a file in your app's bundle -- the entire bundle is read-only.
Consider reading iOS Data Storage Guidelines to better understand the purpose of directories below, in context of iCloud backup.
<Application_Home>/AppName.app
This is the bundle directory containing the app itself. Do not write
anything to this directory. To prevent tampering, the bundle directory
is signed at installation time. Writing to this directory changes the
signature and prevents your app from launching again.
<Application_Home>/Documents/
Use this directory to store critical user documents and app data
files. Critical data is any data that cannot be recreated by your app,
such as user-generated content. The contents of this directory can be
made available to the user through file sharing. The contents of this
directory are backed up by iTunes.
<Application_Home>/Library/
This directory is the top-level directory for files that are not user
data files. You typically put files in one of several standard
subdirectories but you can also create custom subdirectories for files
you want backed up but not exposed to the user. You should not use
this directory for user data files. The contents of this directory
(with the exception of the Caches subdirectory) are backed up by
iTunes. For additional information about the Library directory, see
“The Library Directory Stores App-Specific Files.”
See full list (tmp/, Documents/Inbox) in iOS Standard Directories: Where Files Reside
UPDATE
I use NSFileManager method URLForDirectory:inDomain:appropriateForURL:create:error:
Like Caleb said, you can't write to your app's directory, but you can write to your app's Documents folder. You can get it like this:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
Your app's bundle is read-only. There is two ways I could see:
1) Write in documents folder:
NSArray *pathList = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path =  [myPathList  objectAtIndex:0];
2) Use sqlite database. This is the same as 1 (you must save db in documents anyway), but you're using sqlite database. I think this is better than a lot of txt and plist files: here's a tutorial on the topic.
I use the following code :
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *appFile = [documentsDirectory stringByAppendingPathComponent:#"set.txt"];
NSString *data=#"Kostas";
[data writeToFile:appFile atomically:YES];
NSString *myData = [NSString stringWithContentsOfFile:appFile];
NSLog(#"Data : %# ",myData);

SQLite3 db on iOS 9: read only error, how to write to the db? [duplicate]

i deployed my App to my iPhone and get
Unknown error calling sqlite3_step (8: attempt to write a readonly database) eu
on Insert / Update Statements.
On the Simulator it all works like it should.
My sqlite Database is placed in the Resource Folder (Xcode).
Thanks for help!
Your application bundle is not writable on the iPhone. You MUST copy the file somewhere else, like your documents folder. It works in the simulator because the Mac does not enforce all the sandboxing restrictions the iPhone does.
You can copy your database from the application bundle directory to the Documents directory in viewDidLoad. You can read/write from/to your database in the Documents directory after this. Of course, you need to check if the database in the Documents directory exist before you do the copy in order not to overwrite it the next time you bring up the app.
Assuming you have defined your database name '#define kFilename #"yourdatabase.db"' in the .m file.
In viewDidLoad add:
// Get the path to the main bundle resource directory.
NSString *pathsToReources = [[NSBundle mainBundle] resourcePath];
NSString *yourOriginalDatabasePath = [pathsToResources stringByAppendingPathComponent:kFilename];
// Create the path to the database in the Documents directory.
NSArray *pathsToDocuments = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [pathsToDocuments objectAtIndex:0];
NSString *yourNewDatabasePath = [documentsDirectory stringByAppendingPathComponent:kFilename];
if (![[NSFileManager defaultManager] isReadableFileAtPath:yourNewDatabasePath]) {
if ([[NSFileManager defaultManager] copyItemAtPath:yourOriginalDatabasePath toPath:yourNewDatabasePath error:NULL] != YES)
NSAssert2(0, #"Fail to copy database from %# to %#", yourOriginalDatabasePath, yourNewDatabasePath);
}
Good luck!
aobs

Accessing assets in iOS7 with NSBundle

I am having problems updating an app to iOS7 SDK. Before I've used iOS 6 SDK and accessed my mp3 file using a NSURL for the folder like this:
NSURL *folderURL = [[NSBundle mainBundle] URLForResource:#"" withExtension:#"" subdirectory:#"AudioGuide"];
Now, using the iOS 7 SDK I always get nil as the value for folderURL and my audio guide doesn't find the mp3's anymore.
I've already looked into the generated .app-Bundle for the simulator (in ~/Library/Application Support/...), and I can see the "AudioGuide" folder in the root. So it's definitly there.
I am not that iOS guru and didn't really follow iOS7 updates. Has there been any changes made on how to access own assets in an app? How do I access my files?
Apple doc for - (NSURL *)URLForResource:(NSString *)name withExtension:(NSString *)extension subdirectory:(NSString *)subpath
Returns the file URL for the resource file identified by the specified
name and extension and residing in a given bundle directory.
what that means is you can get the file URL with specific type in a given subdirectory, so you should use this method call with your file name and extension.
If you are trying to read the list of files under that directory, what you can do is bundle all of your audio files in a single zip or gzipped file and you extract it in your Documents or Application Support directory when it is accessed for the very first time, then you can read it using the code below.
NSArray *directories = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
NSString *directory = [directories objectAtIndex:0];
NSString *audioDirectoryPath = [directory stringByAppendingPathComponent:#"AudioGuide"];
NSArray *audioFiles = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:audioDirectoryPath];
Hope this helps!

What is the basic file structure in an iOS application?

I'm trying to load a plist file in my application with
NSBundle* bundle = [NSBundle mainBundle];
NSString* plistPath = [bundle pathForResource:#"CategoryData" ofType:#"plist"];
categoryProps = [[NSArray alloc] initWithContentsOfFile:plistPath];
but the categoryProps array always ends up with 0 objects. I've placed the CategoryData.plist file under the "Supporting Files" dir in my project but I can't figure out how files are arranged in the compiled app.
Can someone point me to docs that describe how the file system of an app is laid out and how to figure out where files are located within the file system?
I forgot to point out that I am using XCode 4 which does not create a resources folder for the project
Your loading code code should work for locating the file within the file system. In a project, I have:
NSString *data = [[NSBundle mainBundle] pathForResource:#"data" ofType:#"plist"];
What I would do is log the plistPath to the console or inspect it in the debugger, then navigate to that location on disk and determine if the plist ends up where you think it does.
Also, locate your application bundle in /Users/<# Username #>/Library/Developer/Xcode/DerivedData/<# Unique Appname #>/Build/Products/Debug-iphonesimulator/<# Appname #>.app, right click on it and select "Show package Contents". Ensure that you see your plist where you think you should.
You need to place your plist file in the Resources folder. Then you will be able to load and use them like this
NSString *path = [[NSBundle mainBundle] bundlePath];
NSString *finalPath = [path stringByAppendingPathComponent:#"Info.plist"];
NSDictionary *plistData = [[NSDictionary dictionaryWithContentsOfFile:finalPath] retain];
UPD: In xcode4 you must to place plist files in the "Supporting Files" directory instead of "Resources". And try to use NSDictionary instead of NSArray

Resources