NSArray/NSDictionary: case insensitive element lookup? [duplicate] - ios

This question already has answers here:
Case insensitive indexOfObject for NSArray
(4 answers)
Closed 9 years ago.
Is there a way to use indexOfObject: of NSArray or objectForKey: of NSDictionary without case sensitive?
So if I have an array:
#[#"Apple", #"Banana", #"Peach"]
Then
[array indexOfObject:#"apple"]
can give me 0?
Thanks

This is possible with a lot if extra work and its a bad idea. Case sensitivity is a human idea. When keys in dictionaries are strings (normally they should be) the difference between Apple and apple is a different unichar and a different hash value.
Attempting to do this the hard way would degrade performance .
That said, you might have a valid reason to do it, in which case, you could get the array of all keys, do a containsObject with caseInsensitiveCompare then use the object at index matching. But you might still find nothing.
If your keys are coming from user input or JSON or something, you might do well to sanitize them or otherwise normalize them first.

Related

iOS - Why Does It Work When I Compare Two NSNumbers With "=="?

In my app, I accidentally used "==" when comparing two NSNumber objects like so:
NSNumber *number1;
NSNumber *number2;
Later on, after these objects' int values were set, I accidentally did this:
if (number1 == number2) {
NSLog(#"THEY'RE EQUAL");
}
And, confusingly, it worked! I could have sworn I was taught to do it this way:
if (number1.intValue == number2.intValue) {
NSLog(#"THEY'RE EQUAL");
}
How did using "==" between the two NSNumber objects work, and why? Does that mean it's okay to compare them that way, or was it just a fluke and this is generally not guaranteed to work every time? It really confused me :(
It's not a fluke.
It's due to the tagged pointers feature of the Objective-C runtime while using an ARM64 CPU.
In Mac OS X 10.7, Apple introduced tagged pointers. Tagged pointers allow certain classes with small amounts of per-instance data to be stored entirely within the pointer. This can eliminate the need for memory allocations for many uses of classes like NSNumber, and can make for a good performance boost.[…] on ARM64, the Objective-C runtime includes tagged pointers, with all of the same benefits they've brought to the Mac
Source
That is possibly a fluke.
From NSHipster :
Two objects may be equal or equivalent to one another, if they share a common set of observable properties. Yet, those two objects may still be thought to be distinct, each with their own identity. In programming, an object’s identity is tied to its memory address.
Its possible that your statement evaluated to YES because number1 and number2 were pointing to the same object. This would not work if they had the same value but were two different objects.
The obvious reason NSNumber variables would point to the same would be that you explicitly assigned one to the other, like so:
number1 = number2;
But there's one other thing. From this answer :
This is likely either a compiler optimisation or an implementation detail: as NSNumber is immutable there's no need for them be separate instances. probably an implementation optimisation thinking about it. Likely numberWithInt returns a singleton when called subsequently with the same integer.
But anyways, its safest to use isEqualToNumber:, as there is no telling what other "things" are lurking in the depths of code that may or may not cause it to evaluate YES
From RyPress :
While it’s possible to directly compare NSNumber pointers, the isEqualToNumber: method is a much more robust way to check for equality. It guarantees that two values will compare equal, even if they are stored in different objects.
There two concepts of equality at work here:
Object identity: Comparing that two pointers point to the same objects
Value equality: That the contents of two objects are equal.
In this case, you want value equality. In your code you declare two pointers to NSNumber objects:
NSNumber *number1;
NSNumber *number2;
But at no point show assignment of a value to them. This means the contents of the pointers can be anything, and quite by chance you have two pointers pointing to the memory locations (not necessarily the same ones) where (number1.intValue == number2.intValue) happens to be true.
You can expect the behaviour to change in unstable ways - for instance as soon as you add any more code.
Of course you can compare two NSNumber* with ==. This will tell you whether the pointers are equal. Of course if the pointers are equal then the values must be the same. The values can be the same without the pointers being equal.
Now you need to be aware that MaxOS X and iOS do some significant optimisations to save storage, especially in 64 bit code. Many NSNumbers representing the same integer value will actually be the same pointer.
NSNumber* value1 = [[NSNumber alloc] initWithInteger:1];
NSNumber* value2 = [[NSNumber alloc] initWithInteger:1];
These will be the same pointers. In 64 bit, many others will be the same pointers. There are only ever two NSNumber objects with boolean values. There is only ever one empty NSArray object, and only one [NSNull null] object.
Don't let that lull you into any wrong assumptions. If you want to see if two NSNumbers have the same value, use isEqualToNumber: You may say "if (number1 == number2 || [number1 isEqualToNumber:number2])"; that's fine (didn't check if I got the names right).

When would you use NSNumber literal to create encapsulated character values?

I'm just going through Apple's iOS development tutorial at the moment and reading the chapter on the Foundation framework and value objects.
Just on the NSNumber class, it says:
You can even use NSNumber literals to create encapsulated Boolean and
character values.
NSNumber *myBoolValue = #YES; NSNumber *myCharValue = #'V';
I'm just wondering, when, or why, or in what scenario, might you want to use NSNumber for a character value rather than using NSString, say?
An NSNumber is useful for encapsulating primitive values to be inserted into Objective-C collection classes such as NSArray, NSSet, NSDictionary, etc.
Image a scenario where you would want to iterate over each character in an ASCII string and extract a unique set of vowels used. You can evaluate each character and add it to an NSMutableSet. To do so, you would need to encapsulate each character in an NSNumber as NSMutableSet expects an Objective-C object. This is just one example, but the concept applies to many situations where primitives need to be added into a collection.
Well, one case is where you're using KVC to set a value for a key, and the property type is char:
[object setValue:#'a' forKey:someCharPropertyName];
You can use NSNumber with characters to return its ASCII Code, so V would return 86.
I don't think many people use it that much, but you could probably use it for character validation. I think it just one of those things where Apple went, yeah, lets put that in for the heck of it.
It's really not used for much else. The #YES and #NO is the same as YES and NO, so its kinda inelegant in some places.

Class method access by dot operator [duplicate]

This question already has answers here:
Objective-C dot notation with class methods?
(3 answers)
Closed 9 years ago.
This question related to knowing something we don't know. I'm researching with "Why people don't use this"? Is any reason behind this related to specific tech? So read it carefully and give downvote or give correct answer.
We can write
NSMutableString *string = NSMutableString.string;
instead of
NSMutableString *string = [NSMutableString string];
Same as how can we write this method,
NSMutableString *string = [NSMutableString stringWithString:#"test"];
Update:
This question is not an duplicate which is little bit different. And I accept with below answers which is not recommended for good programmers. But They didn't explain Why, for What reason, programmers should avoid this? Could anyone give clear explanation about this with proper link or document?
NSMutableString.string is a hack. It "works" for the same reason that myString.length and [myString length] produce the same result. However, since dot notation is not used with an actual property, it is an abuse of the language feature, because properties have a different semantic. For example, when you access a property multiple times, you naturally expect to get the same result, unless the state of the object has changed in between the two invocations. Since NSMutableString.string produces a new string object on each invocation, it breaks the semantic expected of the "proper" properties, bringing down the readability of your program.
Objective-C does not have a general way of calling a method with arguments using the dot notation. There feature is very specific to properties. Although theoretically you could use MyClass.xyz = abc in place of [MyClass setXyz:abc], but that would be a hack as well.
To answer your question, Objective-C does not offer a way to call [NSMutableString stringWithString:#"test"] with dot notation.
It's just a syntactic sugar. string method has no arguments so it's treated like a getter, which is not in fact. stringWithString: is method with parameter, so you can't call like that.
In general, I'd not recommend using dot syntax with methods, it's confusing.
Objective-C dot notation with class methods?
Update
I don't think there is any technical reason you should avoid it.
It's rather in means of coding style, keeping code clean and consistent.

NSArray objectAtIndex: shorthand [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Is there some literal dictionary or array syntax in Objective-C?
I have recently noticed that something strange seems to work in objective-c.
When I have an array,
NSArray *myArray = #[#"1", #"b", #"3", #"d"];
I can normally access the second element by,
NSString *element = [myArray objectAtIndex:1]; // second element
however I seem to now also be able to access it via.
NSString *element = myArray[1];
Does anyone know if this is now a defined behaviour and therefore safe to use, or should I avoid it? Thanks to anyone who can help!!
This syntax was added in Clang 3.3 : Objective C Literals. Essentially, the compiler converts expressions of the type objCObj[idx] to the expression [objCObj objectAtIndexedSubscript:idx]. It also works for dictionaries, and you're free to adopt it for your own objects.
As such, you're perfectly safe using it, assuming you'll be using a modern version of Objective C and suitably updated Objective C compiler (i.e. Clang).
this is a new feature of objective-c and avaiable since xCode 4.5
its safe to use this syntax, you can even give your own classes support for this.
Ya, it's safe to use these syntax.
Those syntax are part of Modern Objective-C.
You can check this article for more options: ObjectiveCLiterals
It's a perfectly valid code for the latest version of the LLVM compiler.
So far, it's invalid for other compilers (e.g. GCC).
Whether you should avoid it or not - well, it's a matter of taste. There are several big discussions about it on the internet since the indexing behaves slightly different (a whole different method is used to implement it).
There are also discussions whether to use the expression literals or not since there are ocassions when they are making the code less readable (e.g. they are written like literals but they actually are autoreleased objects). Note that everything is done using literals can be done using simple macros.

Obj-c for..in loop with NSArray ordering? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Does fast enumeration in Objective-C guarantee the order of iteration?
Just a quick question that was proving problematic to google:
When fast-iterating over an NSArray like so:
for (NSObject *obj in array) {}
Is the order well-defined? In my tests it seems to be, but I wasn't able to find a guarantee anywhere...
Thanks!
From the Fast Enumeration section of The Objective-C Programming Language:
For collections or enumerators that have a well-defined order—such as an NSArray or an NSEnumerator instance derived from an array—the enumeration proceeds in that order, so simply counting iterations gives you the proper index into the collection if you need it.
Yes, it does.
The documentation says NSArray and its subclasses «manage ordered collections of objects».
This is the guarantee you are looking for.
Note this is not the case with NSDictionary, for instance.

Resources