I'd like to log which Cocoapods and their related versions I'm using in a project but not sure how to do this. Is there a method available that I can use to write these values to a log file? I'm using Objective-C for this project but I can port from Swift if needed.
Here's how I did this. First, go to Build Phases -> Copy Bundle Resources and add the Podfile.lock (add other..)
Then I use this method to return the contents of the file:
-(NSString *)getPodfileLockContent
{
NSString* podfileLockContent = nil;
NSError* error;
NSURL* podfileLockURL = [[NSBundle mainBundle] URLForResource:#"Podfile" withExtension:#"lock"];
_podfileLockContent = [[NSString alloc] initWithContentsOfURL:podfileLockURL encoding:NSUTF8StringEncoding error:&error];
if (podfileLockContent) {
[NSLog(#"ERROR: failed to read Podfile.lock, make sure you have added it to the target in your project (this needs to be done manually at the moment). %#", error];
return nil;
}
}
return podfileLockContent;
}
This returns the full contents of the podfile.lock. You can just print this out or parse it for the values your require.
Related
I am using a read-only Core Data sqlite from the Main Bundle, works well. When i add a new version of the database (more read-only data) to the main bundle it still reads the "Old" version of the database.
Anyone that can help me understand why and what to do to get the new database version the current one when a current user download an update with the new version of the database?
This is part of trying to solve the problem in this post: Same problem when accessing updated database from documents directory
===SOLUTION====
I solved this by changing the name of the new database in the "new" main bundle and it works like a dream. Also, if this is an update i delete the old database in the documents directory to clean up.
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator != nil) {
return persistentStoreCoordinator;
}
//===READ DATABASE FROM MAIN BUNDLE===//
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *storeUrl = [[NSBundle mainBundle] URLForResource:kNewDB withExtension:#"sqlite"];
//=== IF THE OLD DATABASE STILL EXIST DELETE IT FROM DOCUMENT DIRECTORY ===//
NSURL *oldDatabasePathURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"database.sqlite"];
NSString *oldDatabasePath = [oldDatabasePathURL path];
if ([fileManager fileExistsAtPath:oldDatabasePath]) {
//Remove old database from Documents Directory
[fileManager removeItemAtURL:oldDatabasePathURL error:nil];
}
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];
NSError *error;
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]) {
// Update to handle the error appropriately.
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
exit(-1); // Fail
}
return persistentStoreCoordinator;
}
You must have a place in your code where you check to see if a copy of the database file exists in some writable directory (possibly your Documents directory) and if not, then you copy it there. This is a very common approach to take when you need to make changes to your database. The problem is, when you update your app, the file already exists, so it is never copied over again.
There are two approaches to take to fix your problem:
(Preferable): Don't copy the database in the first place. Since it is read only, you don't need to, and it just takes up extra space on the device. Simply open the database using the path of the file that is in the main bundle.
Instead of checking to see if a file exists in the writable directory, check to see if it is newer than the one in the main bundle. (not by using the date, since they could have installed the program and created the file after your update was submitted to the app store for approval, which would result in the new one not being copied over. You need to check the version of the database, possibly by storing another file in your app bundle which stores the version info, or determining it with version specific code). If not, then copy it over again.
PeterK, I was having the same issue when using the tutorial at http://www.raywenderlich.com/12170/core-data-tutorial-how-to-preloadimport-existing-data-updated to use a read-only sqlite database by Core Data. All was fine, until I had to update my database and re-release my target app. As you know, the proposed code in that tutorial only copies in the new database if no database exists in the Application's Documents directory.
I did not think that renaming my database (and updating the copying code) was a good design approach, so I got my design working by following Inafziger's preferred advise and reading up on iOS file structure. I provide the below only to show how to implement Inafziger's proposal. And of note is that this approach likely only works if your app does not change the contents of the Core Data information as it is read in as read-only.
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
// Updated processing to now just have the NRPersistentStoreCoordinator point to the sqlite db in the
// application's Bundle and not by copying that db to the app's Documents directory and then using
// the db in the Documents directory.
NSURL *refactoredStoreURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#“NameOfYourDatabase ofType:#"sqlite"]];
NSError *error = nil;
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
// Added to ensure the NSPersistentStoreCoordinator reads the Bundle's db file as read-only since
// it is not appropriate to allow the app to modify anything in the Bundle
NSDictionary *readOnlyOptions = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSReadOnlyPersistentStoreOption, nil];
// Use the URL that points to the Bundle's db file and used the ReadOnly options
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:refactoredStoreURL options:readOnlyOptions error:&error]) {
// Your logic if there is an error
}
return _persistentStoreCoordinator;
}
I hope this helps the next reader of this question.
I wish to retrieve all filenames from the root directory with the extension *.gs and store them in an array.
I tried using directoryContentsAtPath.. but it says that this method has been deprecated in ios5. Do you know any alternatives?
You should use NSFileManager's:
– contentsOfDirectoryAtPath:error:
(See Apple's documentation on NSFileManager.)
You will end up with something like:
NSString *path = #"your/path";
NSError *error = nil;
NSArray *files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:&error];
If you feel you don't need to check for a potential error, you may pass nil for the error argument. However, I would recommend that you check whether an error occurred and display an appropriate error message in that case. You could do it like so:
if (error) {
// display some error message here
} else {
// process filenames returned by NSFileManager
}
I am working on a Cocoa application which talks to a local SQLite database with FMDB. I ran into an issue that I can't do any insert or update operation on DB. Select queries run perfectly fine, so I would assume my db connection settings are correct.
The structure of my code is basically like this:
FMDatabase* db=[FMDatabase databaseWithPath:[[NSBundle mainBundle] pathForResource:#"DBName" ofType:#"sqlite"]];
if(![db open])
{
NSLog(#"Could not open db.");
}
db.traceExecution=YES;
[db beginTransation];
[db ExecuteUpdate:"INSERT INTO test (title) VALUES(?)", [NSNumber numberWithInt]:2],nil];
[db commit];
[db close];
No exceptions or warnings were thrown during execution, the console output regarding db.traceExecution is like following:
<FMDatabase: 0x100511fd0> executeUpdate: BEGIN EXCLUSIVE TRANSACTION;
<FMDatabase: 0x100511fd0> executeUpdate: INSERT INTO test (title) VALUES(?);
obj: 2
<FMDatabase: 0x100511fd0> executeUpdate: COMMIT TRANSACTION;
The testing database is simply just a one column table of INT type.
Everything looks fine except that the db file is not updated at all. It's really confusing to me as the Select query works perfectly fine. I checked the path of the database, it is pointing to the right one. First I suspect it's caused by file permission, but the issue remain the same even if I allowed everyone to be able to read/write.
I have been stucked with this problems for many hours and couldn't find a proper solution. Can anyone shed some light on this? Thanks!
Databases in the bundle are read only. If the file doesn't exist at the destination folder where you define, you should copy it from the bundle to the library or documents folder and then connect to that. That means it will copy on first use of that path.
Here's a function to 'prepare' the database by copying it to the destination from the bundle. It copies it to library (from my iOS app) but you can copy wherever you want. In my case, it was contacts.db.
I called this method from ensureOpened.
- (BOOL)ensureDatabasePrepared: (NSError **)error
{
// already prepared
if ((_dbPath != nil) &&
([[NSFileManager defaultManager] fileExistsAtPath:_dbPath]))
{
return YES;
}
// db in main bundle - cant edit. copy to library if !exist
NSString *dbTemplatePath = [[NSBundle mainBundle] pathForResource:#"contacts" ofType:#"db"];
NSLog(#"%#", dbTemplatePath);
NSString *libraryPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) lastObject];
_dbPath = [libraryPath stringByAppendingPathComponent:#"contacts.db"];
NSLog(#"dbPath: %#", _dbPath);
// copy db from template to library
if (![[NSFileManager defaultManager] fileExistsAtPath:_dbPath])
{
NSLog(#"db not exists");
NSError *error = nil;
if (![[NSFileManager defaultManager] copyItemAtPath:dbTemplatePath toPath:_dbPath error:&error])
{
return NO;
}
NSLog(#"copied");
}
return YES;
}
Are there any libraries that work in Objective C for zipping entire folders (and decompressing them)? I have looked at some of them by searching but they look like they require adding files individually and some of them supposedly crash...
It looks like this library might work:
http://bitbucket.org/dchest/osxzip/overview
I don't know if it supports folders, however. Anyone know if it does or have any other libraries that support zipping folders? Even sample code for interacting with the command line libz would be fine with me...
You could use NSTask to run the command line ditto program. Be sure to look at the ditto man page for the right combination of flags to get Finder-compatible zipping.
According to this example: http://www.raywenderlich.com/1948/how-integrate-itunes-file-sharing-with-your-ios-app you can get a NSData Object with the Zipped Data and then just write it with [data writeToFile....]
- (NSData *)exportToNSData {
NSError *error;
NSURL *url = [NSURL fileURLWithPath:_docPath];
NSFileWrapper *dirWrapper = [[[NSFileWrapper alloc] initWithURL:url options:0 error:&error] autorelease];
if (dirWrapper == nil) {
NSLog(#"Error creating directory wrapper: %#", error.localizedDescription);
return nil;
}
NSData *dirData = [dirWrapper serializedRepresentation];
NSData *gzData = [dirData gzipDeflate];
return gzData;
}
Is there anyway to do Files Handling in Objective-C? I am just trying to do simple read and write and can use 'c' but i am force to use Objective-C classes for that :#. I am looking into NSInputStream, but its going over my head. Is there any tutorial which explains how to use NSInputStream?
I had trouble with basic file i/o when I first hit it in Obj-C as well. I ended up using NSFileHandle to get C style access to my file. Here's a basic example:
// note: myFilename is an NSString containing the full path to the file
// create the file
NSFileManager *fManager = [[NSFileManager alloc] init];
if ([fManager createFileAtPath:myFilename contents:nil attributes:nil] != YES) {
NSLog(#"Failed to create file: %#", myFilename);
}
[fManager release]; fManager = nil;
// open the file for updating
NSFileHandle *myFile = [NSFileHandle fileHandleForUpdatingAtPath:myFilename];
if (myFile == nil) {
NSLog(#"Failed to open file for updating: %#", myFilename);
}
// truncate the file so it is guaranteed to be empty
[myFile truncateFileAtOffset:0];
// note: rawData is an NSData object
// write data to a file
[myFile writeData:rawData];
// close the file handle
[myFile closeFile]; myFile = nil;
If all you need to do is really simple I/O, you can just tell an object to initialize itself from, or write itself to, a filesystem path or URL. This works with several Foundation classes, including NSString, NSData, NSArray, and NSDictionary among others.
Try starting out by looking at the following two NSString methods:
- initWithContentsOfFile:encoding:error:
- writeToFile:atomically:encoding:error:
I find apple's guides short and to the point.
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Streams/Articles/ReadingInputStreams.html