Can't find Module in NativeModules - ios

I'm trying to implement an iCloudStorage in react-native (0.53.3) with native code.
Right now I have the following:
Header
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>
#interface iCloudStorage : RCTEventEmitter <RCTBridgeModule>
#end
Source
#import "iCloudStorage.h"
#import <React/RCTEventDispatcher.h>
static NSString* const ICLOUDSTORAGE_PREFIX = #"#com.manicakes.iCloudStorage/";
static NSString* const ICLOUD_STORE_CHANGED = #"ICLOUD_STORE_CHANGED";
static NSString* const kStoreChangedEvent = #"iCloudStoreDidChangeRemotely";
static NSString* const kChangedKeys = #"changedKeys";
#implementation iCloudStorage
RCT_EXPORT_MODULE()
+ (NSString*)appendPrefixToKey:(NSString*)key {
return [NSString stringWithFormat:#"%#%#", ICLOUDSTORAGE_PREFIX, key];
}
+ (NSString*)removePrefixFromKey:(NSString*)key {
if (![key hasPrefix:ICLOUDSTORAGE_PREFIX]) {
return nil;
}
return [key substringFromIndex:[ICLOUDSTORAGE_PREFIX length]];
}
+ (NSDictionary*)storeDictionary {
NSUbiquitousKeyValueStore* store = [NSUbiquitousKeyValueStore defaultStore];
return [store dictionaryRepresentation];
}
+ (NSArray*)allKeysInStore {
return [[iCloudStorage storeDictionary] allKeys];
}
+ (id) getObjectForKey:(NSString*)key {
return [[NSUbiquitousKeyValueStore defaultStore] objectForKey:[iCloudStorage appendPrefixToKey:key]];
}
+ (void) setValue:(NSString*)value forKey:(NSString*)key {
[[NSUbiquitousKeyValueStore defaultStore] setObject:value forKey:[iCloudStorage appendPrefixToKey:key]];
[[NSUbiquitousKeyValueStore defaultStore] synchronize];
}
+ (void) removeKey:(NSString*)key {
[[NSUbiquitousKeyValueStore defaultStore] removeObjectForKey:[iCloudStorage appendPrefixToKey:key]];
[[NSUbiquitousKeyValueStore defaultStore] synchronize];
}
+ (NSString*) getMergedItemWithKey:(NSString*)key value:(NSString*)value rejecter:(RCTPromiseRejectBlock)reject {
NSDictionary* storedItem = #{};
NSDictionary* newItem = #{};
NSString* storedString = [iCloudStorage getObjectForKey:key];
if (storedString != nil) {
NSError* error = nil;
id object = [NSJSONSerialization JSONObjectWithData:[storedString dataUsingEncoding:NSUTF8StringEncoding]
options:0
error:&error];
if (error != nil) {
reject(#"json_decode_err", #"Error parsing stored value as JSON string.", error);
return nil;
}
if (![object isKindOfClass:[NSDictionary class]]) {
reject(#"json_not_object_err", #"The stored JSON string does not parse into an object.", nil);
return nil;
}
if (value != nil) {
id newObject = [NSJSONSerialization JSONObjectWithData:[value dataUsingEncoding:NSUTF8StringEncoding]
options:0
error:&error];
if (error != nil) {
reject(#"json_decode_err", #"The provided value is not valid JSON.", error);
return nil;
}
if (![newItem isKindOfClass:[NSDictionary class]]) {
reject(#"json_not_object_err", #"The provided JSON string does not parse into an object.", nil);
return nil;
}
newItem = newObject;
}
storedItem = object;
}
NSMutableDictionary* mergedItem = [NSMutableDictionary dictionaryWithDictionary:storedItem];
[mergedItem addEntriesFromDictionary:newItem];
NSError* error = nil;
NSData* data = [NSJSONSerialization dataWithJSONObject:mergedItem options:0 error:&error];
if (error != nil) {
reject(#"json_encode_err", #"Error encoding the merged JSON data to string.", error);
return nil;
}
return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
- (instancetype)init {
self = [super init];
if (self) {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(ubiquitousStoreUpdated:)
name:NSUbiquitousKeyValueStoreDidChangeExternallyNotification
object:nil];
[[NSUbiquitousKeyValueStore defaultStore] synchronize];
}
return self;
}
- (NSArray<NSString *> *)supportedEvents {
return #[ kStoreChangedEvent ];
}
- (void) ubiquitousStoreUpdated:(NSNotification*)notification {
// if this notification comes in before bridge has initialized,
// don't try to send the event (app crashes if you do).
if (!self.bridge) {
return;
}
NSArray* changedKeys = [[notification userInfo] objectForKey:NSUbiquitousKeyValueStoreChangedKeysKey];
NSMutableArray* reportedChangedKeys = [NSMutableArray array];
for (NSString* key in changedKeys) {
NSString* reportedKey = [iCloudStorage removePrefixFromKey:key];
if (reportedKey) {
[reportedChangedKeys addObject:reportedKey];
}
}
if ([reportedChangedKeys count]) {
NSDictionary* body = #{ kChangedKeys : reportedChangedKeys };
[self sendEventWithName:kStoreChangedEvent body:body];
}
}
RCT_EXPORT_METHOD(getItem: (NSString*)key resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
resolve([iCloudStorage getObjectForKey:key]);
}
RCT_EXPORT_METHOD(setItem: (NSString*)key value: (NSString*)value resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
[iCloudStorage setValue:value forKey:key];
resolve(#{});
}
RCT_EXPORT_METHOD(removeItem: (NSString*)key resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
[iCloudStorage removeKey:key];
resolve(#{});
}
RCT_EXPORT_METHOD(mergeItem: (NSString*)key value: (NSString*)value resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
NSString* newValue = [iCloudStorage getMergedItemWithKey:key value:value rejecter:reject];
if (newValue == nil) {
// we failed and reject block was called.
return;
}
[iCloudStorage setValue:newValue forKey:key];
resolve(#{});
}
RCT_REMAP_METHOD(clear, clearResolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
for (NSString* key in [iCloudStorage allKeysInStore]) {
if ([key hasPrefix:ICLOUDSTORAGE_PREFIX]) {
[[NSUbiquitousKeyValueStore defaultStore] removeObjectForKey:key];
}
}
resolve(#{});
}
RCT_REMAP_METHOD(getAllKeys, getAllKeysResolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
NSMutableArray* allKeys = [NSMutableArray array];
for (NSString* storeKey in [iCloudStorage allKeysInStore]) {
NSString* key = [iCloudStorage removePrefixFromKey:storeKey];
if (key != nil) {
[allKeys addObject:key];
}
}
resolve(allKeys);
}
RCT_EXPORT_METHOD(multiGet: (NSArray*)keys resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
NSMutableArray *result = [NSMutableArray arrayWithCapacity:[keys count]];
for (NSString* key in keys) {
NSObject* object = [iCloudStorage getObjectForKey:key];
if (object != nil) {
[result addObject:object];
}
}
resolve(result);
}
RCT_EXPORT_METHOD(multiSet: (NSDictionary*)keyValuePairs resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
for (NSString* key in [keyValuePairs allKeys]) {
[iCloudStorage setValue:[keyValuePairs objectForKey:key] forKey:key];
}
resolve(#{});
}
RCT_EXPORT_METHOD(multiRemove: (NSArray*)keys resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
for (NSString* key in keys) {
[iCloudStorage removeKey:key];
}
resolve(#{});
}
RCT_EXPORT_METHOD(multiMerge: (NSDictionary*)keyValuePairs resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) {
NSMutableDictionary* result = [NSMutableDictionary dictionaryWithCapacity:[keyValuePairs count]];
BOOL failed = NO;
for (NSString* key in [keyValuePairs allKeys]) {
NSString* newValue = [iCloudStorage getMergedItemWithKey:key value:[keyValuePairs objectForKey:key] rejecter:reject];
if (newValue == nil) {
break;
}
}
if (failed) {
return;
}
for (NSString* key in [result allKeys]) {
[iCloudStorage setValue:[result objectForKey:key] forKey:key];
}
resolve(#{});
}
- (NSDictionary<NSString *,id> *)constantsToExport {
return #{ ICLOUD_STORE_CHANGED : kStoreChangedEvent };
}
+ (BOOL)requiresMainQueueSetup {
return TRUE;
}
#end
The problem is that it isn't shown in the NativeModules when I import it. It returns undefined.
What am I missing? I use RCT_EXPORT_MODULE() to export it and I have the requiresMainQueueSetup to suppress the warning Module RCTImageLoader requires main queue setup since it overridesinitbut doesn't implementrequiresMainQueueSetup. In a future release React Native will default to initializing all native modules on a background thread unless explicitly opted-out of.
I've been searching but couldn't find an answer anywhere.
I've added the files to folder that is named after the project:
<projectfolder>
--<projectName>
iCloudStorage.h
iCloudStorage.m
--libraries
--etc..
Thanks for the help!

Just make sure your files are in the iOS folder.
Try to make a simple exported module work and then modify it according to your needs.
Don't forget to re-build with xCode or console after modifying iOS native files.
A simple exported native module should look like this (according to RN docs):
// CalendarManager.h
#import <React/RCTBridgeModule.h>
#interface CalendarManager : NSObject <RCTBridgeModule>
#end
// CalendarManager.m
#import "CalendarManager.h"
#implementation CalendarManager
// To export a module named CalendarManager
RCT_EXPORT_MODULE();
// This would name the module AwesomeCalendarManager instead
// RCT_EXPORT_MODULE(AwesomeCalendarManager);
#end
Then try to import it in your RN code:
import {NativeModules} from 'react-native';
var CalendarManager = NativeModules.CalendarManager;
Source:
https://facebook.github.io/react-native/docs/native-modules-ios
Your project tree should probably look like:
<projectfolder>
--<projectName>
--<ios>
iCloudStorage.h
iCloudStorage.m
--<android>
--JS libraries
--JS files etc
About the requiresMainQueueSetup warning:
If it is in the native modules, usually updating those modules should work.
If the warnings are related to your code you will have to modify your module as below:
For Swift:
#objc(MyModule)
class MyModule: NSObject {
// ADD the 3 lines from below:
#objc static func requiresMainQueueSetup() -> Bool {
return false
}
For Objective C:
+ (BOOL)requiresMainQueueSetup
{
return NO;
}
Just set the return value according to what your module needs. Usually a NO should be enough if your module doesn't interact with UI.

Related

CloudKit integration requires that the value transformers for transformable attributes are available via +[NSValueTransformer valueTransformerForName:

I'm using CoreData+CloudKit to store data, currently there are two Entities,AEntity and BEntity:
In AEntity, there is an attribute: content, used to store NSAttributedString, its Type is "Transformable", I set its "Transformer" to "AttributedStringValueTransformer" in the right menu of Xcode:
#implementation AttributedStringValueTransformer
+ (Class)transformedValueClass {
return [NSAttributedString class];
}
+ (BOOL)allowsReverseTransformation {
return YES;
}
- (NSData *)transformedValue:(NSAttributedString *)value {
if (!value) {
return nil;
}
if ([value isKindOfClass:[NSData class]]) {
return (NSData *)value;
}
NSData *stringAsData = [NSKeyedArchiver archivedDataWithRootObject:value];
return stringAsData;
}
- (NSAttributedString *)reverseTransformedValue:(NSData *)value {
NSAttributedString *attributedString = [NSKeyedUnarchiver unarchiveObjectWithData:value];
return attributedString;
}
#end
In BEntity, there is an Attribute: images, which is used to store image arrays (NSArray), and its Type is also "Transformable". I set its "Transformer" to "ArrayValueTransformer" in the right menu of Xcode:
#implementation ArrayValueTransformer
+ (Class)transformedValueClass {
return [NSArray class];
}
+ (BOOL)allowsReverseTransformation {
return YES;
}
- (NSData *)transformedValue:(NSAttributedString *)value {
if (!value) {
return nil;
}
if ([value isKindOfClass:[NSData class]]) {
return (NSData *)value;
}
return [NSKeyedArchiver archivedDataWithRootObject:value];;
}
- (NSAttributedString *)reverseTransformedValue:(NSData *)value {
return [NSKeyedUnarchiver unarchiveObjectWithData:value];
}
#end
When calling the loadPersistentStoresWithCompletionHandler: method:
+ (instancetype)containerWithName:(NSString *)name {
NSPersistentCloudKitContainer *persistentContainer = [[NSPersistentCloudKitContainer alloc] initWithName:name];
persistentContainer.viewContext.automaticallyMergesChangesFromParent = YES;
NSPersistentStoreDescription *description = [persistentContainer.persistentStoreDescriptions firstObject];
[description setOption:#(YES) forKey:NSPersistentHistoryTrackingKey];
[description setOption:#(YES) forKey:NSPersistentStoreRemoteChangeNotificationPostOptionKey];
description.shouldInferMappingModelAutomatically = YES;
description.shouldMigrateStoreAutomatically = YES;
persistentContainer.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
[persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *storeDescription, NSError *error) {
if (error != nil) {
NSLog(#"Unresolved error %#, %#", error, error.userInfo);
// abort();
}
}];
return persistentContainer;
}
The error information in the callback of loadPersistentStoresWithCompletionHandler is:
Error Domain=NSCocoaErrorDomain Code=134060 "A Core Data error
occurred." UserInfo={NSLocalizedFailureReason=CloudKit integration
requires that the value transformers for transformable attributes are
available via +[NSValueTransformer valueTransformerForName:], return
instances of NSData, and allow reverse transformation: AEntity:
content - Claims to return instances of NSAttributedString BEntity:
images - Claims to return instances of NSArray}
What is the reason for this? And how should this problem be solved?

Property 'utmParametersDictionary' not found on object of type 'FIRDynamicLink *'

Semantic Issue (Xcode): Property 'utmParametersDictionary' not found on object of type 'FIRDynamicLink *'
/Users/jeremydormevil/.pub-cache/hosted/pub.dartlang.org/firebase_dynamic_links-4.1.1/ios/Classes/FLTFirebaseDynamicLinksPlugin.m:26:47
When i take a look into the code, the problem seem to came from this line :
dictionary[#"utmParameters"] = dynamicLink.utmParametersDictionary;
CODE:
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import <Firebase/Firebase.h>
#import <TargetConditionals.h>
#import <firebase_core/FLTFirebasePluginRegistry.h>
#import "FLTFirebaseDynamicLinksPlugin.h"
NSString *const kFLTFirebaseDynamicLinksChannelName = #"plugins.flutter.io/firebase_dynamic_links";
NSString *const kDLAppName = #"appName";
NSString *const kUrl = #"url";
NSString *const kCode = #"code";
NSString *const kMessage = #"message";
NSString *const kDynamicLinkParametersOptions = #"dynamicLinkParametersOptions";
NSString *const kDefaultAppName = #"[DEFAULT]";
static NSMutableDictionary *getDictionaryFromDynamicLink(FIRDynamicLink *dynamicLink) {
if (dynamicLink != nil) {
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
dictionary[#"link"] = dynamicLink.url.absoluteString;
NSMutableDictionary *iosData = [[NSMutableDictionary alloc] init];
if (dynamicLink.minimumAppVersion) {
iosData[#"minimumVersion"] = dynamicLink.minimumAppVersion;
}
dictionary[#"utmParameters"] = dynamicLink.utmParametersDictionary;
dictionary[#"ios"] = iosData;
return dictionary;
} else {
return nil;
}
}
static NSDictionary *getDictionaryFromNSError(NSError *error) {
NSString *code = #"unknown";
NSString *message = #"An unknown error has occurred.";
if (error == nil) {
return #{
kCode : code,
kMessage : message,
#"additionalData" : #{},
};
}
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
dictionary[kCode] = [NSString stringWithFormat:#"%d", (int)error.code];
dictionary[kMessage] = [error localizedDescription];
id additionalData = [NSMutableDictionary dictionary];
if ([error userInfo] != nil) {
additionalData = [error userInfo];
}
return #{
kCode : code,
kMessage : message,
#"additionalData" : additionalData,
};
}
#implementation FLTFirebaseDynamicLinksPlugin {
NSObject<FlutterBinaryMessenger> *_binaryMessenger;
}
#pragma mark - FlutterPlugin
- (instancetype)init:(NSObject<FlutterBinaryMessenger> *)messenger
withChannel:(FlutterMethodChannel *)channel {
self = [super init];
if (self) {
[[FLTFirebasePluginRegistry sharedInstance] registerFirebasePlugin:self];
_binaryMessenger = messenger;
_channel = channel;
}
return self;
}
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar {
FlutterMethodChannel *channel =
[FlutterMethodChannel methodChannelWithName:kFLTFirebaseDynamicLinksChannelName
binaryMessenger:[registrar messenger]];
FLTFirebaseDynamicLinksPlugin *instance =
[[FLTFirebaseDynamicLinksPlugin alloc] init:registrar.messenger withChannel:channel];
[registrar addMethodCallDelegate:instance channel:channel];
#if TARGET_OS_OSX
// Publish does not exist on MacOS version of FlutterPluginRegistrar.
// FlutterPluginRegistrar. (https://github.com/flutter/flutter/issues/41471)
#else
[registrar publish:instance];
[registrar addApplicationDelegate:instance];
#endif
}
- (void)cleanupWithCompletion:(void (^)(void))completion {
if (completion != nil) completion();
}
- (void)detachFromEngineForRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar {
[self cleanupWithCompletion:nil];
}
- (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result {
FLTFirebaseMethodCallErrorBlock errorBlock = ^(
NSString *_Nullable code, NSString *_Nullable message, NSDictionary *_Nullable details,
NSError *_Nullable error) {
if (code == nil) {
NSDictionary *errorDetails = getDictionaryFromNSError(error);
code = errorDetails[kCode];
message = errorDetails[kMessage];
details = errorDetails;
} else {
details = #{
kCode : code,
kMessage : message,
#"additionalData" : #{},
};
}
if ([#"unknown" isEqualToString:code]) {
NSLog(#"FLTFirebaseDynamicLinks: An error occurred while calling method %#, errorOrNil => %#",
call.method, [error userInfo]);
}
result([FLTFirebasePlugin createFlutterErrorFromCode:code
message:message
optionalDetails:details
andOptionalNSError:error]);
};
FLTFirebaseMethodCallResult *methodCallResult =
[FLTFirebaseMethodCallResult createWithSuccess:result andErrorBlock:errorBlock];
NSString *appName = call.arguments[kDLAppName];
if (appName != nil && ![appName isEqualToString:kDefaultAppName]) {
// TODO - document iOS default app only
NSLog(#"FLTFirebaseDynamicLinks: iOS plugin only supports the Firebase default app");
}
if ([#"FirebaseDynamicLinks#buildLink" isEqualToString:call.method]) {
[self buildLink:call.arguments withMethodCallResult:methodCallResult];
} else if ([#"FirebaseDynamicLinks#buildShortLink" isEqualToString:call.method]) {
[self buildShortLink:call.arguments withMethodCallResult:methodCallResult];
} else if ([#"FirebaseDynamicLinks#getInitialLink" isEqualToString:call.method]) {
[self getInitialLink:methodCallResult];
} else if ([#"FirebaseDynamicLinks#getDynamicLink" isEqualToString:call.method]) {
[self getDynamicLink:call.arguments withMethodCallResult:methodCallResult];
} else {
result(FlutterMethodNotImplemented);
}
}
#pragma mark - Firebase Dynamic Links API
- (void)buildLink:(id)arguments withMethodCallResult:(FLTFirebaseMethodCallResult *)result {
FIRDynamicLinkComponents *components = [self setupParameters:arguments];
result.success([components.url absoluteString]);
}
- (void)buildShortLink:(id)arguments withMethodCallResult:(FLTFirebaseMethodCallResult *)result {
FIRDynamicLinkComponentsOptions *options = [self setupOptions:arguments];
NSString *longDynamicLink = arguments[#"longDynamicLink"];
if (longDynamicLink != nil) {
NSURL *url = [NSURL URLWithString:longDynamicLink];
[FIRDynamicLinkComponents
shortenURL:url
options:options
completion:^(NSURL *_Nullable shortURL, NSArray<NSString *> *_Nullable warnings,
NSError *_Nullable error) {
if (error != nil) {
result.error(nil, nil, nil, error);
} else {
if (warnings == nil) {
warnings = [NSMutableArray array];
}
result.success(#{
kUrl : [shortURL absoluteString],
#"warnings" : warnings,
});
}
}];
} else {
FIRDynamicLinkComponents *components = [self setupParameters:arguments];
components.options = options;
[components
shortenWithCompletion:^(NSURL *_Nullable shortURL, NSArray<NSString *> *_Nullable warnings,
NSError *_Nullable error) {
if (error != nil) {
result.error(nil, nil, nil, error);
} else {
if (warnings == nil) {
warnings = [NSMutableArray array];
}
result.success(#{
kUrl : [shortURL absoluteString],
#"warnings" : warnings,
});
}
}];
}
}
- (void)getInitialLink:(FLTFirebaseMethodCallResult *)result {
_initiated = YES;
NSMutableDictionary *dict = getDictionaryFromDynamicLink(_initialLink);
if (dict == nil && self.initialError != nil) {
result.error(nil, nil, nil, self.initialError);
} else {
result.success(dict);
}
}
- (void)getDynamicLink:(id)arguments withMethodCallResult:(FLTFirebaseMethodCallResult *)result {
NSURL *shortLink = [NSURL URLWithString:arguments[kUrl]];
FIRDynamicLinkUniversalLinkHandler completion =
^(FIRDynamicLink *_Nullable dynamicLink, NSError *_Nullable error) {
if (error) {
result.error(nil, nil, nil, error);
} else {
result.success(getDictionaryFromDynamicLink(dynamicLink));
}
};
[[FIRDynamicLinks dynamicLinks] handleUniversalLink:shortLink completion:completion];
}
#pragma mark - AppDelegate
// Handle links received through your app's custom URL scheme. Called when your
// app receives a link and your app is opened for the first time after installation.
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options {
[self checkForDynamicLink:url];
// Results of this are ORed and NO doesn't affect other delegate interceptors' result.
return NO;
}
// Handle links received as Universal Links when the app is already installed (on iOS 9 and newer).
- (BOOL)application:(UIApplication *)application
continueUserActivity:(NSUserActivity *)userActivity
restorationHandler:(nonnull void (^)(NSArray *_Nullable))restorationHandler {
__block BOOL retried = NO;
void (^completionBlock)(FIRDynamicLink *_Nullable dynamicLink, NSError *_Nullable error);
void (^__block __weak weakCompletionBlock)(FIRDynamicLink *_Nullable dynamicLink,
NSError *_Nullable error);
weakCompletionBlock = completionBlock =
^(FIRDynamicLink *_Nullable dynamicLink, NSError *_Nullable error) {
if (!error && dynamicLink && dynamicLink.url) {
[self onDeepLinkResult:dynamicLink error:nil];
}
if (!error && dynamicLink && !dynamicLink.url) {
NSLog(#"FLTFirebaseDynamicLinks: The url has not been supplied with the dynamic link."
#"Please try opening your app with the long dynamic link to see if that works");
}
// Per Apple Tech Support, a network failure could occur when returning from background on
// iOS 12. https://github.com/AFNetworking/AFNetworking/issues/4279#issuecomment-447108981
// So we'll retry the request once
if (error && !retried && [NSPOSIXErrorDomain isEqualToString:error.domain] &&
error.code == 53) {
retried = YES;
[[FIRDynamicLinks dynamicLinks] handleUniversalLink:userActivity.webpageURL
completion:weakCompletionBlock];
}
if (error && retried) {
// Need to update any event channel the universal link failed
[self onDeepLinkResult:nil error:error];
}
};
[[FIRDynamicLinks dynamicLinks] handleUniversalLink:userActivity.webpageURL
completion:completionBlock];
// Results of this are ORed and NO doesn't affect other delegate interceptors' result.
return NO;
}
#pragma mark - Utilities
- (void)checkForDynamicLink:(NSURL *)url {
FIRDynamicLink *dynamicLink = [[FIRDynamicLinks dynamicLinks] dynamicLinkFromCustomSchemeURL:url];
if (dynamicLink) {
[self onDeepLinkResult:dynamicLink error:nil];
}
}
// Used to action events from firebase-ios-sdk custom & universal dynamic link event listeners
- (void)onDeepLinkResult:(FIRDynamicLink *_Nullable)dynamicLink error:(NSError *_Nullable)error {
if (error) {
if (_initialLink == nil) {
// store initial error to pass back to user if getInitialLink is called
_initialError = error;
}
NSDictionary *errorDetails = getDictionaryFromNSError(error);
FlutterError *flutterError =
[FLTFirebasePlugin createFlutterErrorFromCode:errorDetails[kCode]
message:errorDetails[kMessage]
optionalDetails:errorDetails
andOptionalNSError:error];
NSLog(#"FLTFirebaseDynamicLinks: Unknown error occurred when attempting to handle a dynamic "
#"link: %#",
flutterError);
[_channel invokeMethod:#"FirebaseDynamicLink#onLinkError" arguments:flutterError];
} else {
NSMutableDictionary *dictionary = getDictionaryFromDynamicLink(dynamicLink);
if (dictionary != nil) {
[_channel invokeMethod:#"FirebaseDynamicLink#onLinkSuccess" arguments:dictionary];
}
}
if (_initialLink == nil && dynamicLink.url != nil) {
_initialLink = dynamicLink;
}
if (dynamicLink.url != nil) {
_latestLink = dynamicLink;
}
}
- (FIRDynamicLinkComponentsOptions *)setupOptions:(NSDictionary *)arguments {
FIRDynamicLinkComponentsOptions *options = [FIRDynamicLinkComponentsOptions options];
NSNumber *shortDynamicLinkPathLength = arguments[#"shortLinkType"];
if (![shortDynamicLinkPathLength isEqual:[NSNull null]]) {
switch (shortDynamicLinkPathLength.intValue) {
case 0:
options.pathLength = FIRShortDynamicLinkPathLengthUnguessable;
break;
case 1:
options.pathLength = FIRShortDynamicLinkPathLengthShort;
break;
default:
break;
}
}
return options;
}
- (FIRDynamicLinkComponents *)setupParameters:(NSDictionary *)arguments {
NSURL *link = [NSURL URLWithString:arguments[#"link"]];
NSString *uriPrefix = arguments[#"uriPrefix"];
FIRDynamicLinkComponents *components = [FIRDynamicLinkComponents componentsWithLink:link
domainURIPrefix:uriPrefix];
if (![arguments[#"androidParameters"] isEqual:[NSNull null]]) {
NSDictionary *params = arguments[#"androidParameters"];
FIRDynamicLinkAndroidParameters *androidParams =
[FIRDynamicLinkAndroidParameters parametersWithPackageName:params[#"packageName"]];
NSString *fallbackUrl = params[#"fallbackUrl"];
NSNumber *minimumVersion = params[#"minimumVersion"];
if (![fallbackUrl isEqual:[NSNull null]])
androidParams.fallbackURL = [NSURL URLWithString:fallbackUrl];
if (![minimumVersion isEqual:[NSNull null]])
androidParams.minimumVersion = ((NSNumber *)minimumVersion).integerValue;
components.androidParameters = androidParams;
}
components.options = [self setupOptions:arguments];
if (![arguments[#"googleAnalyticsParameters"] isEqual:[NSNull null]]) {
NSDictionary *params = arguments[#"googleAnalyticsParameters"];
FIRDynamicLinkGoogleAnalyticsParameters *googleAnalyticsParameters =
[FIRDynamicLinkGoogleAnalyticsParameters parameters];
NSString *campaign = params[#"campaign"];
NSString *content = params[#"content"];
NSString *medium = params[#"medium"];
NSString *source = params[#"source"];
NSString *term = params[#"term"];
if (![campaign isEqual:[NSNull null]]) googleAnalyticsParameters.campaign = campaign;
if (![content isEqual:[NSNull null]]) googleAnalyticsParameters.content = content;
if (![medium isEqual:[NSNull null]]) googleAnalyticsParameters.medium = medium;
if (![source isEqual:[NSNull null]]) googleAnalyticsParameters.source = source;
if (![term isEqual:[NSNull null]]) googleAnalyticsParameters.term = term;
components.analyticsParameters = googleAnalyticsParameters;
}
if (![arguments[#"iosParameters"] isEqual:[NSNull null]]) {
NSDictionary *params = arguments[#"iosParameters"];
FIRDynamicLinkIOSParameters *iosParameters =
[FIRDynamicLinkIOSParameters parametersWithBundleID:params[#"bundleId"]];
NSString *appStoreID = params[#"appStoreId"];
NSString *customScheme = params[#"customScheme"];
NSString *fallbackURL = params[#"fallbackUrl"];
NSString *iPadBundleID = params[#"ipadBundleId"];
NSString *iPadFallbackURL = params[#"ipadFallbackUrl"];
NSString *minimumAppVersion = params[#"minimumVersion"];
if (![appStoreID isEqual:[NSNull null]]) iosParameters.appStoreID = appStoreID;
if (![customScheme isEqual:[NSNull null]]) iosParameters.customScheme = customScheme;
if (![fallbackURL isEqual:[NSNull null]])
iosParameters.fallbackURL = [NSURL URLWithString:fallbackURL];
if (![iPadBundleID isEqual:[NSNull null]]) iosParameters.iPadBundleID = iPadBundleID;
if (![iPadFallbackURL isEqual:[NSNull null]])
iosParameters.iPadFallbackURL = [NSURL URLWithString:iPadFallbackURL];
if (![minimumAppVersion isEqual:[NSNull null]])
iosParameters.minimumAppVersion = minimumAppVersion;
components.iOSParameters = iosParameters;
}
if (![arguments[#"itunesConnectAnalyticsParameters"] isEqual:[NSNull null]]) {
NSDictionary *params = arguments[#"itunesConnectAnalyticsParameters"];
FIRDynamicLinkItunesConnectAnalyticsParameters *itunesConnectAnalyticsParameters =
[FIRDynamicLinkItunesConnectAnalyticsParameters parameters];
NSString *affiliateToken = params[#"affiliateToken"];
NSString *campaignToken = params[#"campaignToken"];
NSString *providerToken = params[#"providerToken"];
if (![affiliateToken isEqual:[NSNull null]])
itunesConnectAnalyticsParameters.affiliateToken = affiliateToken;
if (![campaignToken isEqual:[NSNull null]])
itunesConnectAnalyticsParameters.campaignToken = campaignToken;
if (![providerToken isEqual:[NSNull null]])
itunesConnectAnalyticsParameters.providerToken = providerToken;
components.iTunesConnectParameters = itunesConnectAnalyticsParameters;
}
if (![arguments[#"navigationInfoParameters"] isEqual:[NSNull null]]) {
NSDictionary *params = arguments[#"navigationInfoParameters"];
FIRDynamicLinkNavigationInfoParameters *navigationInfoParameters =
[FIRDynamicLinkNavigationInfoParameters parameters];
NSNumber *forcedRedirectEnabled = params[#"forcedRedirectEnabled"];
if (![forcedRedirectEnabled isEqual:[NSNull null]])
navigationInfoParameters.forcedRedirectEnabled = [forcedRedirectEnabled boolValue];
components.navigationInfoParameters = navigationInfoParameters;
}
if (![arguments[#"socialMetaTagParameters"] isEqual:[NSNull null]]) {
NSDictionary *params = arguments[#"socialMetaTagParameters"];
FIRDynamicLinkSocialMetaTagParameters *socialMetaTagParameters =
[FIRDynamicLinkSocialMetaTagParameters parameters];
NSString *descriptionText = params[#"description"];
NSString *imageURL = params[#"imageUrl"];
NSString *title = params[#"title"];
if (![descriptionText isEqual:[NSNull null]])
socialMetaTagParameters.descriptionText = descriptionText;
if (![imageURL isEqual:[NSNull null]])
socialMetaTagParameters.imageURL = [NSURL URLWithString:imageURL];
if (![title isEqual:[NSNull null]]) socialMetaTagParameters.title = title;
components.socialMetaTagParameters = socialMetaTagParameters;
}
return components;
}
#pragma mark - FLTFirebasePlugin
- (void)didReinitializeFirebaseCore:(void (^)(void))completion {
[self cleanupWithCompletion:completion];
}
- (NSDictionary *_Nonnull)pluginConstantsForFIRApp:(FIRApp *)firebase_app {
return #{};
}
- (NSString *_Nonnull)firebaseLibraryName {
return LIBRARY_NAME;
}
- (NSString *_Nonnull)firebaseLibraryVersion {
return LIBRARY_VERSION;
}
- (NSString *_Nonnull)flutterChannelName {
return kFLTFirebaseDynamicLinksChannelName;
}
#end
Can someone help me ? Thanks in advance.
Run pod update to get at least Firebase 7.7.0 which is when utmParametersDictionary was introduced to the API.

I'm not able to resume download task in NSURLSession

I have create a demo for downloading a file from the server it is working fine with foreground and background, but when I'm going to resume it, It will giving below Error
I have stcuk here could help me so solved it, I search in internet but I couldn't find anything helpful.
Download file and Pause Downlaod is working fine I have issue to resume it.
Task <3AE5BF24-3A4E-4713-8FC2-A0032022C913>.<6> finished with error [-3003] Error Domain=NSURLErrorDomain Code=-3003 "(null)" UserInfo={_NSURLErrorRelatedURLSessionTaskErrorKey=(
"BackgroundDownloadTask <3AE5BF24-3A4E-4713-8FC2-A0032022C913>.<6>"
), _NSURLErrorFailingURLSessionTaskErrorKey=BackgroundDownloadTask <3AE5BF24-3A4E-4713-8FC2-A0032022C913>.<6>}
Here is the final Xcode project
Downlaod xcode project
#import "NSURLSession+ResumeData.h"
#import <UIKit/UIKit.h>
#define IS_IOS10ORLATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 10)
#pragma mark- private
static NSData * correctRequestData(NSData *data) {
if (!data) {
return nil;
}
// return the same data if it's correct
if ([NSKeyedUnarchiver unarchiveObjectWithData:data] != nil) {
return data;
}
NSMutableDictionary *archive = [[NSPropertyListSerialization propertyListWithData:data options:NSPropertyListMutableContainersAndLeaves format:nil error:nil] mutableCopy];
if (!archive) {
return nil;
}
NSInteger k = 0;
id objectss = archive[#"$objects"];
while ([objectss[1] objectForKey:[NSString stringWithFormat:#"$%ld",k]] != nil) {
k += 1;
}
NSInteger i = 0;
while ([archive[#"$objects"][1] objectForKey:[NSString stringWithFormat:#"__nsurlrequest_proto_prop_obj_%ld",i]] != nil) {
NSMutableArray *arr = archive[#"$objects"];
NSMutableDictionary *dic = arr[1];
id obj = [dic objectForKey:[NSString stringWithFormat:#"__nsurlrequest_proto_prop_obj_%ld",i]];
if (obj) {
[dic setValue:obj forKey:[NSString stringWithFormat:#"$%ld",i+k]];
[dic removeObjectForKey:[NSString stringWithFormat:#"__nsurlrequest_proto_prop_obj_%ld",i]];
[arr replaceObjectAtIndex:1 withObject:dic];
archive[#"$objects"] = arr;
}
i++;
}
if ([archive[#"$objects"][1] objectForKey:#"__nsurlrequest_proto_props"] != nil) {
NSMutableArray *arr = archive[#"$objects"];
NSMutableDictionary *dic = arr[1];
id obj = [dic objectForKey:#"__nsurlrequest_proto_props"];
if (obj) {
[dic setValue:obj forKey:[NSString stringWithFormat:#"$%ld",i+k]];
[dic removeObjectForKey:#"__nsurlrequest_proto_props"];
[arr replaceObjectAtIndex:1 withObject:dic];
archive[#"$objects"] = arr;
}
}
// Rectify weird "NSKeyedArchiveRootObjectKey" top key to NSKeyedArchiveRootObjectKey = "root"
if ([archive[#"$top"] objectForKey:#"NSKeyedArchiveRootObjectKey"] != nil) {
[archive[#"$top"] setObject:archive[#"$top"][#"NSKeyedArchiveRootObjectKey"] forKey: NSKeyedArchiveRootObjectKey];
[archive[#"$top"] removeObjectForKey:#"NSKeyedArchiveRootObjectKey"];
}
// Reencode archived object
NSData *result = [NSPropertyListSerialization dataWithPropertyList:archive format:NSPropertyListBinaryFormat_v1_0 options:0 error:nil];
return result;
}
static NSMutableDictionary *getResumeDictionary(NSData *data) {
NSMutableDictionary *iresumeDictionary = nil;
if (IS_IOS10ORLATER) {
id root = nil;
id keyedUnarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
#try {
root = [keyedUnarchiver decodeTopLevelObjectForKey:#"NSKeyedArchiveRootObjectKey" error:nil];
if (root == nil) {
root = [keyedUnarchiver decodeTopLevelObjectForKey:NSKeyedArchiveRootObjectKey error:nil];
}
} #catch(NSException *exception) {
}
[keyedUnarchiver finishDecoding];
iresumeDictionary = [root mutableCopy];
}
if (iresumeDictionary == nil) {
iresumeDictionary = [NSPropertyListSerialization propertyListWithData:data options:NSPropertyListMutableContainersAndLeaves format:nil error:nil];
}
return iresumeDictionary;
}
static NSData *correctResumeData(NSData *data) {
NSString *kResumeCurrentRequest = #"NSURLSessionResumeCurrentRequest";
NSString *kResumeOriginalRequest = #"NSURLSessionResumeOriginalRequest";
if (data == nil) {
return nil;
}
NSMutableDictionary *resumeDictionary = getResumeDictionary(data);
if (resumeDictionary == nil) {
return nil;
}
resumeDictionary[kResumeCurrentRequest] = correctRequestData(resumeDictionary[kResumeCurrentRequest]);
resumeDictionary[kResumeOriginalRequest] = correctRequestData(resumeDictionary[kResumeOriginalRequest]);
NSData *result = [NSPropertyListSerialization dataWithPropertyList:resumeDictionary format:NSPropertyListXMLFormat_v1_0 options:0 error:nil];
return result;
}
#implementation NSURLSession (ResumeData)
- (NSURLSessionDownloadTask *)downloadTaskWithCorrectResumeData:(NSData *)resumeData {
NSString *kResumeCurrentRequest = #"NSURLSessionResumeCurrentRequest";
NSString *kResumeOriginalRequest = #"NSURLSessionResumeOriginalRequest";
NSData *cData = correctResumeData(resumeData);
cData = cData ? cData:resumeData;
NSURLSessionDownloadTask *task = [self downloadTaskWithResumeData:cData];
NSMutableDictionary *resumeDic = getResumeDictionary(cData);
if (resumeDic) {
if (task.originalRequest == nil) {
NSData *originalReqData = resumeDic[kResumeOriginalRequest];
NSURLRequest *originalRequest = [NSKeyedUnarchiver unarchiveObjectWithData:originalReqData ];
if (originalRequest) {
[task setValue:originalRequest forKey:#"originalRequest"];
}
}
if (task.currentRequest == nil) {
NSData *currentReqData = resumeDic[kResumeCurrentRequest];
NSURLRequest *currentRequest = [NSKeyedUnarchiver unarchiveObjectWithData:currentReqData];
if (currentRequest) {
[task setValue:currentRequest forKey:#"currentRequest"];
}
}
}
return task;
}
#end

Error on Adding to NSMutableArray

The following code is in my implementation file:
NSMutableArray *courseArray;
- (IBAction)btnClick:(id)sender
{
NSDictionary *courseNames;
if(![_txtBox.text isEqual:#""]) //if not empty
{
courseNames = [self retrieveCourseNamesForSemester:_txtBox.text];
for (NSString *key in courseNames)
{
NSString *val = [NSString stringWithFormat:#"%#-%#",key,[courseNames objectForKey:key]];
_txtView.text = val;
#try
{
[courseArray addObject:val];
}
#catch(NSException *e)
{
NSLog(#"Exception: %# for value = %#", e, val);
}
}
}
[_coursePicker reloadAllComponents];
_coursePicker.hidden=false;
[_txtBox resignFirstResponder];
}
Where you see the call to NSLog(), I get the following error message:
2014-03-29 00:02:25.830 WebServiceTest[44646:60b] Exception: -[__NSArrayI addObject:]: unrecognized selector sent to instance 0x8d82c30 for value = 73-522-Course Name
EDIT: Also, courseArray is populated with sample data in viewDidLoad:
- (void)viewDidLoad
{
[super viewDidLoad];
courseArray = #[#"Australia (AUD)", #"China (CNY)",
#"France (EUR)", #"Great Britain (GBP)", #"Japan (JPY)"];
}
Is there somewhere I should be defining that courseArray will take NSString objects?
The code in viewDidLoad creates an immutable array. You need to make a mutable copy, like this
(void)viewDidLoad
{
[super viewDidLoad];
courseArray = [#[#"(AUD)", #"(CNY)", #"(EUR)"] mutableCopy];
}
Try this code,
for (NSString *key in courseNames)
{
NSString *val = [NSString stringWithFormat:#"%#-%#",key,[courseNames objectForKey:key]];
_txtView.text = val;
if ([CourseArray count]==0)
{
CourseArray= [NSMutableArray arrayWithObject:val];
}
else
{
[CourseArray addObject:val];
}
}

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.

Resources