Quick way to tell what objects NSArray contains - objective-c

I'm currently working with someone else code, so i have a question is there a way to quickly tell what objects i have in NSArray.
In code i have for example:
Someclassobj.arr
And i know there is an array as a property in Someclassobj and of course i can see the definition of it, but still dont know what objects are inside. Could be NSString, NSDictionary,ObjectDefinedByUSer... How to quicly tell?
There is a method to check classes? If i execute:
id someUnknownObj = [Someclassobj.arr objectAtIndex:0];
How to check it? (i know isKindOfClass isMemberOfClass methods, but its doesn't work for me).
Of course there is doesn't have to be code method, could be something like option+click.

Will do the trick:
NSLog(#"%#",yourArray);
If you want to avoid this kind of stuff:
1) Put a breakpoint as soon as the NSArray has the objects.
2) Go to the Console on Xcode and do:
po yourArray
A great article about using the console in Xcode here.

you can do stk like this :
NSArray *arr; // Array with random stuff
for (id elt in arr) {
if ([elf iskindOfClass:[NSString class]])
NSLog(#"Object = NSString);"
}

Related

NSArray create with some elements plus another NSArray

I am trying to use model inheritance on realm. So I minded up using the code below to override and also call super method.
+ (NSArray *)requiredProperties {
return #[[super requiredProperties], #"thisIsRequired",#"thisIsAlsoRequired"];
}
So the question: is it OK to create an NSArray on the fly while also using another NSArray and some more elements:
NSArray *mySecondArray = #[myFirstArray, #"andSomeExtras", #"alsoMoreExtras"];
What I have been expecting is; first element of mySecondArray should be the first element of myFirstArray. Second element of mySecondArray should be the second element of myFirstArray and so on. (size of myFirstArray) +1 th element of mySecondArray should be #"thisIsRequired" .
Or I am making up some kind of magix?
Well, as you can see I am new to the stuff and I might be confused.
In general, it is okay to instantiate such heterogeneous arrays with Foundation. It's just not what you want here. In your example, you would end up with the following instead:
NSArray *myFirstArray = #[#"firstsFirstsElement", #"firstsSecondElement"];
NSArray *mySecondArray = #[myFirstArray, #"andSomeExtras", #"alsoMoreExtras"];
/* =>
#[
#[#"firstsFirstsElement", #"firstsSecondElement"],
#"andSomeExtras",
#"alsoMoreExtras",
]
*/
You're looking for - arrayByAddingObjectsFromArray:. You can use it like seen below:
+ (NSArray *)requiredProperties {
return [super.requiredProperties arrayByAddingObjectsFromArray:#[
#"thisIsRequired",
#"thisIsAlsoRequired",
]];
}
Yes it is Ok, as long as you will remember what you are doing anywhere in your code.
However you usually reserve the use of NSArray for a homogeneous collection of objects and use NSDictionary, or better your own DTO class, for heterogeneous aggregation of data.
NSArray official documentation show a similar example in the section dedicated to the method arrayWithObjects:
NSArray is really an array of id, even with generics enabled.
This other link about Objective C generics may also help understand the nature of the raw NSArray class.
Why not use NSMutableArray and just add the objects?
NSMutableArray *mySecondArray = [myFirstArray mutableCopy];
[mySecondArray addObject:#"andSomeExtras"];
[mySecondArray addObject:#"alsoMoreExtras"];

Understanding Objective-C method value passing

Lets say I have in viewDidLoad:
NSMutableArray *entries = [NSMutableArray array];
[self doSomethingWithArray:entries];
NSLog(#"%#", entries);
Then in method I have:
- (void)doSomethingWithArray:(NSMutableArray *)entries
{
// create some custom data here, lets say - Something *something...
[entries addObject:something];
}
How is it possible that entries (one at the top) now (after method is finished) contain object something, since object "something" is not added to property or instance variable, and nslog will log class "Something" ? And doSomethingWithArray doesn't return anything since its "void".
I have encountered this for first time and dunno if there is any name of this appearance ?
I have seen this for second time in some examples and really dunno how its done.
If anyone could explain this a bit whats happening here I would be very very grateful.
Thank you a lot.
Because Objective-C instances are passed by reference (as you can tell by the * pointer syntax). You basically pass the address of the array to the doSomethingWithArray: method. In that method you add something to the array referenced by that address. And of course once the method returns, your array will contain that new object.
When you are adding the something object to the array, the array always retains it i.e it maintains copy of the Something object.
So NSLog prints the something.
Hope that helps.

Objective C Keyword 'in'

Im having some problems understanding some code in a programme I have inherited.
CGPoint tapLocation = [gesture locationInView:self.view];
for (UIView *view in self.view.subviews){
if (!CGRectContainsPoint(view.frame, tapLocation)){
//do something
}
}
The problem is that I have no idea what the keyword 'in' is doing. I've searched around and can only find some obscure reference to it and a post here.
The post says that:
in: argument is an input argument only and won’t be referenced later
I don't really see how this applies to the code above. Any help would be greatly appreciated.
I think apple calls this fast enumeration.
In other languages a similar functionality is provided by a "for each"-loop.
The "in" you're seeing there is part of Fast Enumeration.
Here is some documentation for it.
EDIT: And Derek pointed out another bit of documentation in his comment below.
It's a succinct way to iterate through a collection. Where it says:
for (object in collection)
it means "this code happens once for each object in the collection".
The in in the link you've specified in your question is entirely different from the in in the for loop. The farmer comes under #encoding and the later comes in the context of for loops. This kind of for loop is called for-each loop in general, and in Objective-C it is called fast enumeration.
It creates an enumerator automatically for you such that you can iterator over the collection. So the collection has to conform to NSFastEnumeration.
in is used to iterete through an array.
For instance:
NSArray *values = [NSArray arrayWithObjects:#"val1", #"val2", #"val3", nil];
for (NSString *val in values) {
NSLog(#"Value = '%#'", val);
}
Basically, this is an extension of the for loop built for objective-c.
Think of this code like this:
for (NSArray *arr = UIViewGetSubviews(UIViewControllerGetView(self)), i = 0; i < arr.count; i++) {
}
Note that the actual implementation uses a NSEnumerator, not a for with integer variable loop.

Subclassing in Objective-C

I'm a bit new to Objective-C, and I've been trying to do something that apparently isn't allowed, even though it's common practice in other languages (I think).
As a specific example, I want to subclass NSMutableArray to make a SortedMutableArray that always maintains itself in a sorted state. So I subclassed NSMutableArray in the usual manner, adding a NSComparator property that determines the sort order. I overrode the addObject: method to insert objects in a sorted manner:
- (void) addObject:(id)anObject {
for (int i = 0; i < [self count]; ++i) {
NSComparisonResult result = (NSComparisonResult)self.comparator([self objectAtIndex:i], anObject);
if (result == NSOrderedDescending || result == NSOrderedSame) {
[super insertObject:anObject atIndex:i];
break;
}
else {
if (result != NSOrderedAscending) {
[NSException raise:#"InvalidBlockException" format:#"Block must return one of NSOrderedDescending, NSOrderedAscending, or NSOrderedSame"];
}
}
}
}
and everything compiles great. But when I run the program, I get an error indicating that insertObject:atIndex: is now abstract and needs to be implemented. Reading the documentation, it lists several methods that must be implemented in any subclass of NSMutableArray, one of which is indeed insertObject:atIndex:. But I don't need to change the functionality of insertObject:atIndex:; I want it to word exactly as it does in NSMutableArray. Is there a way that I can do this (in general, too, not just for this specific problem)? Why must certain methods be implemented in subclasses like this? Doesn't that kind of defeat one of the purposes of inheritance, code reuse? I've never seen anything like this in other languages, where a method is concrete in a superclass but becomes abstract when it is subclassed. Does this pattern/concept have a name?
Thanks in advance for any help, and I'm sorry if I'm duplicating another question, but I didn't know what to search for other than "subclass" in the objective-c tag, which gave too many results to find what I was looking for.
Bad idea. NSArray is actually a class cluster (which is our word for [essentially] an abstract factory). This means that when you alloc/init an NSArray, you don't actually get an NSArray back. You get (usually) an NSCFArray, which is a private subclass.
NSMutableArray is the same deal (it's abstract). When you alloc/init an NSMutableArray, you get an NSCFArray back that has a little internal mutable bit flipped.
The upshot of this is that subclass a class cluster is generally discouraged, because it's a bit more complex than just creating a normal subclass.
What I would recommend is to instead check out the CHDataStructures framework, which has a whole bunch of data structures that do what you're looking for already.
See Dave DeLong's post about why this is a not a good idea.
If you really want to do something like this, you could try, uhmm, "fake-subclassing" it.
in the .h file,
...
NSMutableArray *mutableArray;
...
#property (nonatomic, retain) NSMutableArray *mutableArray;
...
- (void) addObject:(id)anObject;
in the .m file,
...
#synthesize mutableArray;
...
- (void) addObject:(id)anObject {
[mutableArray addObject:id];
[mutableArray sortUsingSelector:#selector(yourSortingSelector);
}
- (NSMutableArray)mutableArray {
return mutableArray;
}
...
Which works and everything. My colleague did a similar class to this before (we were objective-c noobs at the time, about 2-3 weeks into learning how to code).
What I would recommend, however, is to use a Key-Value Observing approach if you can. Try to listen in whenever an element is added, and sort your array when you get the notification. I haven't done this to an NSMutableArray before though, so I don't know how this will work or if it even will.
My 2 cents, hope it helps. Happy holidays! ^_^
You shouldn't be subclassing NSMutableArray, look up categories. It provides a way to add newer methods to classes
apple's link to categories

Question regarding programming structure of a recursive method

I have this method and it's kind of really big so I can't include it in this post. It takes an array as parameter and tests its objects (NSStrings). Sometimes -but not always-, the method calls itself with an array containing one of those strings. If every test is passed, then the NSString is sent to another method which processes it. This all works fine but now I'm working on a different approach. I want to call the method and let it return an array of all NSStrings that passed the test successfully. But since the method calls itself I don't really know how to do this. Instead of processing it, I could add all successfully tested NSStrings to an array but that array would then needed to be accessible in all methods. What is recommended here? I would like to avoid public variables..
- (void)doStuff: (NSArray *)array { //A quick (very short) example of what I have now.
for (NSString *string in array) {
if ([string isEqualToString: #"test"])
[self doStuff: [NSArray arrayWithObject: #"test2"]];
else
[self processStuff: string];
}
}
You can add a mutable array as one of its parameters and add the result there:
- (void)doRecursiveWithData:(NSArray *)array storeResultsIn:(NSMutableArray *)results {
if ( shoudGoDeeper )
[self doRecursiveWithData:(your new array)];
else
[results addObject:(whatever you want to store)]; // or use another method to so so
}
I know your example is just that, an example, but maybe it's worth thinking about how you can go without the recursion - in many ways that's easily doable and often performs better.