Index of object equal to string - ios

If I have an array of strings, can I reliably test if it contains a given string with NSArray containsObject - or should I loop through and test isEqualToString on each object?

containsObject: uses isEqual:, which is reliable and tests for equality, i.e., if the object in the array and the parameter are really equal. It might actually call isEqualToString: under the hood.

Yes you can use containsObject method as well which is internally calls isequal method only.

Related

Why does the Ruby Array class have to_a and to_ary methods?

Are there any use cases in which we'd call Array.to_a and Array.to_ary on an object that's already an Array?
If not, why do these methods exist within the Array class?
Are there any use cases in which we'd call these coercion methods (Array.to_a and Array.to_ary) on an object that's already Array?
Yes: in Ruby, you generally never care what class an object is an instance of. Only what it can do. So, you only care about "can this object convert itself to an array". Obviously, an array can convert itself to an array, so it should have those methods.
Slightly longer answer: if we don't care what class an object is an instance of … then why do we care whether it can convert itself to an array? Well, that's a pragmatic choice. From a purely OO perspective, it shouldn't matter. But there are certain operations that are implemented deep inside the core of the execution engine that require an object to be of a certain class, for efficiency and performance reasons. In other words, sometimes objects don't work, you need an Abstract Data Type.
For example, there are certain operations inside the Ruby execution engine that take advantage of the fact that they know about the internal memory layout of Arrays. Obviously, those operations will break in horrible ways if you hand them something that is not an Array and they go poking around in that object's memory. From a purely OO perspective, those operations shouldn't know that, and they should use Array's public interface, but alas, they don't. But, in order to give you (the programmer) an escape hatch for your own array-like objects, those operations will allow you to convert yourself to an Array first, by calling to_ary.
In other words, implementing to_ary means that your object is a kind-of array. Obviously, an array is a kind-of array, that's why it responds to to_ary.
There are other similar conversion methods in Ruby: to_str for strings, to_int for integers, to_float for floats, to_proc for "functions".
There are also their single-letter variants. The long variants mean "I really am an array, I just don't happen to be an instance of the Array class." The short variants, instead, mean "I can kinda-sorta represent myself as an array".
You can see that most obvious with nil: it responds to to_i (because it kinda-sorta makes sense to represent nil as the integer 0), but it doesn't respond to to_int (because nil is not an integer in different clothing, it is something completely different).
The fact that arrays, integers, etc. also implement to_a, to_ary, to_i, to_int, etc. means that you can treat all array-like objects the same, polymorphically. It doesn't matter if it's an array, a stack, a set, a tree, an enumerator, a range, or whatever. As long as it can kinda-sorta be represented as an array, it will respond to to_a, and as long as it actually is an array (even if its class isn't Array), it will respond to to_ary, and you don't have to check because it doesn't matter.
However, note that these situations ideally should be rare. In general, you should care about, say, whether the object can iterate itself (i.e. it responds to each). In fact, most of the things you can do with an array, you can also do with any other Enumerable, without using to_ary or to_a. Those should be the last resort.
I think it's (among other things) to avoid having a special case for nil.
Let's say foo is a method that can either return an array or nil. The snippet below would fail half of the time:
foo.each { |x| puts x }
If Array didn't implement a to_a method, you'd probably have to write something like this, which in my opinion is a bit ugly:
(foo || []).each { |x| puts x }
Instead of this:
foo.to_a.each { |x| puts x }
In a similar fashion, Integer has a to_i method and String has a to_s method, and so on.
Array implements to_a and to_ary because this allows for cleaner methods that coerce arguments into specific types.
For example, what if you had a method:
def foo(object)
#does some work on object that requires object acts like an array.
...
end
and wanted to use this method on sets generated from somewhere else in your code.
One way you can do this is to cast object.to_a before doing the operation:
def foo(object)
array = object.to_a
...
end
If Array didn't implement to_a, then you'd have to do a check:
def foo(object)
array = object.to_a if object.respond_to?(:to_a)
...
end

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.

How are identical NSStrings determined in Objective-C?

Consider the following code:
+ (NSString *)helloString
{
return #"hello";
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSString *a = [AppDelegate helloString];
NSString *b = [AppDelegate helloString];
NSLog(#"%#", a == b ? #"yes" : #"no");
abort();
}
On my machine the result is always "yes". Does it mean that the NSString literal #"hello" is always the same "object" in Objective-C runtime?
Actually my original purpose is to use an uniquely identifiable object to bind in NSNotification's postNotificationName:object: method. I plan to use a NSString literal to act as the object. Is it safe/recommended to do so?
Historically, NSString literals were guaranteed to be unique within a translation unit, and were often unique even between translation units in practice. The current documentation no longer makes this claim as far as I know, and the Clang docs recommend against relying on it.
If you want a string that's guaranteed to always be the same object, you can simply assign a string to a global constant. All references to that constant will definitely yield the same object.
With regard to NSNotification, though, I wouldn't use such a string as the object. The semantics of NSNotification say the the object argument should be the object that triggered the notification — where it conceptually "comes from." Other information associated with the notification would make more sense in the user info dictionary.
[a isEqualToString: b] compares two strings a and b, and returns YES if the contents is the same. This works if they are the same object, or different objects, or one is an NSString and one is an NSMutableString, or one is one of the many classes that behave like strings. If a is nil the result is NO, if a is not nil but b is nil you get a crash.
Comparing strings with a == b is interesting: If a and b are both nil the result is YES, one nil but not the other returns NO. If a and b are the same string because you have the same string literal or the same NSString object assigned to a and b, the result is YES. In your example, the "helloString" method always returns the same literal. Not just a literal with the same characters, but the same literal.
If you use literals with the same characters, they may or may not be the same. No guarantees. If you use the copy method, the result may be the same as the original or not. No guarantees. All in all, == or != for NSString is not very useful. It's only useful to compare nil vs. not nil, or if you know exactly which string was assigned.
BTW >=, >, <=, < give undefined behaviour if the strings are not the same, so they are completely useless.
That depends on the compiler implementation, which in theory could change from time to time, so it is not reliable. If you need to make sure that the NSString pointer is always the same, you should use a constant.
const NSString* kSomeConstantName = #"ConstantValue";
Just use the following Code:
[a isEqualToString:b]
Actually in your case #"hello" is always returned same pointer as mostly all language including objective c use string interning for string literals which means for same string literal it reruns single object.
But this is not the case which is always true means two strings with same characters may have different references if you allocate them differently by alloc keyword.
So always use isEqualToString: if you need to check string equality for its contents.== is used for reference equality(locations in memory) which may or may not different for same contents strings.
Does it mean that the NSString literal #"hello" is always the same "object" in Objective-C runtime?
I wouldn't count on it being true in all cases. Strings should be compared with -isEqualToString:.
Actually my original purpose is to use an uniquely identifiable object to bind in NSNotification's postNotificationName:object: method.
That seems like a misuse of the API. In most cases, you should just pass the object that's posting the notification.

How is comparing operator '==' for NSObject [duplicate]

This question already has answers here:
Should you use 'isEqual' or '=='?
(2 answers)
Closed 8 years ago.
How is comparing operator '==' for NSObject?
Method -isEqual: works fine for me, but when I'm using -isEqual I need to check if objects exists. With '==' I don't need to check this but where I can find documentation for it?
From Apple documentation:
Returns a Boolean value that indicates whether the receiver and a
given object are equal. (required) This method defines what it means
for instances to be equal. For example, a container object might
define two containers as equal if their corresponding objects all
respond YES to an isEqual: request. See the NSData, NSDictionary,
NSArray, and NSString class specifications for examples of the use of
this method. If two objects are equal, they must have the same hash
value. This last point is particularly important if you define
isEqual: in a subclass and intend to put instances of that subclass
into a collection. Make sure you also define hash in your subclass.
if you do like this
if([obj1 isEqual:obj2])
and obj1, or obj2 is nil then you will get NO. (if this is what you meant by your question)
- Now
if(obj1 == obj2)
This is a pointer comparison. Pointers
The == operator tests whether the two expressions are the same pointer to the same object. Cocoa calls this relation “identical”
To test whether two objects are equal, you would send one of them an isEqual:

iOS: Object equality when enumerating

Say I have a NSArray, and each item is an NSDictionary with three keys keyA, keyB, and keyC - each referring to objects of unknown type (id).
If I wanted to write a method that found the given element with those three keys i.e.
-(NSDictionary *) itemThatContainsKeys:(id)objectA and:(id)objectB and:(id)objectC
would I run into trouble by simply enumerating through and testing object equality via if([i objectForKey:(keyA) isEqualTo:objectA]) etc? I would be passing in the actual objects that were set in the dictionary initialization - ie not strings with the same value but different locations.
Is this bad practise?
Is there a better way to do this without creating a database?
You can override isEqual to stipulate the notion of equality for your type. The same rules apply as in other languages:
If you provide an implementation of equals you should provide an implementation of 'hash'
Objects that are 'equal' should have the same 'hash'
Equals should be transitive -> if A equals B, and B equals C, then C must equal A.
Equals should be bi-directional -> if A equals B, then B must equal A.
This will ensure predictable behavior in classes like NSSet, that use hash for performance, falling back to equals on when there's a collision.
As Jason Whitehorn notes, Objective-C also has the convention of providing another isEqualToMyType method for convenience.
AppCode, EqualsBuilder, Boiler-plate code
It would be nice if there was something like Apache's 'EqualsBuilder' class, but in the meantime AppCode does a fine job of implementing these methods for you.
The isEqual: method compares object identity unless overwritten by a subclass. Depending on what class the target is, this May or may not be what you want. What I prefer is to use a more class specific comparison like isEqualToNumber: simply because of it's explicitness. But, isEqual should work depending on the target.
Other than that, and not knowing more specifics of what you're doing, it's hard to say if there is a better way to accomplish what you're after. But, here are my thoughts;
An array of a dictionary almost sounds like you might need a custom class to represent some construct in your app. Perhaps the dictionary could be replaced with a custom object on which you implement an isEqualToAnotherThing: method. This should simplify your logic.

Resources