Objective-C method_exchangeImplementations result is not as expected - objective-c

I'm learning Objective-C runtime, and try to use method_exchangeImplementations to exchange addObject: method and removeObject: method of NSMutableArray.
My code like this:
int main(int argc, const char * argv[]) {
#autoreleasepool {
Method removeMethod = class_getInstanceMethod(NSMutableArray.class, #selector(removeObject:));
Method addMethod = class_getInstanceMethod(NSMutableArray.class, #selector(addObject:));
method_exchangeImplementations(addMethod, removeMethod);
NSMutableArray *array = [[NSMutableArray alloc] init];
NSObject *obj = [[NSObject alloc] init];
[array removeObject:obj];
NSLog(#"%lu", (unsigned long)array.count); // expect print 1, actual print 1
[array addObject:obj];
NSLog(#"%lu", (unsigned long)array.count); // expect print 0, actual print 2
}
return 0;
}
I expect exchange add/remove function, but seems like only removeObject: has been exchange to addObject: , addObject: still is addObject to array, now I have two addObject method of NSMutableArray
I'm not sure the reason. I try to exchange other method like uppercaseString/lowercaseString of NSString, that work correct.

OK, I solved problem. Thanks #Willeke for the tip.
The real class of my array is not NSMutableArray, so use NSMutableArray.class in class_getInstanceMethod can't get correct method. Use [array class] is the answer.
int main(int argc, const char * argv[]) {
#autoreleasepool {
NSMutableArray *array = [[NSMutableArray alloc] init];
Method removeMethod = class_getInstanceMethod([array class], #selector(removeObject:));
Method addMethod = class_getInstanceMethod([array class], #selector(addObject:));
method_exchangeImplementations(addMethod, removeMethod);
NSObject *obj = [[NSObject alloc] init];
[array removeObject:obj];
NSLog(#"%lu", (unsigned long)array.count); // expect print 1, actual print 1
[array addObject:obj];
NSLog(#"%lu", (unsigned long)array.count); // expect print 0, actual print 0
}
return 0;
}

Related

why is this not printing out a grocery list? NSMuteableArray For fast loop enumeration

#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
#autoreleasepool {
NSMutableArray *groceries;
NSString *a = (#"loaf of bread");
NSString *b = (#"stick of butter");
NSString *c = (#"big ass cookie");
[groceries addObject:a];
[groceries addObject:b];
[groceries addObject:c];
for (NSString *d in groceries){
NSLog(#"%#", d);
}
}
return 0;
}
Why is this not working? What is wrong? Thanks.
I cannot seem to figure it out at this moment, the for loop defiantly seems to be the hangup.
While you didn't initialize NSMutableArray, it's is nil. Adding object to non-initialized mutable array always give nil.
Firstly you need to initialize groceries:
NSMutableArray *groceries = [NSMutableArray new];
or more liked by me way:
NSMutableArray *groceries = #[].mutableCopy;
In your case, for example, you can declare so:
NSMutableArray *groceries = #[#"loaf of bread", #"stick of butter", #"big ass cookie"].mutableCopy;

Objective-C Why is this not working?

#import <Foundation/Foundation.h>
int main(int argc, const char * argv[])
{
#autoreleasepool {
NSMutableString *outputStringSet = [[NSMutableString alloc] init];
NSMutableString *outputStringArray = [[NSMutableString alloc] init];
NSMutableSet *mySet = [[NSMutableSet alloc] init];
NSMutableArray *myArray = [[NSMutableArray alloc] initWithCapacity: 10];
int userInput;
NSLog(#"Enter 10 numbers");
for( int i = 0; i < 10; i++) {
scanf("%i", &userInput);
NSNumber *input = [[NSNumber alloc] initWithInt: userInput];
[myArray addObject:input];
if([mySet member: input]) {
[mySet addObject: input];
}
}
for (int k = 0; k < [myArray count]; k++) {
[outputStringArray appendFormat:#"%#, ", [myArray objectAtIndex:k]];
}
NSLog(#"%#", [outputStringArray substringToIndex:[outputStringArray length] - 2]);
for (int j = 0; j < [myArray count]; j++) {
if([mySet containsObject: [myArray objectAtIndex:j]]) {
[outputStringSet appendFormat:#"%#, ", [myArray objectAtIndex:j]];
}
NSLog(#"%#", outputStringSet);
}
}
return 0;
}
Code above prints the array but not the appropriate object in the set
Why?
Please explain clearly. I am a bit of a noob, and couldnt find the answer anywhere else.
thanks
if([mySet member: input]) {
[mySet addObject: input];
}
You're adding the object to the set if it’s already in it. You want the reverse: add the object if it's not in it.
Thus:
if ( ! [mySet member:input] )
[mySet addObject:input];
By the way, you should use containsObject: instead of member: in your test:
containsObject:
Returns a Boolean value that indicates whether a given
object is present in the set.
- (BOOL)containsObject:(id)anObject
Edit: you don't even need to test if the object is already in the set before adding it. After all, that's the main purpose of a NSSet: to ensure uniqueness of its objects. So if you add an object twice, the second call will silently be ignored, as the object is alreay in it.
Your set is empty because of
if([mySet member: input]) {
[mySet addObject: input];
}
member:
Determines whether the set contains an object equal to a given object,
and returns that object if it is present.

what is the use of stringsByAppendingPaths

#import <Foundation/Foundation.h>
int main(int argc, const char * argv[])
{
#autoreleasepool {
NSArray *array = [[NSArray alloc] initWithObjects:#"/tmp/1.txt" ,#"/tmp/2.txt", nil];
NSLog(#"%#", array);
NSString *result = [[NSString alloc] init];
NSArray *array2 = [[NSArray alloc]initWithArray:[result stringsByAppendingPaths:array]];
NSLog(#"%#", array2);
}
return 0;
}
The argument we provide to stringsByAppendingPaths: is an array and so is the return type. So what is the use of this NSString method?
Well, you're appending empty string (result), so it doesn't make much sense. But if your receiver contains say /tmp and the array contains 1.txt and 2.txt, getting the array /tmp/1.txt and /tmp/2.txt makes sense.

NSMutableArray : getObject method returning null

This program should take 5 NSString's in input and print them.
I put them in an NSMutableArray.
During the loop if I try to print the NSString's they're printed correctly.
But when I try getting the objects from the array, I don't know why it returns null.
So if I try printing them in the second loop, they're all null.
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[])
{
NSAutoreleasePool* pool=[[NSAutoreleasePool alloc]init];
NSMutableArray* array;
NSString* str=[[NSString alloc]init];
char* cstr;
cstr=(char*)calloc(100,sizeof(char));
for(int i=0;i<5;i++)
{
fgets(cstr,100,stdin);
str=[NSString stringWithUTF8String:cstr];
[array addObject : str];
}
for(int i=0;i<5;i++)
{
str=[array objectAtIndex:i];
NSLog(#"%#",str);
}
[pool drain];
return 0;
}
In this line:
NSMutableArray* array;
You are declaring array, to be an NSMutableArray, but you're not setting the pointer to anything, so array is just nil.
You want to do this instead to allocate and initialize an actual instance of NSMutableArray and assign it to that pointer:
NSMutableArray* array = [[NSMutableArray alloc] init];
You haven't initialized your array. You should put: NSMutableArray *array = [[NSMutableArray alloc] init];
or better yet: NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:5];

Method Creates an Array with 11 objects, All Out of Scope, Unrecognized Selector Results

Okay, so, I'm doing a simple lookup. I have an array of NSString objects and a string to search for in the array's elements.
It all seems to work up until I try to add a match to a new mutable array made to hold the search results. The stringHolder variable gets the string, and resultsCollectorArray even get the right number of new elements, but each element is empty and "out of range". Here's the method:
#implementation NSArray (checkForString)
-(NSMutableArray *) checkForString: (NSString *) matchSought
{
long unsigned numberofArrayElements;
long unsigned loop = 0;
NSRange searchResults;
NSMutableArray * resultCollectorArray = [[NSMutableSet alloc] init];
id stringHolder;
numberofArrayElements = [self count];
while (loop < numberofArrayElements) {
searchResults.length = 0;
searchResults = [[self objectAtIndex: loop] rangeOfString: matchSought options:NSCaseInsensitiveSearch];
if (searchResults.length > 0) {
stringHolder = [self objectAtIndex: loop];
[resultCollectorArray addObject: stringHolder];
}
loop++;
}
return [resultCollectorArray autorelease];
}
Once we get back to the main portion of the program, I get an unrecognized selector sent to the mutable array that was supposed to receive the result of the method. Here's the main section:
#import <Foundation/Foundation.h>
#import "LookupInArray.h"
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSString *testString = [[NSString alloc] initWithString: #"ab"];
NSMutableString * resultString = [[NSString alloc] init];
NSArray * theArray = [[NSArray alloc] initWithObjects: ..., nil]; // Actual code has the objects
NSMutableArray *resultArray = [[NSMutableArray alloc] init];
NSUInteger arrayCount = 0;
unsigned long loops = 0;
resultArray = [theArray checkForString: testString];
arrayCount = [resultArray count];
while (loops < arrayCount){
resultString = [resultArray objectAtIndex: loops]; // Here's where we get the unrecognized selector.
NSLog(#"%#", resultString);
loops++;
}
[pool drain]; // Also, I'll release the objects later. I just want to get what's above working first.
return 0;
}
I've searched the other answers (for hours now), but didn't seen anything that solved the issue.
Any and all help would be really appreciated.
And thanks beforehand.
NSMutableArray * resultCollectorArray = [[NSMutableSet alloc] init]; is so incorrect. You are creating a mutable set and assigning it to a mutable array.
You are getting unrecognized selector because objectAtIndex: is not a valid selector for NSMutableSet. Make that statement,
NSMutableArray * resultCollectorArray = [[NSMutableArray alloc] init];
A Better way
NSArray * filteredArray = [array filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"SELF contains[cd] %#", searchString]];
You can directly filter the array using predicates. This way you do this in a single step. :)