iOS How do I find Strings in Apple's private APIs - ios

Let's skip the discussion about using the private APIs, it's just for testing something.
I am looking for a way to access hidden field of MPMediaItem by using the value(forProperty:) but the String I'm looking for is not available publicly. I have looked over MPMediaItem header here and I could not find what I was looking for however this didn't surprise me because when looking at MPMediaPlaylist.h I also couldn't find any info about "parentPersistentID" or "isFolder" properties both which can be easily accessed by value(forProperty: "isFolder") as Bool
Normally you would access Playlist's name or other fields by something like value(forProperty: MPMediaPlaylistPropertyName), because MPMediaPlaylistPropertyName is publicly available, MPMediaPlaylistPropertyIsFolder is not so we have to use "isFolder"
Is it possible to find those hidden Strings? I am wondering if it's a matter of luck when guessing the name or there is a header which contains those Strings
Below are those String which are available publicly

I think that you really need to rethink your application in this point.
I think that one should never play with private APIs, it is made private for a purpose.
But this Objective-C code, could display the private variables:
unsigned int o;
Ivar *d = class_copyIvarList([MPMediaItem class], &o);
for(int i=0;i<o;i++) {
NSLog(#"%#", [NSString stringWithCString:ivar_getName(d[i]) encoding:NSUTF8StringEncoding]);
}
free(d);
You also may need the properties, sometimes there are computed properties (sorry for the swifty term), these properties also may be private and you may want to know it.
You can also try to add this:
objc_property_t *prop = class_copyPropertyList([something class], &l);
for (int i = 0; i < l; i++) {
NSLog(#"%#", [NSString stringWithCString: property_getName(prop[i]) encoding:NSUTF8StringEncoding]);
}

Related

How can I view the contents of an objective C Protocol?

If I have access to an objective-C Protocol and trying to figure out how to look inside it to see what methods it contains, including their signatures, etc.
I've tried NSLog and looking in the object in the debugger, as well as on the internet, and cannot find any way to do this.
I checked out the methods in objc/runtime.h after seeing the answers to this SO post: List selectors for Objective-C object and found a way to NSLog a protocol's method signatures
#import <objc/runtime.h>
Protocol *protocol = #protocol(UITableViewDelegate);
BOOL showRequiredMethods = NO;
BOOL showInstanceMethods = YES;
unsigned int methodCount = 0;
struct objc_method_description *methods = protocol_copyMethodDescriptionList(protocol, showrequiredMethods, showInstanceMethods, &methodCount);
NSLog(#"%d required instance methods found:", methodCount);
for (int i = 0; i < methodCount; i++)
{
struct objc_method_description methodDescription = methods[i];
NSLog(#"Method #%d: %#", i, NSStringFromSelector(methodDescription.name));
}
free(methods)
The only catch is that in protocol_copyMethodDescriptionList you need to specify whether you want required vs. non-required methods and whether you want class vs. instance methods. So to cover all four cases, you would need to call protocol_copyMethodDescriptionList four times and print the results for each list.

How to check how much two strings are different

How to compare two strings while some parts of them are same?
Let say I have a string ABCAAAA.
For some reason, only ONE character of the string ABCAAAA can be changed at a time. For example, I can change this string to DBCAAAA.
Now the problem is :
How can I ensure ONLY ONE character is changed each time? Is there a method for NSString to compare how much two strings differ?
Purpose: I put each string into own UITextField to determine whether this one is editable if others had changed. I need to ensure only one is edited at a time. So if one had been edited, I will set UITextField's enable to NO to disable editing.
There is no built-in NSString method available to do what you want. You need to write your own method. Objective-C does let you "extend" classes with new methods to cover cases like this.
This is how I would do it:
#interface NSString(Extend)
-(NSInteger)proximity:(NSString*)otherString;
#end
#implementation NSString(Extend)
-(NSInteger)proximity:(NSString*)otherString
{
NSUInteger length = [otherString length];
if(length != [self length]) return -1;
NSUInteger k;
NSUInteger differences = 0;
for(k=0;k<length;++k)
{
unichar c1 = [self characterAtIndex:k];
unichar c2 = [otherString characterAtIndex:k];
if(c1!=c2)
{
++differences;
}
}
return differences;
}
#end
Then in my code at the place I wanted to check I would say something like
Michael L gave a good answer (+1)
I just wanted to note that if all your text strings are in separate UITextFields, then only one of them can be edited at a time. Therefore I really don't understand what you want to do with enable = NO part.
If text strings must be edited in certain order, just keep count of order by index by yourself.

Verify if an NSString object's text is contained in a collection of strings (a domain)

Rather than a long if statement, what is a more compact and readable way to verify if a string is contained in a collection of possible values? In other words, check if a value is within a domain?
I want to do something like this…
NSArray* domain = [NSArray arrayWithObjects:#"dog", #"cat", #"bird", nil];
BOOL valueFoundInDomain = [domain containsObject:#"elephant"];
But I'm concerned about equality checking with NSString. I want to check the value of the text, not object identity.
The documentation for NSArray says the containsObject method uses the isEqual method. But I cannot find in the documentation for NSString an explanation for its implementation of isEqual. The presence of the isEqualToString method suggests that isEqual may be doing something else. If that something else involves interning of string objects, then experimenting myself may give misleading results, so I'd like a documented answer.
I never use -isEqualToString:, only -isEqual: and it just works as it should! (I do this for years.)
NSString is implementing -isEqual: and it returns YES if the other object is a string and it has the same contents.
In Apples Objective-C documentation, methods that are overridden from a baseclass are often not explicitely documented. But -isEqual: is one of the few methods that is implemented in all foundation classes where it makes sense.
The isEqual method does an additional type check to ensure you are comparing two objects of the same class.
IsEqualToString assumes you are sending a string and will crash if you send a nil or object of another type.
Your code looks good for its use case.
Lets Try Using This
NSArray* domain = [NSArray arrayWithObjects:#"dog", #"cat", #"bird", nil];
NSIndexSet *indexes = [domain indexesOfObjectsWithOptions:NSEnumerationConcurrent passingTest:^BOOL(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
return [obj isEqualToString:#"elephant"];
}];
// Where indexes contains matched indexes of array elements
Here isqualToString: Returns a Boolean value that indicates whether a given string is equal to the receiver using a literal Unicode-based comparison.isEquealTo: Returns a Boolean value that indicates whether the receiver and a given object are equal. When you know both objects are strings, isEqualToString: is a faster way to check equality than isEqual:

equality of two objects in Objective C [duplicate]

This question already has answers here:
Should you use 'isEqual' or '=='?
(2 answers)
Comparing objects in Obj-C
(4 answers)
Closed 8 years ago.
I am reading the Programming with Objective-C . In the section of Determining Equality of Objects , it says the following words:
- When dealing with objects, the == operator is used to test whether two separate pointers are pointing to the same object:
if (firstPerson == secondPerson) {
// firstPerson is the same object as secondPerson
}
- If you need to test whether two objects represent the same data, you need to call a method like isEqual:, available from NSObject:
if ([firstPerson isEqual:secondPerson]) {
// firstPerson is identical to secondPerson
}
I get confused about the differences between == and isEqual with the above explanation, does it mean firstPerson == secondPerson is an alternative of [firstPerson isEqual:secondPerson] ?
The definition of == is correct, it checks to see that they're pointing to the actual same pointer/memory address (ie. 0xffffff)
The key to understanding what you're asking is to think about what you mean by the word "equal". "equal" typically means, from the developer's point of view, that "these two objects contain the same data in the fields that I require for all practical purposes". You can have two user objects each with the same userID property but different times in lastUpdated - would you consider them equal? Depends on your use case. Most likely you would say yes because they're the same user. They were updated from the server at different times, so some fields differ, but for your implementation, they're equal.
In the case above, are they the same object? Definitely not. They point to different memory addresses. So == would be NO, whereas if you wrote your isEqual: method to check just the userID property, it would return YES
The definition of isEqual: is entirely up to the author of the class. isEqual: can be written to use == if you wanted. All you have to do, in your class, is to override the isEqual: method which is defined by the NSObject protocol.
If you have a custom object, use isEqual: to define what your definition of equal is. In the example of a user object, you might define:
- (BOOL)isEqual:(id)otherObject {
if ([otherObject isKindOfClass:[self class]]) {
MyClass *otherObjectAfterCast = (MyClass*)otherObject;
if ([otherObjectAfterCast.userID isEqualToString:self.userID])
return YES;
}
return NO;
}
Technically you'd probably want to use caseInsensitiveCompare: or something like that but you get the drift...
isEqual: can also be used to trigger other methods - in the case of NSString - calling isEqual: when both operands are strings results in a call to isEqualToString: - which is why the documentation recommends calling isEqualToString: if you know they're both strings, since it's a bit faster.
So, isEqual: is whatever you make of it, or whatever the class author has defined it to be.
This is also a pretty clear definition in the docs (for once lol): NSObject Protocol Reference
Hope this helps! Let me know if you need any further clarification.
NSString *string1 = [[NSString alloc] initWithString:#"some string"];
NSString *string2 = [[NSString alloc] initWithString:#"some string"];
NSString *string3 = string2;
BOOL equal1 = (string1 == string2); // NO
BOOL equal2 = [string1 isEqual:string2]; // YES
BOOL equal3 = (string2 == string3); // YES
BOOL equal4 = [string2 isEqualToString:string3]; // YES
The simple version is this.
== tells you if the pointers are the same object or not.
The isEqual: family of methods do something different.
They tell you if the objects at the other end of the pointers are effectively the same based on some criteria such as the properties or ivars holding equal values or whatever logic is implemented in the method used. They may or may not be the exact same object.

Why can't I add to a dictionary within my model from my controller? [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
My model is intended to store JSON data. Part of what's to be stored is an array nested in the JSON, which could be a varying number of elements. This is how I retrieve that data in code.
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"SomeJsonFile" ofType:#"json"];
NSData *jsonFromFile = [[NSData alloc] initWithContentsOfFile:filePath];
NSError *error = nil;
NSDictionary *jsonData = [NSJSONSerialization JSONObjectWithData:jsonFromFile options:0 error:&error];
DLog(#"simulated 'Stuff' JSON, stored in dictionary: %#", jsonData);
That works great. A callback sends along that dictionary, at which point I experience my problem. Here's an example of the nested array in the JSON.
stuff = (
{
id = 11;
"someState" = 1;
someNumber = 100;
description = "Human-readable text for thing #11!";
},
{
id = 22;
"someState" = 0;
someNumber = 20;
description = "Human-readable text for thing #22!";
},
{
id = 33;
"someState" = 1;
someNumber = 250;
description = "Human-readable text for thing #33!";
},
);
My model should store the data sent along there, but since that nested array is an unknown amount of elements, I've elected to:
Use an NSMutableArray to store the IDs of each array element.
Use an NSMutableDictionary for each property of the element (like someState, someNumber, description).
When the time comes to list all the elements of the model, I'll iterate through the array of IDs and use each ID as a key for each of the NSMutableDictionary properties, thus retrieving everything I need.
Those NSMutableDictionary properties from step 2 aren't responding. They don't set the keys or values; they remain null. From other questions, it seems this is because they aren't initialized. Also from other questions, I've been able to add and remove keys/values to an arbitrary NSMutableDictionary that I initialized (not a part of the model).
The controller should be blind to this initialization pertinent to the model, but I can't seem to initialize the NSMutableDictionary properties by overriding the getters/setters of the model. What is the correct way in objective-C to set up my model with NSMutableDictionary properties such that I can set keys and values in it from my controller?
I also feel like my many-dictionaries indexed by ids in an array solution is overkill. If you can spot that and know the better way to deal with this in iOS, please feel free to lend your wisdom.
EDIT
At the request of Marcus Adams, here is the code where I use the NSMutableDictionary properties. I do not initialize the NSMutableDictionary properties; where to do that so that it's appropriate to the MVC model is my question. His answer has led me to try initializing by overriding "init", and this works as part of the instantiation of the model (Marcus Adams will be marked as the answer if he provides the explanation, since he led me to the answer, but answers with code samples for correctly overriding "init" will be up voted).
// Now we're ready to store what's in the JSON.
NSDictionary *stuff = jsonData[#"stuff"];
NSMutableDictionary *tempDictBecauseAllocNeeded = [[NSMutableDictionary alloc] init];
for (NSDictionary *thing in stuff) {
[tempDictBecauseAllocNeeded setObject:thing[#"description"] forKey:thing[#"id"]]; // This works!
theModel.thingDescriptions[thing[#"id"]] = thing[#"description"]; // This wasn't working!
[theModel.thingIds addObject:thing[#"id"]]; // This is the array of ids used to retrieve values from each dictionary
}
I guess your code should be working now. I was curious how you were copying the NSDictionaries and thought the problem might be there. Obviously, you discovered that you hadn't initialized tempDictBecauseAllocNeeded. I wouldn't use a getter to initialize unless you are keeping tempDictBecauseAllocNeeded around for awhile. If you are, storing it as a property and initializing it in a getter is the simplest thing to do.
// Getter ensures that when you reference self.tempDictBecauseAllocNeeded
/// it's always initialized
-(NSMutableDictionary *) tempDictBecauseAllocNeeded {
if (!_tempDictBecauseAllocNeeded) {
_tempDictBecauseAllocNeeded = [[NSMutableDictionary alloc] init];
}
return _tempDictBecauseAllocNeeded;
}
Since the original JSON parsing, by default, creates mutable leaves, even though you assign it to an NSDictionary, each leaf in there is still mutable.
So, when you (shallow copy) over the leaves to your NSMutableDictionary, they are still mutable, of course.
stuff = ( ...
This is not a JSON array, is it supposed to be? JSON array would be
stuff = [ ...

Resources