Singleton in static library in iOS - ios

I have a static library which contains a Singleton class (FMDB SQLite Data Access), now I open from my main application the connection and do thingss... this works, after that a method in my library want to call the a method on my singleton and I get the error that
-[FMDatabase executeQuery:withArgumentsInArray:]: message sent to deallocated instance 0xa443960
is this not possible what I'm trying to achieve?
this is short version of my singleton
static MySingleton* _sharedMySingleton = nil;
FMDatabase *database;
#ifndef __clang_analyzer__
+(MySingleton*)sharedMySingleton
{
#synchronized([MySingleton class])
{
if (!_sharedMySingleton)
[[self alloc] init];
return _sharedMySingleton;
}
}
#endif
+(id)alloc
{
#synchronized([MySingleton class])
{
NSAssert(_sharedMySingleton == nil, #"Attempted to allocate a second instance of a singleton.");
_sharedMySingleton = [super alloc];
return _sharedMySingleton;
}
}
-(Resource *)getResourceForName:(NSString *)name
{
NSString *select = #"SELECT Data, MimeType FROM File WHERE FileName = ? LIMIT 1";
NSArray *arguments = [NSArray arrayWithObject:[NSString stringWithFormat:#"/%#", name]];
FMResultSet *s = [database executeQuery:select withArgumentsInArray:arguments];
if (s == NULL)
{
FuncFileLog(#"getResourceForName file cant be loaded: %#", [database lastErrorMessage]);
return nil;
}
NSData *data = nil;
NSString *mimeType;
while ([s next])
{
data = [NSData dataFromBase64String:[s stringForColumnIndex:0]];
mimeType = [s stringForColumnIndex:1];
}
Resource *resource = [[[Resource alloc] initWithData:data mimeType:mimeType] autorelease];
return resource;
}
-(BOOL)openDatabase
{
database = [FMDatabase databaseWithPath:[self getDocumentResourcePath]];
return [database open];
}
-(void)closeDatabase
{
[database close];
[database release];
}
-(void)dealloc
{
if (database != NULL)
{
[self closeDatabase];
}
[baseUrl release];
[super dealloc];
}
#end
EDIT:
I found that the dealloc from FMDatabase gets called after my application start return, but dont know why.
EDIT2:
Currently I thought one problem was this line
database = [FMDatabase databaseWithPath:[self getDocumentResourcePath]];
here I have to retain the object.

You don't actually assign the singleton instance:
if (!_sharedMySingleton)
[[self alloc] init];
should be:
if (!_sharedMySingleton)
_sharedMySingleton = [[self alloc] init];
and dump that overridden alloc method.
Also database should be an instance variable in the class, and not at global scope.

Related

use the autorelease to release,the app will crash

I write an app (using no-arc)named Album which as the iPhone's native "Photo".
My Question:
1.
(please look the attached file name:1)when clicking the button of "+",then inputing some string and clicking the button of "save",the app will crash.But if change the code from "NSMutableArray *albumArr = [[[NSMutableArray alloc] init] autorelease];" to "NSMutableArray *albumArr = [[NSMutableArray alloc] init]", the app can work fine.But I think I should use the autorelease to release.
The related code:
// AlbumDB.m
+ (NSMutableArray *)fetchAlbumData
{
#warning why autorelease crash?
NSMutableArray *albumArr = [[[NSMutableArray alloc] init] autorelease];
FMDatabase *db = [FMDatabase databaseWithPath:[self dataBasePath]];
if ([db open]) {
NSString *sqlSelect = #"SELECT * FROM ALBUM";
FMResultSet *result = [db executeQuery:sqlSelect];
while ([result next]) {
AlbumModel *albumModel = [[AlbumModel alloc] init];
albumModel.albumid = [result intForColumn:#"albumid"];
albumModel.albumName = [result stringForColumn:#"albumName"];
[albumArr addObject:albumModel];
[albumModel release];
}
[db close];
}
return albumArr;
}
(please look the attached file name:2)when analyzing the code,I find the potential leak of an object.But in the dealloc,I had released.Why happen?
The related code:
//MainViewController.h
#property (nonatomic, retain) AlbumModel *editingAlbum;
// MainViewController.m
- (void)dealloc
{
[_albumArr release], _albumArr = nil;
self.editingAlbum = nil;
self.detailViewController = nil;
[super dealloc];
}
I think you should learn more about mrc.
In your first case, the albumArr if it is autorelease , it means when the runloop end ,it will be release, so the _albumArr will be nil when you use, you must retain it ,when you set the value to _albumArr.
In the second case, self.editingAlbum = [[AlbumModel alloc] init]; It will casuse the editingAlbum retain cout ==2 .You must change the code to like this:
AlbumModel *temp = [[AlbumModel alloc] init];
self.editingAlbum = temp;
[temp release];

Core Data NSPersistentStoreCoordinator's +metadataForPersistentStoreOfType:URL:error: sometimes returns nil

I have a method that progressively migrates a core data sqlite store though multiple NSManagedObjectModel versions until the store is at a the current version. The method is inspired by the code in Marcus Zarra's Core Data book.
The app is in production but my method is failing in about 0.5% of cases. When it fails it returns NO and an error is logged using Crashlytics:
NSSQLiteErrorDomain = 14; NSUnderlyingException = "I/O error for database at <store url>. SQLite error code:14, 'unable to open database file'"
The sqlite store use's write-ahead logging (WAL) and I am able to sometimes get the same error if I call +metadataForPersistentStoreOfType:URL:error: after first manually deleting the sqlite-WAL file.
Progressive Migration Code:
- (BOOL)progressivelyMigrateURL:(NSURL*)sourceStoreURL
toModel:(NSManagedObjectModel*)finalModel
error:(NSError**)error
{
NSURL *storeDirectoryURL = [sourceStoreURL URLByDeletingLastPathComponent];
NSString *storeExtension = [sourceStoreURL pathExtension];
NSDictionary *sourceMetadata = [NSPersistentStoreCoordinator
metadataForPersistentStoreOfType:NSSQLiteStoreType
URL:sourceStoreURL
error:error];
if (!sourceMetadata) return NO;
while (![finalModel isConfiguration:nil
compatibleWithStoreMetadata:sourceMetadata]) {
NSManagedObjectModel *sourceModel =
[self managedObjectModelForMetadata:sourceMetadata];
if (!sourceModel) return NO;
NSString *modelName = nil;
NSManagedObjectModel *targetModel =
[self suitableTargetModelForMigrationFromSourceModel:sourceModel
modelName:&modelName];
if (!targetModel) return NO;
NSMigrationManager *manager =
[[NSMigrationManager alloc] initWithSourceModel:sourceModel
destinationModel:targetModel];
NSMappingModel *mappingModel =
[NSMappingModel mappingModelFromBundles:nil
forSourceModel:sourceModel
destinationModel:targetModel];
NSURL *destinationStoreURL =
[[storeDirectoryURL URLByAppendingPathComponent:modelName]
URLByAppendingPathExtension:storeExtension];
BOOL migrated = [manager migrateStoreFromURL:sourceStoreURL
type:NSSQLiteStoreType
options:nil
withMappingModel:mappingModel
toDestinationURL:destinationStoreURL
destinationType:NSSQLiteStoreType
destinationOptions:nil
error:error];
if (!migrated) return NO;
NSString *sourceModelName =
[self versionStringForManagedObjectModel:sourceModel];
NSURL *backUpURL = [self backupURLWithDirectoryURL:storeDirectoryURL
pathExtension:storeExtension
modelName:sourceModelName];
BOOL replaced = [self replaceStoreAtURL:sourceStoreURL
withStoreAtURL:destinationStoreURL
backupURL:backUpURL
error:error];
if (replaced == NO) return NO;
sourceMetadata = [NSPersistentStoreCoordinator
metadataForPersistentStoreOfType:NSSQLiteStoreType
URL:sourceStoreURL
error:error];
if (!sourceMetadata) return NO;
}
return YES;
}
- (NSManagedObjectModel *)managedObjectModelForMetadata:(NSDictionary *)metadata
{
for (NSURL *URL in [self modelURLs]) {
NSManagedObjectModel *model =
[[NSManagedObjectModel alloc] initWithContentsOfURL:URL];
if ([model isConfiguration:nil compatibleWithStoreMetadata:metadata]) {
return model;
}
}
return nil;
}
- (NSManagedObjectModel *)suitableTargetModelForMigrationFromSourceModel:(NSManagedObjectModel *)sourceModel
modelName:(NSString **)modelName
{
for (NSURL *modelURL in [self modelURLs]) {
NSManagedObjectModel *targetModel =
[[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
NSMappingModel *mappingModel =
[NSMappingModel mappingModelFromBundles:nil
forSourceModel:sourceModel
destinationModel:targetModel];
if (mappingModel) {
*modelName = [[modelURL lastPathComponent] stringByDeletingPathExtension];
return targetModel;
}
}
return nil;
}
- (NSArray *)modelURLs
{
NSMutableArray *modelURLs =
[[[NSBundle mainBundle] URLsForResourcesWithExtension:#"mom"
subdirectory:nil] mutableCopy];
NSArray *momdURLs =
[[[NSBundle mainBundle] URLsForResourcesWithExtension:#"momd"
subdirectory:nil] mutableCopy];
for (NSURL *momdURL in momdURLs) {
NSString *directory = [momdURL lastPathComponent];
NSArray *array =
[[NSBundle mainBundle] URLsForResourcesWithExtension:#"mom"
subdirectory:directory];
[modelURLs addObjectsFromArray:array];
}
return [modelURLs copy];
}
- (NSURL *)backupURLWithDirectoryURL:(NSURL *)URL
pathExtension:(NSString *)extension
modelName:(NSString *)name
{
NSString *GUID = [[NSProcessInfo processInfo] globallyUniqueString];
NSString *pathComponant = [NSString stringWithFormat:#"%#-%#", GUID, name];
return [[URL URLByAppendingPathComponent:pathComponant]
URLByAppendingPathExtension:extension];
}
- (BOOL)replaceStoreAtURL:(NSURL *)originalStoreURL
withStoreAtURL:(NSURL *)newStoreURL
backupURL:(NSURL *)backupURL
error:(NSError **)error
{
BOOL storeMoved = [self moveStoreAtURL:originalStoreURL
toURL:backupURL
error:error];
if (!storeMoved) return NO;
storeMoved = [self moveStoreAtURL:newStoreURL
toURL:originalStoreURL
error:error];
if (!storeMoved) return NO;
return YES;
}
- (BOOL)moveStoreAtURL:(NSURL *)sourceURL
toURL:(NSURL *)targetURL
error:(NSError **)error
{
NSMutableArray *sourceURLs = [#[sourceURL] mutableCopy];
NSMutableArray *targetURLs = [#[targetURL] mutableCopy];
NSString *walExtension = #"sqlite-wal";
if ([self storeAtURL:sourceURL hasAccessoryFileWithExtension:walExtension]) {
[sourceURLs addObject:[self URLByReplacingExtensionOfURL:sourceURL
withExtension:walExtension]];
[targetURLs addObject:[self URLByReplacingExtensionOfURL:targetURL
withExtension:walExtension]];
}
NSString *shmExtension = #"sqlite-shm";
if ([self storeAtURL:sourceURL hasAccessoryFileWithExtension:shmExtension]) {
[sourceURLs addObject:[self URLByReplacingExtensionOfURL:sourceURL
withExtension:shmExtension]];
[targetURLs addObject:[self URLByReplacingExtensionOfURL:targetURL
withExtension:shmExtension]];
}
NSFileManager *fileManager = [NSFileManager defaultManager];
for (int i = 0; i < [sourceURLs count]; i++) {
BOOL fileMoved = [fileManager moveItemAtURL:sourceURLs[i]
toURL:targetURLs[i]
error:error];
if (!fileMoved) return NO;
}
return YES;
}
- (BOOL)storeAtURL:(NSURL *)URL hasAccessoryFileWithExtension:(NSString *)extension
{
NSURL *accessoryURL = [self URLByReplacingExtensionOfURL:URL
withExtension:extension];
return [[NSFileManager defaultManager] fileExistsAtPath:[accessoryURL path]];
}
- (NSURL *)URLByReplacingExtensionOfURL:(NSURL *)URL withExtension:(NSString *)extension
{
return [[URL URLByDeletingPathExtension] URLByAppendingPathExtension:extension];
}
- (NSString *)versionStringForManagedObjectModel:(NSManagedObjectModel *)model
{
NSString *string = #"";
for (NSString *identifier in model.versionIdentifiers) {
string = [string stringByAppendingString:identifier];
}
return string;
}
Sorry for the super long code.
The likely cause is your moveStoreAtURL:toURL:error: method. The error you're getting is mentioned in Apple's docs as being the result of failing to copy all of a persistent store's files. It looks like you're trying to hit all of them, but either (a) there's a bug in the copy code that I can't find right now or (b) the store is "live" in your app, being used by a persistent store coordinator, and so you're not getting a consistent state from the copy.
You might be able to fix it with some debugging, and if you ensured that the store was not in use. It would be better and probably more reliable to change the journal mode so that you don't have wal and shm files (which that link also describes). Even better, if your store files aren't too huge, use migratePersistentStore:toURL:options:withType:error to have Core Data make the copy. That should be pretty much guaranteed to work, though in some cases it can use too much memory.
I'm using NSMigrationManager, so I can't use NSPersistentStoreCoordinator's - migratePersistentStore..., so my solution was to force a checkpoint operation:
- (void)performCheckpointStoreWithSourceModel:(NSManagedObjectModel *)sourceModel sourceStoreURL:(NSURL *)sourceStoreURL {
NSPersistentStoreCoordinator *tempPSC = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:sourceModel];
[tempPSC addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:sourceStoreURL options:#{NSSQLitePragmasOption: #{#"journal_mode": #"DELETE"}} error:nil];
[tempPSC removePersistentStore:[tempPSC persistentStoreForURL:sourceStoreURL] error:nil];
}
...before performing migration with NSMigrationManager:
if (![manager migrateStoreFromURL:sourceStoreURL
type:type
options:nil
withMappingModel:mappingModel
toDestinationURL:destinationStoreURL
destinationType:type
destinationOptions:nil
error:error]) {
return NO;
}

Loading csv file in Core Data

I am trying to load a csv file in core data when the application is ran for the first time. On another post on stackoverflow found here (What is the fastest way to load a large CSV file into core data), I found out how to do that.
I am using the same code form the provided function: populateDB, in my controller and calling the function if the data has never been loaded before (first run). However, xcode is giving me an error:
No visible #interface for ...Controller declares the selector persistentStoreCoordinator.
The function is:
-(void)populateDB{
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
NSManagedObjectContext *context;
if (coordinator != nil) {
context = [[NSManagedObjectContext alloc] init];
[context setPersistentStoreCoordinator:coordinator];
}
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"input" ofType:#"txt"];
if (filePath) {
NSString * myText = [[NSString alloc]
initWithContentsOfFile:filePath
encoding:NSUTF8StringEncoding
error:nil];
if (myText) {
__block int count = 0;
[myText enumerateLinesUsingBlock:^(NSString * line, BOOL * stop) {
line=[line stringByReplacingOccurrencesOfString:#"\t" withString:#" "];
NSArray *lineComponents=[line componentsSeparatedByString:#" "];
if(lineComponents){
if([lineComponents count]==3){
float f=[[lineComponents objectAtIndex:0] floatValue];
NSNumber *number=[NSNumber numberWithFloat:f];
NSString *string1=[lineComponents objectAtIndex:1];
NSString *string2=[lineComponents objectAtIndex:2];
NSManagedObject *object=[NSEntityDescription insertNewObjectForEntityForName:#"Bigram" inManagedObjectContext:context];
[object setValue:number forKey:#"number"];
[object setValue:string1 forKey:#"string1"];
[object setValue:string2 forKey:#"string2"];
NSError *error;
count++;
if(count>=1000){
if (![context save:&error]) {
NSLog(#"Whoops, couldn't save: %#", [error localizedDescription]);
}
count=0;
}
}
}
}];
NSLog(#"done importing");
NSError *error;
if (![context save:&error]) {
NSLog(#"Whoops, couldn't save: %#", [error localizedDescription]);
}
}
}
}
I am picking up iOS again after 3 years of absence and I have never dived into this part of the SDK before. I would greatly appreciate any help with this issue...
The code below shows you an example to load csv file in Core Data using the class CSVParser.hof Matt Gallagher and supposing an entity MyEntity
// CSV File input.csv and not input.txt separate by space #" "
CSVParser *csvParser = [[CSVParser alloc] initWithContentOfFile:[NSBundle mainBundle] pathForResource:#"input" ofType:#"csv" separator:#" "];
// Array with all your data from CSV
NSArray *data = [csvParser parseFile];
// Your entity from Core Data
MyEntity *myEntity = nil;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
for (NSDictionary *dic in data)
{
fetchRequest.entity = [NSEntityDescription entityForName:#"MyEntity" inManagedObjectContext:context];
if (!entity)
entity = [NSEntityDescription insertNewObjectForEntityForName:#"MyEntity"
inManagedObjectContext:context];
[entity setValue:number forKey:#"number"];
[entity setValue:string1 forKey:#"string1"];
[entity setValue:string2 forKey:#"string2"];
}
// Save the context
[managedObjectContext save:nil];
CVSParser.h using ARC :
//
// CSVParser.h
// CSVImporter
//
// Created by Matt Gallagher on 2009/11/30.
// Copyright 2009 Matt Gallagher. All rights reserved.
//
// Permission is given to use this source code file, free of charge, in any
// project, commercial or otherwise, entirely at your risk, with the condition
// that any redistribution (in part or whole) of source code must retain
// this copyright and permission notice. Attribution in compiled projects is
// appreciated but not required.
//
// Source : http://cocoawithlove.com/2009/11/writing-parser-using-nsscanner-csv.html
#interface CSVParser : NSObject
{
NSString *csvString;
NSString *separator;
NSScanner *scanner;
BOOL hasHeader;
NSMutableArray *fieldNames;
id receiver;
SEL receiverSelector;
NSCharacterSet *endTextCharacterSet;
BOOL separatorIsSingleChar;
}
- (id)initWithString:(NSString *)aCSVString
separator:(NSString *)aSeparatorString;
- (id)initWithContentOfFile:(NSString *)aPath
separator:(NSString *)aSeparatorString;
- (id)initWithString:(NSString *)aCSVString
separator:(NSString *)aSeparatorString
hasHeader:(BOOL)header
fieldNames:(NSArray *)names;
- (id)initWithContentOfFile:(NSString *)aPath
separator:(NSString *)aSeparatorString
hasHeader:(BOOL)header
fieldNames:(NSArray *)names;
- (NSArray *)arrayOfParsedRows;
- (void)parseRowsForReceiver:(id)aReceiver selector:(SEL)aSelector;
- (NSArray *)parseFile;
- (NSMutableArray *)parseHeader;
- (NSDictionary *)parseRecord;
- (NSString *)parseName;
- (NSString *)parseField;
- (NSString *)parseEscaped;
- (NSString *)parseNonEscaped;
- (NSString *)parseDoubleQuote;
- (NSString *)parseSeparator;
- (NSString *)parseLineSeparator;
- (NSString *)parseTwoDoubleQuotes;
- (NSString *)parseTextData;
#end
CVSParser.m using ARC :
//
// CSVParser.m
// CSVImporter
//
// Created by Matt Gallagher on 2009/11/30.
// Copyright 2009 Matt Gallagher. All rights reserved.
//
// Permission is given to use this source code file, free of charge, in any
// project, commercial or otherwise, entirely at your risk, with the condition
// that any redistribution (in part or whole) of source code must retain
// this copyright and permission notice. Attribution in compiled projects is
// appreciated but not required.
//
#import "CSVParser.h"
#implementation CSVParser
//
// initWithString:separator:hasHeader:fieldNames:
//
// Parameters:
// aCSVString - the string that will be parsed
// aSeparatorString - the separator (normally "," or "\t")
// header - if YES, treats the first row as a list of field names
// names - a list of field names (will have no effect if header is YES)
//
// returns the initialized object (nil on failure)
//
- (id)initWithString:(NSString *)aCSVString
separator:(NSString *)aSeparatorString
hasHeader:(BOOL)header
fieldNames:(NSArray *)names
{
self = [super init];
if (self)
{
csvString = [aCSVString retain];
separator = [aSeparatorString retain];
NSAssert([separator length] > 0 &&
[separator rangeOfString:#"\""].location == NSNotFound &&
[separator rangeOfCharacterFromSet:[NSCharacterSet newlineCharacterSet]].location == NSNotFound,
#"CSV separator string must not be empty and must not contain the double quote character or newline characters.");
NSMutableCharacterSet *endTextMutableCharacterSet =
[[NSCharacterSet newlineCharacterSet] mutableCopy];
[endTextMutableCharacterSet addCharactersInString:#"\""];
[endTextMutableCharacterSet addCharactersInString:[separator substringToIndex:1]];
endTextCharacterSet = endTextMutableCharacterSet;
if ([separator length] == 1)
{
separatorIsSingleChar = YES;
}
hasHeader = header;
fieldNames = [names mutableCopy];
}
return self;
}
- (id)initWithString:(NSString *)aCSVString
separator:(NSString *)aSeparatorString
{
return [self initWithString:aCSVString
separator:aSeparatorString
hasHeader:YES
fieldNames:nil];
}
- (id)initWithContentOfFile:(NSString *)aPath
separator:(NSString *)aSeparatorString
{
return [self initWithString:[NSString stringWithContentsOfFile:aPath
encoding:NSUTF8StringEncoding
error:nil]
separator:aSeparatorString];
}
- (id)initWithContentOfFile:(NSString *)aPath
separator:(NSString *)aSeparatorString
hasHeader:(BOOL)header
fieldNames:(NSArray *)names
{
return [self initWithString:[NSString stringWithContentsOfFile:aPath
encoding:NSUTF8StringEncoding
error:nil]
separator:aSeparatorString
hasHeader:header
fieldNames:names];
}
//
// dealloc
//
// Releases instance memory.
//
- (void)dealloc
{
[csvString release];
[separator release];
[fieldNames release];
[endTextCharacterSet release];
[super dealloc];
}
//
// arrayOfParsedRows
//
// Performs a parsing of the csvString, returning the entire result.
//
// returns the array of all parsed row records
//
- (NSArray *)arrayOfParsedRows
{
scanner = [[NSScanner alloc] initWithString:csvString];
[scanner setCharactersToBeSkipped:[[[NSCharacterSet alloc] init] autorelease]];
NSArray *result = [self parseFile];
[scanner release];
scanner = nil;
return result;
}
//
// parseRowsForReceiver:selector:
//
// Performs a parsing of the csvString, sending the entries, 1 row at a time,
// to the receiver.
//
// Parameters:
// aReceiver - the target that will receive each row as it is parsed
// aSelector - the selector that will receive each row as it is parsed
// (should be a method that takes a single NSDictionary argument)
//
- (void)parseRowsForReceiver:(id)aReceiver selector:(SEL)aSelector
{
scanner = [[NSScanner alloc] initWithString:csvString];
[scanner setCharactersToBeSkipped:[[[NSCharacterSet alloc] init] autorelease]];
receiver = [aReceiver retain];
receiverSelector = aSelector;
[self parseFile];
[scanner release];
scanner = nil;
[receiver release];
receiver = nil;
}
//
// parseFile
//
// Attempts to parse a file from the current scan location.
//
// returns the parsed results if successful and receiver is nil, otherwise
// returns nil when done or on failure.
//
- (NSArray *)parseFile
{
scanner = [[NSScanner alloc] initWithString:csvString];
[scanner setCharactersToBeSkipped:[[[NSCharacterSet alloc] init] autorelease]];
if (hasHeader)
{
if (fieldNames)
{
[fieldNames release];
}
fieldNames = [[self parseHeader] retain];
if (!fieldNames || ![self parseLineSeparator])
{
return nil;
}
}
NSMutableArray *records = nil;
if (!receiver)
{
records = [NSMutableArray array];
}
NSDictionary *record = [[self parseRecord] retain];
if (!record)
{
return nil;
}
while (record)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
if (receiver)
{
[receiver performSelector:receiverSelector withObject:record];
}
else
{
[records addObject:record];
}
[record release];
if (![self parseLineSeparator])
{
break;
}
record = [[self parseRecord] retain];
[pool drain];
}
[scanner release];
scanner = nil;
return records;
}
//
// parseHeader
//
// Attempts to parse a header row from the current scan location.
//
// returns the array of parsed field names or nil on parse failure.
//
- (NSMutableArray *)parseHeader
{
NSString *name = [self parseName];
if (!name)
{
return nil;
}
NSMutableArray *names = [NSMutableArray array];
while (name)
{
[names addObject:name];
if (![self parseSeparator])
{
break;
}
name = [self parseName];
}
return names;
}
//
// parseRecord
//
// Attempts to parse a record from the current scan location. The record
// dictionary will use the fieldNames as keys, or FIELD_X for each column
// X-1 if no fieldName exists for a given column.
//
// returns the parsed record as a dictionary, or nil on failure.
//
- (NSDictionary *)parseRecord
{
//
// Special case: return nil if the line is blank. Without this special case,
// it would parse as a single blank field.
//
if ([self parseLineSeparator] || [scanner isAtEnd])
{
return nil;
}
NSString *field = [self parseField];
if (!field)
{
return nil;
}
NSInteger fieldNamesCount = [fieldNames count];
NSInteger fieldCount = 0;
NSMutableDictionary *record =
[NSMutableDictionary dictionaryWithCapacity:[fieldNames count]];
while (field)
{
NSString *fieldName;
if (fieldNamesCount > fieldCount)
{
fieldName = [fieldNames objectAtIndex:fieldCount];
}
else
{
fieldName = [NSString stringWithFormat:#"FIELD_%d", fieldCount + 1];
[fieldNames addObject:fieldName];
fieldNamesCount++;
}
[record setObject:field forKey:fieldName];
fieldCount++;
if (![self parseSeparator])
{
break;
}
field = [self parseField];
}
return record;
}
//
// parseName
//
// Attempts to parse a name from the current scan location.
//
// returns the name or nil.
//
- (NSString *)parseName
{
return [self parseField];
}
//
// parseField
//
// Attempts to parse a field from the current scan location.
//
// returns the field or nil
//
- (NSString *)parseField
{
NSString *escapedString = [self parseEscaped];
if (escapedString)
{
return escapedString;
}
NSString *nonEscapedString = [self parseNonEscaped];
if (nonEscapedString)
{
return nonEscapedString;
}
//
// Special case: if the current location is immediately
// followed by a separator, then the field is a valid, empty string.
//
NSInteger currentLocation = [scanner scanLocation];
if ([self parseSeparator] || [self parseLineSeparator] || [scanner isAtEnd])
{
[scanner setScanLocation:currentLocation];
return #"";
}
return nil;
}
//
// parseEscaped
//
// Attempts to parse an escaped field value from the current scan location.
//
// returns the field value or nil.
//
- (NSString *)parseEscaped
{
if (![self parseDoubleQuote])
{
return nil;
}
NSString *accumulatedData = [NSString string];
while (YES)
{
NSString *fragment = [self parseTextData];
if (!fragment)
{
fragment = [self parseSeparator];
if (!fragment)
{
fragment = [self parseLineSeparator];
if (!fragment)
{
if ([self parseTwoDoubleQuotes])
{
fragment = #"\"";
}
else
{
break;
}
}
}
}
accumulatedData = [accumulatedData stringByAppendingString:fragment];
}
if (![self parseDoubleQuote])
{
return nil;
}
return accumulatedData;
}
//
// parseNonEscaped
//
// Attempts to parse a non-escaped field value from the current scan location.
//
// returns the field value or nil.
//
- (NSString *)parseNonEscaped
{
return [self parseTextData];
}
//
// parseTwoDoubleQuotes
//
// Attempts to parse two double quotes from the current scan location.
//
// returns a string containing two double quotes or nil.
//
- (NSString *)parseTwoDoubleQuotes
{
if ([scanner scanString:#"\"\"" intoString:NULL])
{
return #"\"\"";
}
return nil;
}
//
// parseDoubleQuote
//
// Attempts to parse a double quote from the current scan location.
//
// returns #"\"" or nil.
//
- (NSString *)parseDoubleQuote
{
if ([scanner scanString:#"\"" intoString:NULL])
{
return #"\"";
}
return nil;
}
//
// parseSeparator
//
// Attempts to parse the separator string from the current scan location.
//
// returns the separator string or nil.
//
- (NSString *)parseSeparator
{
if ([scanner scanString:separator intoString:NULL])
{
return separator;
}
return nil;
}
//
// parseLineSeparator
//
// Attempts to parse newline characters from the current scan location.
//
// returns a string containing one or more newline characters or nil.
//
- (NSString *)parseLineSeparator
{
NSString *matchedNewlines = nil;
[scanner
scanCharactersFromSet:[NSCharacterSet newlineCharacterSet]
intoString:&matchedNewlines];
return matchedNewlines;
}
//
// parseTextData
//
// Attempts to parse text data from the current scan location.
//
// returns a non-zero length string or nil.
//
- (NSString *)parseTextData
{
NSString *accumulatedData = [NSString string];
while (YES)
{
NSString *fragment;
if ([scanner scanUpToCharactersFromSet:endTextCharacterSet intoString:&fragment])
{
accumulatedData = [accumulatedData stringByAppendingString:fragment];
}
//
// If the separator is just a single character (common case) then
// we know we've reached the end of parseable text
//
if (separatorIsSingleChar)
{
break;
}
//
// Otherwise, we need to consider the case where the first character
// of the separator is matched but we don't have the full separator.
//
NSUInteger location = [scanner scanLocation];
NSString *firstCharOfSeparator;
if ([scanner scanString:[separator substringToIndex:1] intoString:&firstCharOfSeparator])
{
if ([scanner scanString:[separator substringFromIndex:1] intoString:NULL])
{
[scanner setScanLocation:location];
break;
}
//
// We have the first char of the separator but not the whole
// separator, so just append the char and continue
//
accumulatedData = [accumulatedData stringByAppendingString:firstCharOfSeparator];
continue;
}
else
{
break;
}
}
if ([accumulatedData length] > 0)
{
return accumulatedData;
}
return nil;
}
#end
Thanks for everyone's assistance. I found the answer on stackoverflow, a 2-3 years old forum (Adding Core Data to existing iPhone project)...
So the issue it seems is that when I first created the project I didn't request using core data and only did that later on. Following the post I posted above:
Add the following to supporting files/projectName-Prefix.pch
#import <CoreData/CoreData.h>
Once I did, the persistenceCoordinator error disappeared...
WOW, big lesson learned there...
-(void)populateDB {
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
NSManagedObjectContext *context;
[....]
}
The Problem might be [self persistentStoreCoordinator]... Do you have a function called "persistentStoreCoordinator" ? If not, you have to write the function.
[EDIT]
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
#synchronized (self)
{
if (__persistentStoreCoordinator != nil)
return __persistentStoreCoordinator;
NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:#"myProject" ofType:#"sqlite"];
NSString *storePath = [[[self applicationDocumentsDirectory] path] stringByAppendingPathComponent: #"myProject.sqlite"];
NSError *error;
if (![[NSFileManager defaultManager] fileExistsAtPath:storePath])
{
if ([[NSFileManager defaultManager] copyItemAtPath:defaultStorePath toPath:storePath error:&error])
NSLog(#"Copied starting data to %#", storePath);
else
NSLog(#"Error copying default DB to %# (%#)", storePath, error);
}
NSURL *storeURL = [NSURL fileURLWithPath:storePath];
__persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return __persistentStoreCoordinator;
}
}
Is this Code in another File ? Maybe you forgot to import the .h-file, where persistentStoreCoordinator is declared in.

Singeleton - error: [CFString isNSString__] message sent to deallocated instance

I have an NSMutableArray in a singleton, which I want to access in two classes. I've done this in another project exactly like this (that one had ARC, this one doesn't) and it worked there.
Project doesn't have ARC on.
I'm getting the error:
*** -[CFString isNSString__]: message sent to deallocated instance 0xb3d1db0
StoreVars.h
#interface StoreVars : NSObject
#property (nonatomic, retain) NSMutableArray *sharedArrayOfVideo;
+ (StoreVars *)sharedInstance;
#end
StoreVars.m
#implementation StoreVars
#synthesize sharedArrayOfVideo;
+ (StoreVars *) sharedInstance {
static StoreVars *myInstance = nil;
if (myInstance == nil) {
myInstance = [[[[self class] alloc] init] retain];
myInstance.sharedArrayOfVideo = [[NSMutableArray alloc] init];
}
return myInstance;
}
#end
Populating the array asynchronously:
NSDictionary *tempDict = [[NSDictionary alloc] initWithObjectsAndKeys:
ID,#"id",
title,#"title", nil];
[[StoreVars sharedInstance].sharedArrayOfVideo addObject:tempDict];
This is where crash happens:
NSLog(#"%i",[[StoreVars sharedInstance].sharedArrayOfVideo count]);
NSLog(#"%#",[StoreVars sharedInstance]);
if ([[StoreVars sharedInstance] respondsToSelector:#selector(sharedArrayOfVideo)]) {
**NSLog(#"%#",[StoreVars sharedInstance].sharedArrayOfVideo);**
//NSLog(#"%#",[[StoreVars sharedInstance].sharedArrayOfVideo objectAtIndex:8]);
}
Output:
10
<StoreVars: 0xb381b00>
*** -[CFString isNSString__]: message sent to deallocated instance 0xb3d1db0
Found the problem, when creating the dictionary, I did:
NSString *ID = [[[arrayOfEntry objectAtIndex:index] objectForKey:#"id"]; autorelease]
NSString *title = [[[arrayOfEntry objectAtIndex:index] objectForKey:#"title"] autorelease];
Instead of:
NSString *ID = [[arrayOfEntry objectAtIndex:index] objectForKey:#"id"];
NSString *title = [[arrayOfEntry objectAtIndex:index] objectForKey:#"title"];
NSDictionary *tempDict = [NSDictionary dictionaryWithObjectsAndKeys:ID,#"id",title,#"title", nil];
Try to create singleton with gcd like this:
static ASBTLEManager *sharedInstance = nil;
+ (ASBTLEManager *)sharedManager
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[ASBTLEManager alloc] initInstance];
});
return sharedInstance;
}
try this way to create singleton instance, this is more accurate than what you are trying
+(StoreVars *) sharedInstance
{
static StoreVars * myInstance = nil;
static dispatch_once_t oneTimePredicate;
//get calls only once.
dispatch_once(&oneTimePredicate, ^{
myInstance = [[self alloc] init];
myInstance.sharedArrayOfVideo = [[NSMutableArray alloc] init];
});
return myInstance;
}
I have a question with regards to the line below in your code:
if ([[StoreVars sharedInstance] respondsToSelector:#selector(sharedArrayOfVideo)])
Q. Why have you tried to check the mutableArray as method via selector ?
If you want to iterate through the added dictionaries do the following
StoreVars *storeVars = [StoreVars sharedInstance];
if(storeVars.sharedArrayOfVideo.count>0)
{
for(int i=0; i<storeVars.sharedArrayOfVideo.count; i++)
{
NSDictionary *dictionary = [storeVars.sharedArrayOfVideo objectAtIndex:i];
// do stuff with the grabbed dictionary.
}
}
else { NSLog(#"sharedArrayOfVideo is empty"); }
Further in your singleton creation code perform the following edit:
Instead of following:
if (myInstance == nil) {
myInstance = [[[[self class] alloc] init] retain];
Use the following:
if (myInstance == nil) {
myInstance = [[StoreVars alloc] init];
// you already own the above object via alloc/init, so no extra retains.

accessing data from s3 using xcode

I am not quite sure how to download data from S3 with XCode. Any help on how to do this would be greatly appreciated. I have tried the following code to access an image from S3,
AmazonCredentials *cred = [[Amazon alloc] initWithAccessKey:accessKey withSecretKey:secretAccessKey];
AmazonS3Client *s3 = [[AmazonS3Client alloc] initWithCredentials:cred];
S3GetObjectRequest *s3Request = [[S3GetObjectRequest alloc] initWithKey:urlPath withBucket:bucket];
s3Request.delegate = self;
S3GetObjectResponse *s3Response = [s3 getObject:s3Request];
NSData*data = s3Response.body;
image = [UIImage imageWithData:data];
When I run the program, I get the exception "EXC_BAD_ACCESS (code = 2, address = 0x0)." I am also unsure about what exactly to include in the bucket name. Should the bucket string be just "nameOfBucket"? or something like "topLevelFolder/nameOfBucket"? Also, what specifically should be included in the "urlPath"? I think that my exception probably has to do with incorrect bucket and urlPath names.
EDIT: I found that we weren't getting any data from S3 and the solution was to remove the line that said "s3Request.delegate = self;".
Here are two helper methods for getting image and checking if image exists
#import <AWSiOSSDK/S3/AmazonS3Client.h>
+(NSData *)getImage:(NSString *)imageID inFolder:(NSString *)folderName
{
// Initial the S3 Client.
//folderName = bucket name
AmazonS3Client *s3 = [[AmazonS3Client alloc] initWithAccessKey:ACCESS_KEY_ID withSecretKey:SECRET_KEY];
s3.timeout = 1000;
#try {
NSString *pictName = [NSString stringWithFormat:#"%#%#", imageID, #".jpg"];
S3GetObjectRequest *porr = [[S3GetObjectRequest alloc] initWithKey:pictName withBucket:folderName];
// Get the image data from the specified s3 bucket and object.
S3GetObjectResponse *response = [s3 getObject:porr];
NSData *imageData = response.body;
return imageData;
}
#catch (AmazonClientException *exception) {
return nil;
}
}
+(BOOL)isImageExists:(NSString *)imageID inFolder:(NSString *)folderName
{
#try {
AmazonS3Client *s3 = [[AmazonS3Client alloc] initWithAccessKey:ACCESS_KEY_ID withSecretKey:SECRET_KEY];
NSString *pictName = [NSString stringWithFormat:#"%#%#", imageID, #".jpg"];
NSLog(#"Start checking a full size image %#", imageID);
S3GetObjectMetadataRequest *porr = [[S3GetObjectMetadataRequest alloc] initWithKey:pictName withBucket:folderName];
S3GetObjectResponse *response = [s3 getObjectMetadata:porr];
if(response)
{
return YES;
}
}
#catch (AmazonServiceException *ex) {
NSLog(#"AmazonServiceException in isImageExists %#", ex.description);
return NO;
}
#catch (NSException *exception) {
NSLog(#"NSException in isImageExists %#", exception.description);
return NO;
}
return NO;
}
Assigning a delegate s3Request.delegate = self; causes the AmazonS3Client to send messages to the delegate methods (AmazonServiceRequestDelegate) and preempts messages to S3GetObjectResponse
The two most common delegate methods are:
-(void)request:(AmazonServiceRequest *)request didCompleteWithResponse:(AmazonServiceResponse *)response
-(void)request:(AmazonServiceRequest *)request didFailWithError:(NSError *)error

Resources