I have the next NSMutableArray:
Product[0] {
name => val1,
Price => pricevalue 1
}
Product[1] {
name => val2,
Price => pricevalue2
}
I want to search for: name = val2 and return the index of product, so 1.
Use like this
NSIndexSet *indices = [array
indexesOfObjectsPassingTest:^(id obj, NSUInteger idx, BOOL *stop) {
return [[obj objectForKey:#"name"] isEqualToString:#"val2"];
}];
Happy coding.........
__block NSUInteger index = NSUIntegerMax;
[products enumerateObjectsUsingBlock: ^ (Product* product, NSUInteger idx, BOOL* stop) {
if([product.name isEqualToString:#"val2"])
{
index = idx;
*stop = YES;
}
}];
Edit: Ravindra's solution is more elegant!
Related
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];
}
From the following array I want to fetch dictionary with message_id = 1. Basically I want to get the indexpath of the cell whose message_id == 1.
<__NSArrayM 0x17d918d0>(
<__NSArrayM 0x17faa070>(
{
chatStatus = sent;
date = "Feb 05, 2016";
from = "";
height = "17.000000";
isOutgoing = yes;
"message_id" = "1";
time = "02:39 PM";
to = "";
width = "95.000000";
},
{
chatStatus = sent;
date = "Feb 05, 2016";
from = "";
height = "17.000000";
isOutgoing = yes;
"message_id" = "2";
time = "02:39 PM";
to = "";
width = "95.000000";
},
)
)
I think you should look around the NSArray's method
-[NSArray indexesOfObjectsPassingTest:^BOOL(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop)]
by doing something like that :
NSMutableArray *indexPaths = [NSMutableArray array];
[myArray enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger firstIndex, BOOL * _Nonnull stop) {
NSArray *messages = (NSArray*)obj;
NSIndexSet *indexes = [messages indexesOfObjectsPassingTest:^BOOL(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSDictionary *message = (NSDictionary*)obj;
if (message.message_id == 1) {
return YES;
}
return NO;
}];
[indexes enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL * _Nonnull stop) {
[indexPaths addObject:[NSIndexPath indexPathForRow:idx inSection:firstIndex]];
}];
})];
It's seems a bit tricky, and I did it quickly so that I think you could improve it. The idea is to enumerate through your first array, and then use "indexesOfObjectsPassingTest" to get all indexes for your matching objects. And then you and your indexPaths by going through the enumeration of the NSIndexSet object :)
I think you could even do it recursively, so that you won't be limited by the depth of your arrays which is, here, only 2 :/
Hope it helped \o
Bilkix.
My application crashed at following codes:
NSMutableArray* array = [dict objectForKey:key];
if (array)
{
__block BOOL find = NO;
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSString* word = (NSString*)obj;
if ([word isEqualToString:#"jerry"]) {
*stop = YES;
find = YES;
}
}];
And the crash information is:
1 CoreFoundation 0x2ecd30f2 __53-[__NSArrayM enumerateObjectsWithOptions:usingBlock:]_block_invoke (in CoreFoundation) + 90
2 CoreFoundation 0x2ecd3024 -[__NSArrayM enumerateObjectsWithOptions:usingBlock:] (in CoreFoundation) + 232
I can't figure it out, anyone knows how to solve this problem?
try to use:
[word isEqualToString:#"jerry"]
Try this:
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSString* word = (NSString*)obj;
if ([word isEqualToString:#"jerry"]) {
stop = YES;
find = YES;
}
You are comparing strings in the wrong way.
Try this
NSMutableArray* array = [NSMutableArray arrayWithArray:[dict objectForKey:key]];
if (array)
{
__block BOOL find = NO;
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSString* word = (NSString*)obj;
if ([word isEqualToString:#"jerry"]) {
*stop = YES;
find = YES;
}
}];
My money is on your array turning out to not actually be an array. When you create and set your array from the object in dict, check to see that [dict objectForKey:key] is actually an array.
NSMutableArray* array = [dict objectForKey:key];
NSLog(#"class of array: %#", [[dict objectForKey:key] class]);
How can I enumerate an array starting at the center of the array?
#implementation NSArray (Extensions)
- (void)enumerateFromCenterGoBothWaysUsingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))block
{
NSMutableArray *copy = [self mutableCopy];
BOOL shouldStop = NO;
while([copy count] > 0 && shouldStop == NO)
{
NSUInteger index = [copy count] / 2;
id obj = copy[index];
[copy removeObject:obj];
block(obj, index, &shouldStop);
}
}
#end
I am trying to search an NSMutableArray for a string. I am using containsObject: currently but it looks like this is case sensitive. I need to search for all combinations of the given string (trip). Any ideas would be greatly appreciated.
if ([self.theArray containsObject:trip]) {
}
Not that hard:
BOOL found = NO;
for (NSString* str in self.theArray) {
if ([str caseInsensitiveCompare:trip] == NSOrderedSame) {
found = YES;
break;
}
}
Create a category for NSArray and add this function in there.
- (BOOL)containsStringCaseInsensitive:(NSString *)key {
key = [key lowercaseString];
for (int i = ([self count] - 1); i >= 0; i--) {
NSObject * obj = [self objectAtIndex:i];
if ([obj isKindOfClass:[NSString class]]) {
NSString * strInArray = [(NSString *)obj lowercaseString];
if ([key isEqualToString:strInArray]) {
return YES;
}
}
}
return NO;
}
How about a block:
__block trip = #"blah";
if (NSNotFound!=[self.theArray indexOfObjectPassingTest:^(id obj, NSUInteger idx, BOOL *stop)
{
if (NSOrderedSame==[(NSString *)obj caseInsensitiveCompare:trip])
{
stop=YES;
return YES;
}
return NO;
}])
{
NSLog(#"It's a MATCH!");
}