CTTelephonyNetworkInfo.serviceCurrentRadioAccessTechnology changed in iOS 14 crash - ios14

if (#available(iOS 12.0, *)) {
CTTelephonyNetworkInfo * tmp = [[CTTelephonyNetworkInfo alloc] init];
if ([tmp respondsToSelector:#selector(serviceCurrentRadioAccessTechnology)]) {
[tmp.serviceCurrentRadioAccessTechnology enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSString * _Nonnull obj, BOOL * _Nonnull stop) {
currentRadioAccessTechnology = obj;
*stop = YES;
}];
}
tmp = nil;
}
before iOS14 currentRadioAccessTechnology is NSString and
iOS14 currentRadioAccessTechnology is NSArray
if (currentRadioAccessTechnology)
{
if ([currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyLTE])
{
returnValue = network_4g;
}
else if ([currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyEdge]
|| [currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyGPRS])
{
returnValue = network_2g;
}
else
{
returnValue = network_3g;
}
return returnValue;
}
if ([currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyLTE]) crashed error info [__NSArrayM isEqualToString:]: unrecognized selector sent to instance

Related

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.

How to fix '-[__NSArrayM totalLength]: unrecognized

I'm setting up
appDele.mMediaManager=[[BluzManager alloc] initWithConnector:appDele.mBluzConnector];
and Third-party library methods are also implemented. When I init object then the problem goes:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayM totalLength]: unrecognized
Is the NSArray about _m_arrBT goes wrong?
-(void)connectedPeripheral:(CBPeripheral *)peripheral{
if (m_dictConnect != nil) {
BOOL found = NO;
for (int i = 0; i < _m_arrBT.count; i++) {
NSMutableDictionary *dict = [_m_arrBT objectAtIndex:i];
CBPeripheral *device = [dict objectForKey:#"peripheral"];
CBPeripheral *connected = [m_dictConnect objectForKey:#"peripheral"];
// if (device.UUID == connected.UUID) {
if ([self isPeripheral:device equalPeripheral:connected]) {
found = YES;
break;
}
}
if (!found) {
[_m_arrBT addObject:m_dictConnect];
}
_m_arrBT = [self sortDeviceArray:_m_arrBT];
} else {
for (NSDictionary *dict in _m_arrBT) {
CBPeripheral *device = [dict objectForKey:#"peripheral"];
// if (device.UUID == peripheral.UUID) {
if ([self isPeripheral:device equalPeripheral:peripheral]) {
NSLog(#"devicename=%#",[dict objectForKey:#"name"]);
}
}
}
appDele.mMediaManager=[[BluzManager alloc] initWithConnector:appDele.mBluzConnector];
appDele.globalManager=[appDele.mMediaManager getGlobalManager:self];
mUserDiconnected = NO;
m_bConnect=YES;
_m_arrBT = [self sortDeviceArray:_m_arrBT];
[self.tableView reloadData];
if (!mManagerReady || !mHotplugCardArrived || !mHotplugUhostArrived || !mHotplugUSBArrived) {
// [self managerReady];
}
}

when will a NSObject's property could be null

I have a model translator. It reads AModel's properties, and copy the value to BModel's same property if BModel has. Now I have a crash report shows the property is null. That is so strange. The property is got from a property list and it is null.
Here is the message:
*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<XXXXXX 0x1594051a0> valueForUndefinedKey:]: this class is not key value coding-compliant for the key (null).
+ (instancetype)convertSourceObject:(id)sourceObject {
if (!sourceObject) {
return nil;
}
id destination_object = [[self alloc] init];
uint destination_properties_count = 0;
objc_property_t *destination_properties = class_copyPropertyList([self class], &destination_properties_count);
for (int i = 0; i < destination_properties_count; i++) {
objc_property_t destination_property = destination_properties[i];
uint source_attributes_count = 0, destination_attributes_count = 0;
objc_property_attribute_t *destination_attributes = property_copyAttributeList(destination_property, &destination_attributes_count);
const char *property_char_name = property_getName(destination_property);
NSString *property_name = [NSString stringWithUTF8String:property_char_name];
objc_property_t source_property = class_getProperty([sourceObject class], property_char_name);
if (source_property && ![ignorePropertyNames() containsObject:property_name]) {
objc_property_attribute_t *source_attributes = property_copyAttributeList(source_property, &source_attributes_count);
NSString *source_ivar_type = #"";
NSString *destination_ivar_type = #"";
for (int i = 0; i < source_attributes_count; i++) {
if (strcmp(source_attributes[i].name, "T") == 0) {
source_ivar_type = [[NSString stringWithUTF8String:source_attributes[i].value] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#"#\""]];
break;
}
}
for (int i = 0; i < destination_attributes_count; i++) {
if (strcmp(destination_attributes[i].name, "T") == 0) {
destination_ivar_type = [[NSString stringWithUTF8String:destination_attributes[i].value] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#"#\""]];
break;
}
}
if ([self isPropertySetType:source_ivar_type]) {
id source_value = [sourceObject valueForKey:property_name];
if ([source_value isKindOfClass:[NSArray class]]) {
NSArray *destination_array = [self arrayConvert:(NSArray*)source_value];
if (destination_array) {
[destination_object setValue:destination_array forKey:property_name];
}
} else if ([source_value isKindOfClass:[NSDictionary class]]) {
NSDictionary *destination_dict = [self dictionaryConvert:(NSDictionary *)source_value];
if (destination_dict) {
[destination_object setValue:destination_dict forKey:property_name];
}
}
} else {
if ([destination_ivar_type isEqualToString:source_ivar_type]) {
id source_value = [sourceObject valueForKey:property_name];
if (source_value) {
[destination_object setValue:source_value forKey:property_name];
}
} else {
id source_value = [sourceObject valueForKey:property_name];
id destination_value = [NSClassFromString(destination_ivar_type) convertSourceObject:source_value];
if (destination_value) {
[destination_object setValue:destination_value forKey:property_name];
}
}
}
free(source_attributes);
} else {
continue;
}
free(destination_attributes);
}
free(destination_properties);
return destination_object;
}
The error means: you try to read a property which name's "null" AModel's property , but it doesn't exit in AModel.
You should overwrite valueForUndefinedKey in your Model Class, debug the UndefinedKey.
Check your code.It seems happened at
id source_value = [sourceObject valueForKey:property_name];
NSLog debug the property_name, see what you got.

EXC_BAD_ACCESS crash when start running app?

i use linphone SDK in my application. When i start to run app crash happening immediately.
After app start it's call [Fastaddreesbook init] which called [FastAddreesBook reload] which called [FastAddreesBook loadData] which called [FastAddreesBook normalizeSipURI] and exc_bad_access Crash happen in this method:
LinphoneAddress* linphoneAddress = linphone_core_interpret_url([LinphoneManager getLc], [address UTF8String]);
Thread 1: EXC_BAD_ACCESS (code=1, address=0x0)
/* FastAddressBook.h
*
* Copyright (C) 2011 Belledonne Comunications, Grenoble, France
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifdef __IPHONE_9_0
#import <Contacts/Contacts.h>
#endif
#import "FastAddressBook.h"
#import "LinphoneManager.h"
#import "BundleLocalData.h"
#import "AppUtil.h"
#import "WebserviceUtil.h"
#import "ContactEntry.h"
#import "ContactsViewController.h"
#implementation FastAddressBook
static void sync_address_book (ABAddressBookRef addressBook, CFDictionaryRef info, void *context);
+ (NSString*)getContactDisplayName:(ABRecordRef)contact {
NSString *retString = nil;
if (contact) {
CFStringRef lDisplayName = ABRecordCopyCompositeName(contact);
if(lDisplayName != NULL) {
retString = [NSString stringWithString:(NSString*)lDisplayName];
CFRelease(lDisplayName);
}
}
return retString;
}
+ (UIImage*)squareImageCrop:(UIImage*)image
{
UIImage *ret = nil;
// This calculates the crop area.
float originalWidth = image.size.width;
float originalHeight = image.size.height;
float edge = fminf(originalWidth, originalHeight);
float posX = (originalWidth - edge) / 2.0f;
float posY = (originalHeight - edge) / 2.0f;
CGRect cropSquare = CGRectMake(posX, posY,
edge, edge);
CGImageRef imageRef = CGImageCreateWithImageInRect(image.CGImage, cropSquare);
ret = [UIImage imageWithCGImage:imageRef
scale:image.scale
orientation:image.imageOrientation];
CGImageRelease(imageRef);
return ret;
}
+ (UIImage*)getContactImage:(ABRecordRef)contact thumbnail:(BOOL)thumbnail {
UIImage* retImage = nil;
if (contact && ABPersonHasImageData(contact)) {
CFDataRef imgData = ABPersonCopyImageDataWithFormat(contact, thumbnail?
kABPersonImageFormatThumbnail: kABPersonImageFormatOriginalSize);
retImage = [UIImage imageWithData:(NSData *)imgData];
if(imgData != NULL) {
CFRelease(imgData);
}
if (retImage != nil && retImage.size.width != retImage.size.height) {
[LinphoneLogger log:LinphoneLoggerLog format:#"Image is not square : cropping it."];
return [self squareImageCrop:retImage];
}
}
return retImage;
}
- (ABRecordRef)getContact:(NSString*)address {
#synchronized (addressBookMap){
return (ABRecordRef)addressBookMap[address];
}
}
+ (BOOL)isSipURI:(NSString*)address {
return [address hasPrefix:#"sip:"] || [address hasPrefix:#"sips:"];
}
+ (NSString*)appendCountryCodeIfPossible:(NSString*)number {
if (![number hasPrefix:#"+"] && ![number hasPrefix:#"00"]) {
NSString* lCountryCode = [[LinphoneManager instance] lpConfigStringForKey:#"countrycode_preference"];
if (lCountryCode && lCountryCode.length>0) {
//append country code
return [lCountryCode stringByAppendingString:number];
}
}
return number;
}
+ (NSString*)normalizeSipURI:(NSString*)address {
NSString *normalizedSipAddress = nil;
LinphoneAddress* linphoneAddress = linphone_core_interpret_url([LinphoneManager getLc], [address UTF8String]);
if(linphoneAddress != NULL) {
char *tmp = linphone_address_as_string_uri_only(linphoneAddress);
if(tmp != NULL) {
normalizedSipAddress = [NSString stringWithUTF8String:tmp];
ms_free(tmp);
}
linphone_address_destroy(linphoneAddress);
}
return normalizedSipAddress;
}
+ (NSString*)normalizePhoneNumber:(NSString*)address {
NSMutableString* lNormalizedAddress = [NSMutableString stringWithString:address];
[lNormalizedAddress replaceOccurrencesOfString:#" "
withString:#""
options:0
range:NSMakeRange(0, lNormalizedAddress.length)];
[lNormalizedAddress replaceOccurrencesOfString:#"("
withString:#""
options:0
range:NSMakeRange(0, lNormalizedAddress.length)];
[lNormalizedAddress replaceOccurrencesOfString:#")"
withString:#""
options:0
range:NSMakeRange(0, lNormalizedAddress.length)];
[lNormalizedAddress replaceOccurrencesOfString:#"-"
withString:#""
options:0
range:NSMakeRange(0, lNormalizedAddress.length)];
return [FastAddressBook appendCountryCodeIfPossible:lNormalizedAddress];
}
+ (BOOL)isAuthorized {
//addme // return !ABAddressBookGetAuthorizationStatus || ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized;
return ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized;
}
- (FastAddressBook*)init {
if ((self = [super init]) != nil) {
addressBookMap = [[NSMutableDictionary alloc] init];
addressBook = nil;
[self reload];
}
self.needToUpdate = FALSE;
if ([CNContactStore class]) {
//ios9 or later
CNEntityType entityType = CNEntityTypeContacts;
if([CNContactStore authorizationStatusForEntityType:entityType] == CNAuthorizationStatusNotDetermined) {
CNContactStore * contactStore = [[CNContactStore alloc] init];
// nslo(#"CNContactStore requesting authorization");
[contactStore requestAccessForEntityType:entityType completionHandler:^(BOOL granted, NSError * _Nullable error) {
// LOGD(#"CNContactStore authorization granted");
}];
} else if([CNContactStore authorizationStatusForEntityType:entityType]== CNAuthorizationStatusAuthorized) {
// LOGD(#"CNContactStore authorization granted");
}
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(updateAddressBook:) name:CNContactStoreDidChangeNotification object:nil];
}
return self;
}
-(void) updateAddressBook:(NSNotification*) notif {
// LOGD(#"address book has changed");
self.needToUpdate = TRUE;
}
- (void) checkContactListForJogvoiceList {
// if (![BundleLocalData isLoadingJogvoiceContactList]) {
// [BundleLocalData setLoadingJogvoiceContactList:true];
int maxPhoneNumberSubmit = 200;
NSArray *lContacts = (NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBook);
NSMutableDictionary *phoneNumberContactsDictionary = [[NSMutableDictionary alloc] init];
NSMutableArray *allPhoneNumberList = [[NSMutableArray alloc] init];
for (id lPerson in lContacts) {
ABRecordRef person = (ABRecordRef)lPerson;
NSArray *phoneList = [AppUtil getContactPhoneList:person];
for (NSString* phoneNumber in phoneList) {
NSMutableArray* contactList = phoneNumberContactsDictionary[phoneNumber];
if (!contactList) {
contactList = [[NSMutableArray alloc] init];
}
[contactList addObject:(__bridge ABRecordRef)person];
phoneNumberContactsDictionary[phoneNumber] = contactList;
}
[allPhoneNumberList addObjectsFromArray:phoneList];
if (allPhoneNumberList.count >= maxPhoneNumberSubmit) {
[self checkContactList:allPhoneNumberList phoneNumberContactsDictionary:phoneNumberContactsDictionary];
}
}
if (allPhoneNumberList.count > 0) {
[self checkContactList:allPhoneNumberList phoneNumberContactsDictionary:phoneNumberContactsDictionary];
}
// ABAddressBookUnregisterExternalChangeCallback(addressBook, sync_address_book, self);
// [BundleLocalData setLoadingJogvoiceContactList:false];
// }
}
-(void) checkContactList:(NSMutableArray*)allPhoneNumberList phoneNumberContactsDictionary:(NSMutableDictionary*)phoneNumberContactsDictionary {
[WebserviceUtil apiGetUsersRegistered:[NSArray arrayWithArray:allPhoneNumberList]
success:^(AFHTTPRequestOperation *operation, id responseObject){
NSDictionary* response = responseObject;
for (id phoneNumber in allPhoneNumberList) {
NSNumber *status = response[phoneNumber];
if (status.intValue == 1) { // registered
NSArray* contactList = phoneNumberContactsDictionary[phoneNumber];
for (int index = 0; index < contactList.count; index++) {
ABRecordRef contact = (__bridge ABRecordRef) contactList[index];
[self saveContact:phoneNumber contact:contact];
}
}
}
[self saveAddressBook];
[allPhoneNumberList removeAllObjects];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
// nothing
}];
}
-(void) saveContact:(NSString*)phoneNumber contact:(ABRecordRef)contact {
if(contact == NULL || phoneNumber == NULL) {
return;
}
ABMultiValueRef lMap = ABRecordCopyValue(contact, kABPersonInstantMessageProperty);
if (!lMap) {
return;
}
BOOL avafoneAlready = false;
for(int i = 0; i < ABMultiValueGetCount(lMap); ++i) {
ABMultiValueIdentifier identifier = ABMultiValueGetIdentifierAtIndex(lMap, i);
CFDictionaryRef lDict = ABMultiValueCopyValueAtIndex(lMap, i);
if(CFDictionaryContainsKey(lDict, kABPersonInstantMessageServiceKey)) {
if(CFStringCompare((CFStringRef)[LinphoneManager instance].contactSipField, CFDictionaryGetValue(lDict, kABPersonInstantMessageServiceKey), kCFCompareCaseInsensitive) == 0) {
avafoneAlready = true;
}
} else {
//check domain
LinphoneAddress* address = linphone_address_new(((NSString*)CFDictionaryGetValue(lDict,kABPersonInstantMessageUsernameKey)).UTF8String);
if (address) {
if ([[ContactSelection getSipFilter] compare:#"*" options:NSCaseInsensitiveSearch] == NSOrderedSame) {
avafoneAlready = true;
} else {
NSString* domain = [NSString stringWithCString:linphone_address_get_domain(address)
encoding:[NSString defaultCStringEncoding]];
if ([domain compare:[ContactSelection getSipFilter] options:NSCaseInsensitiveSearch] == NSOrderedSame) {
avafoneAlready = true;
}
}
linphone_address_destroy(address);
}
}
CFRelease(lDict);
if(avafoneAlready) {
avafoneAlready = true;
break;
}
}
CFRelease(lMap);
if (avafoneAlready) {
return;
}
NSString *value = [NSString stringWithFormat:#"900%#", phoneNumber];
ContactEntry *entry = nil;
ABMultiValueRef lcMap = ABRecordCopyValue(contact, kABPersonInstantMessageProperty);
if(lcMap != NULL) {
lMap = ABMultiValueCreateMutableCopy(lcMap);
CFRelease(lcMap);
} else {
lMap = ABMultiValueCreateMutable(kABStringPropertyType);
}
ABMultiValueIdentifier index;
NSError* error = NULL;
CFStringRef keys[] = { kABPersonInstantMessageUsernameKey, kABPersonInstantMessageServiceKey};
CFTypeRef values[] = { [value copy], [LinphoneManager instance].contactSipField };
CFDictionaryRef lDict = CFDictionaryCreate(NULL, (const void **)&keys, (const void **)&values, 2, NULL, NULL);
if (entry) {
index = ABMultiValueGetIndexForIdentifier(lMap, entry.identifier);
ABMultiValueReplaceValueAtIndex(lMap, lDict, index);
} else {
CFStringRef label = (CFStringRef)[NSString stringWithString:(NSString*)kABPersonPhoneMobileLabel];
ABMultiValueAddValueAndLabel(lMap, lDict, label, &index);
}
if (!ABRecordSetValue(contact, kABPersonInstantMessageProperty, lMap, (CFErrorRef*)&error)) {
[LinphoneLogger log:LinphoneLoggerLog format:#"Can't set contact with value [%#] cause [%#]", value,error.localizedDescription];
CFRelease(lMap);
} else {
if (entry == nil) {
entry = [[[ContactEntry alloc] initWithData:index] autorelease];
}
CFRelease(lDict);
CFRelease(lMap);
/*check if message type is kept or not*/
lcMap = ABRecordCopyValue(contact, kABPersonInstantMessageProperty);
lMap = ABMultiValueCreateMutableCopy(lcMap);
CFRelease(lcMap);
index = ABMultiValueGetIndexForIdentifier(lMap, entry.identifier);
lDict = ABMultiValueCopyValueAtIndex(lMap,index);
// if(!CFDictionaryContainsKey(lDict, kABPersonInstantMessageServiceKey)) {
/*too bad probably a gtalk number, storing uri*/
NSString* username = CFDictionaryGetValue(lDict, kABPersonInstantMessageUsernameKey);
LinphoneAddress* address = linphone_core_interpret_url([LinphoneManager getLc]
,username.UTF8String);
if(address){
char* uri = linphone_address_as_string_uri_only(address);
CFStringRef keys[] = { kABPersonInstantMessageUsernameKey, kABPersonInstantMessageServiceKey};
CFTypeRef values[] = { [NSString stringWithCString:uri encoding:[NSString defaultCStringEncoding]], [LinphoneManager instance].contactSipField };
CFDictionaryRef lDict2 = CFDictionaryCreate(NULL, (const void **)&keys, (const void **)&values, 2, NULL, NULL);
ABMultiValueReplaceValueAtIndex(lMap, lDict2, index);
if (!ABRecordSetValue(contact, kABPersonInstantMessageProperty, lMap, (CFErrorRef*)&error)) {
[LinphoneLogger log:LinphoneLoggerLog format:#"Can't set contact with value [%#] cause [%#]", value,error.localizedDescription];
}
CFRelease(lDict2);
linphone_address_destroy(address);
ms_free(uri);
}
// }
CFDictionaryRef lDict = CFDictionaryCreate(NULL, (const void **)&keys, (const void **)&values, 2, NULL, NULL);
ABMultiValueReplaceValueAtIndex(lMap, lDict, index);
CFRelease(lMap);
}
CFRelease(lDict);
}
- (void)saveAddressBook {
if( addressBook != nil ){
NSError* err = nil;
if( !ABAddressBookSave(addressBook, (CFErrorRef*)err) ){
Linphone_warn(#"Couldn't save Address Book");
}
}
}
- (void)reload {
NSLog(#"Fastadd reload first is loaded");
CFErrorRef error;
// create if it doesn't exist
if (addressBook == nil) {
addressBook = ABAddressBookCreateWithOptions(NULL, &error);
}
if (addressBook != nil) {
__weak FastAddressBook *weakSelf = self;
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
if (!granted) {
Linphone_warn(#"Permission for address book acces was denied: %#", [(__bridge NSError *)error description]);
return;
}
ABAddressBookRegisterExternalChangeCallback(addressBook, sync_address_book, (__bridge void *)(weakSelf));
dispatch_async(dispatch_get_main_queue(), ^(void) {
[weakSelf loadData];
});
});
} else {
Linphone_warn(#"Create AddressBook failed, reason: %#", [(__bridge NSError *)error localizedDescription]);
}
/*
//method1
if(addressBook != nil) {
ABAddressBookUnregisterExternalChangeCallback(addressBook, sync_address_book, self);
CFRelease(addressBook);
addressBook = nil;
}
NSError *error = nil;
addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
if(addressBook != NULL) {
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
ABAddressBookRegisterExternalChangeCallback (addressBook, sync_address_book, self);
[self loadData];
});
} else {
[LinphoneLogger log:LinphoneLoggerError format:#"Create AddressBook: Fail(%#)", [error localizedDescription]];
}
*/
}
- (void)loadData {
ABAddressBookRevert(addressBook);
#synchronized (addressBookMap) {
[addressBookMap removeAllObjects];
//melog
NSLog(#"Fastadd loaddata is loaded");
NSArray *lContacts = (NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBook);
for (id lPerson in lContacts) {
// Phone
{
ABMultiValueRef lMap = ABRecordCopyValue((ABRecordRef)lPerson, kABPersonPhoneProperty);
if(lMap) {
for (int i=0; i<ABMultiValueGetCount(lMap); i++) {
CFStringRef lValue = ABMultiValueCopyValueAtIndex(lMap, i);
CFStringRef lLabel = ABMultiValueCopyLabelAtIndex(lMap, i);
CFStringRef lLocalizedLabel = ABAddressBookCopyLocalizedLabel(lLabel);
NSString* lNormalizedKey = [FastAddressBook normalizePhoneNumber:(NSString*)lValue];
NSString* lNormalizedSipKey = [FastAddressBook normalizeSipURI:lNormalizedKey];
if (lNormalizedSipKey != NULL) lNormalizedKey = lNormalizedSipKey;
addressBookMap[lNormalizedKey] = lPerson;
CFRelease(lValue);
if (lLabel) CFRelease(lLabel);
if (lLocalizedLabel) CFRelease(lLocalizedLabel);
}
CFRelease(lMap);
}
}
// SIP
{
ABMultiValueRef lMap = ABRecordCopyValue((ABRecordRef)lPerson, kABPersonInstantMessageProperty);
if(lMap) {
for(int i = 0; i < ABMultiValueGetCount(lMap); ++i) {
CFDictionaryRef lDict = ABMultiValueCopyValueAtIndex(lMap, i);
BOOL add = false;
if(CFDictionaryContainsKey(lDict, kABPersonInstantMessageServiceKey)) {
CFStringRef contactSipField = (CFStringRef)[LinphoneManager instance].contactSipField;
if (!contactSipField) {
contactSipField = CFStringCreateWithCString(NULL, "SIP", kCFStringEncodingMacRoman);
}
if(CFStringCompare(contactSipField, CFDictionaryGetValue(lDict, kABPersonInstantMessageServiceKey), kCFCompareCaseInsensitive) == 0) {
add = true;
}
} else {
add = true;
}
if(add) {
CFStringRef lValue = CFDictionaryGetValue(lDict, kABPersonInstantMessageUsernameKey);
NSString* lNormalizedKey = [FastAddressBook normalizeSipURI:(NSString*)lValue];
if(lNormalizedKey != NULL) {
addressBookMap[lNormalizedKey] = lPerson;
} else {
addressBookMap[(NSString*)lValue] = lPerson;
}
/*
NSString *lValue =
(__bridge NSString *)CFDictionaryGetValue(lDict, kABPersonInstantMessageUsernameKey);
NSString *lNormalizedKey = [FastAddressBook normalizeSipURI:lValue];
if (lNormalizedKey != NULL) {
[addressBookMap setObject:(__bridge id)(lPerson)forKey:lNormalizedKey];
} else {
[addressBookMap setObject:(__bridge id)(lPerson)forKey:lValue];
}
*/
}
CFRelease(lDict);
}
CFRelease(lMap);
}
}
}
CFRelease(lContacts);
}
[[NSNotificationCenter defaultCenter] postNotificationName:kLinphoneAddressBookUpdate object:self];
}
void sync_address_book (ABAddressBookRef addressBook, CFDictionaryRef info, void *context) {
FastAddressBook* fastAddressBook = (FastAddressBook*)context;
[fastAddressBook loadData];
}
- (void)dealloc {
ABAddressBookUnregisterExternalChangeCallback(addressBook, sync_address_book, self);
CFRelease(addressBook);
[addressBookMap release];
[super dealloc];
}
#end
P.S.:
-i use non-arc project
-zombie enable too but nothing change.
-Ivalue is will and thats because crash happening.
Debug Console:
warning: could not execute support code to read Objective-C class data in the process. This may reduce the quality of type information available.
LinphoneAddress* linphoneAddress = linphone_core_interpret_url([LinphoneManager getLc], [address UTF8String]);
address is nil. Figure out why that is and you've got your crash source. It likely should be nil as it is probably an optional field in the original record.
That code is a bit of a mess, btw. It isn't following the standard patterns (lots of method prefixed with get, for example). It really should be modernized and have ARC enabled.

I have a class I want some method transfer to an array's object

Like the title said: I have a ObjcClass
I want some thing can be reused ,
because the class may have
-(void)test1:xxx -(void)test2:xxx argu:yyy
I don't want to do that
[dispatchArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[obj test2:xxx argu:yyy];
}];
example:
- (void)test:(NSString *)argument1 {
NSArray *dispatchArray = #[];//If the array is initialized with multiple objects
//I want each object to call the "test:" method unlike the following
// [dispatchArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
// [obj performSelector:#selector(test:) withObject:argument1];
// // or [obj test:argument1];
// }];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[_services enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL * stop) {
if ([obj respondsToSelector:_cmd]) {
[obj application:application didFinishLaunchingWithOptions:launchOptions];
}
}];
return YES;
}
like this ,UIApplicationDelegate has a number of method ,I don't want write [obj application:application didFinishLaunchingWithOptions:launchOptions]; or [obj applicationWillResignActive:application]; at every method,On the contrary I hope that method like [obj respondsToSelector:_cmd] ,that I can propose as a general method like [obj invokeWithMethod:_cmd arguments:_VA_LIST];
Whether these methods can be optimized,because they do the same thing to different method
The methods you app delegate has been implemented, you should implement as before. To the method in UIApplicationDelegate protocol which your app delegate did not implement, you can use message forwarding to achieve your target. Override the message forwarding methods of your app delegate as below:
- (BOOL)respondsToSelector:(SEL)aSelector {
struct objc_method_description desc = protocol_getMethodDescription(objc_getProtocol("UIApplicationDelegate"), aSelector, NO, YES);
if (desc.name != nil) {
return YES;
}
return [super respondsToSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation {
SEL selector = [anInvocation selector];
struct objc_method_description desc = protocol_getMethodDescription(objc_getProtocol("UIApplicationDelegate"), selector, NO, YES);
if (desc.name != nil) {
[_services enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if ([obj respondsToSelector:selector]) {
[anInvocation invokeWithTarget:obj];
}
}];
}
}
Get the return values:
NSMutableArray *returnValues = [NSMutableArray array];
[_services enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
id returnValue = [NSNull null];
if ([obj respondsToSelector:selector]) {
[anInvocation invokeWithTarget:obj];
const char *returnType = anInvocation.methodSignature.methodReturnType;
if( !strcmp(returnType, #encode(void)) ){
//If the return value is `void`, just set returnValue = [NSNull null]
} else if( !strcmp(returnType, #encode(id)) ){
// if the return type is derived data types(`id`)
[anInvocation getReturnValue:&returnValue];
}else{
//if the return value is basicdata type
NSUInteger length = [anInvocation.methodSignature methodReturnLength];
void *buffer = (void *)malloc(length);
[anInvocation getReturnValue:buffer];
if( !strcmp(returnType, #encode(BOOL)) ) {
returnValue = [NSNumber numberWithBool:*((BOOL*)buffer)];
} else if( !strcmp(returnType, #encode(NSInteger)) ){
returnValue = [NSNumber numberWithInteger:*((NSInteger*)buffer)];
}
returnValue = [NSValue valueWithBytes:buffer objCType:returnType];
}
}
// If the `obj` can not responds to selector, or the return value is void(nil), we set the `returnValue = [NSNull null]`
[returnValues addObject:returnValue];
}]
Looks like you just want to loop through the objects in the array. This is not very Type safe. All objects must provide a "test" method. If they're all the same Class that would be better than using NSObject.
for (NSObject *obj in dispatchArray) {
[obj performSelector:#selector(test:) withObject:argument1];
}

Resources