I am a novice in Objective-C and I am trying to understand how pre-defined methods work. I went through the documentation of XCode and the *.h files where the method is defined. However I am eager to read the *.m file or any other document that can help me understand how the method works.
For instance - isEqualToString:(NSString *) checks if two strings (of the type NSString) are equal or not. I am not satisfied with this description. I am eager to see how the method works internally or what is the algorithm it follows. Where can I find this information?
Thank you for your help.
isEqualToString:(NSString *) is a method defined in the NSString class. Apple provides you with the framework, but they do not provide the implementation of those methods. Therefore, you can't see the source behind the standard framework's libraries.
Edit: you can create a binary and use this app to check the assembly code: http://itunes.apple.com/us/app/hopper-disassembler/id422856039?mt=12
Unfortunately, a lot of the implementation (.m) files for Apple's frameworks aren't provided publicly. You have a couple alternatives:
As Matthias suggested in a comment, use the debugger and inspect the assembler code generated for that method.
Browse through the repositories for the GNUstep project, which has some equivalents to Apple classes.
Related
I am using a 3rd party Obj-C static library for and API in a RubyMotion project and one of the classes in the library defines some public instance variables in the interface section in the API header file. Here is the code as it's pretty short:
#interface TransporterFile : NSObject
{
#public
NSString *name;
TransporterFileType type;
NSDate *modifyTime;
NSDate *createTime;
unsigned long long size;
}
- (BOOL) isFolder;
- (BOOL) isShared;
#end
In ObjC, these values can be reached like this:
name = transporterFile->name
but there is no getter defined so you can't use dot notation.
In RubyMotion, probably because there is no getter, there is no instance variable exposed to me. I have tried using the .instance_variables method and it returns an empty array. I also tried the instance_variable_get('#name') method but that doesn't work either. I am able to call the two methods isFolder and isShared and they work as expected.
Update: I tried doing a similar thing in the Swift language and it had similar problems and that led me to a suggestion to use the valueForKeyPath('name') method to access the 'name' instance variable. That worked in Swift and led me to check if a similar method was available to RubyMotion. The good news is that this works but is a bit clunky so I'll leave this question open for now in the hope that a better answer is available.
I realise the 3rd party library is not following best practice and I will recommend to the vendor that they define some properties instead if using instance variables directly but for now I need a workaround.
Can anyone please suggest a way to access these public instance variables from RubyMotion or perhaps by wrapping the vendor's library in another ObjC library. I've never written an ObjC library (wrapper or not) so would appreciate some advice before I embark on this option.
The full API can be seen here: https://secure.connecteddata.com/developer
Note that I'm using Mac OS X 10.10 with Xcode 6.1.1 and the latest version of RubyMotion. The Mac OS X API download from the above site is missing the header file so I used the header from the iOS download.
Many thanks,
Craig.
I updated my question to explain that I found the following method allows me to access the public instance variables.
obj.valueForKeyPath('name')
However, I'd be happy to hear of any better ways to do this as it's a bit clunky.
ps. Why is it that I can spend hours trying to find a solution to a problem then within minutes of posting the question on an open forum, I find a potential answer? Grr... :)
Is it at all possible to have Xcode create a .playground file for Objective-C instead of Swift? Are there any available Xcode plugins that allow that?
You can quickly test code snippets using a test case in a new project. Just create a new project and go to the Navigator in the left pane and hit the Test Navigator button. Then follow this guide
The setup code will look a little different than a swift playground, but it still allows you to prototype and play around.
There is a very good library developed by Krzysztof Zabłocki in Github entitled KZPlayground that support both code in Playgrounds for Objective-C and Swift and a lot of cool features.
I hope this can help you.
If the only purpose is to test out Objective-C snippets, i would really recommend you an OS X command line Tool project.
There are enough moving parts in a playground, and all of those would have to be reimplemented for Objective-C. Reliable playgrounds also depend on definite initialization which Objective-C does not have.
For instance consider:
var d: NSData // this is not initialized, so I can't use it
vs.
NSData *d; // this is also not initialized, but now I can use it
If I am the person storing the description of your NSData for the sidebar, now I know that I am not supposed to do
describe(d)
in the Swift case, but for the Objective-C case, I don't have equal knowledge and I run the risk of saying
[d description]; // even though d is a random pointer now.. oops, I just crashed!
In short, I don't think any such thing exists, and making one work would also involve some trickery
Everything is in the title :)
Is there any templates in ObjC ?
I need equivalent of c# :
public class MyClass<T> : Message
in ObjC .
Any helps will be strongly thanks :(
There is no such ObjC feature. While ObjC++ does exist, I strongly discourage its broad use. It has many problems from poor tool and debugger support, to poor compiler optimization, to degraded ARC performance.
Generally templates are not required in ObjC because it is not a strongly typed language. An NSArray can hold any object, so you don't need to use a template to get the right type. Do you have a specific problem you're trying to solve? There is likely a better ObjC solution.
Obj-C supports templates since Xcode v7. It is named generics:
Lightweight generics now allow you to specify type information for
collection classes such as NSArray, NSSet, and NSDictionary. The type
information improves Swift access when you bridge from Objective-C,
and simplifies the code you have to write. For example:
NSArray<UIImage *> *images;
NSDictionary<NSString *, NSURL *> *resourcesByName;
Look for "Objective-C Language Changes" section in
https://developer.apple.com/library/content/documentation/Xcode/Conceptual/RN-Xcode-Archive/Chapters/xc7_release_notes.html
By the way, Xcode supports adding C++ classes through the New->File. Using the extern "C" {} construct in C++ means you can provide as much or as little C-callable interface as you need, which you can then call directly from your Objective-C code, since Objective-C is a superset of C.
Having said that, it's probably a good idea to stick within the Objective-C paradigm unless you have a pressing reason to move outside it, such as the need to incorporate a body of existing C++ code into your project. (That's not to say that Objective-C is a "better" language, which is a different matter entirely.)
Assume that:
New Protocol is declared
Method in this protocol is marked #required
Class conforms to Protocol
Class does not implement the method mentioned in Protocol
At compile time, information about this method is known: i.e. that it is required and that this class and any other classes this class may may extend do not implement it.
Why in this case the compiler issues a warning and not an error?
Errors are only issued when the compiler cannot continue because something went terribly wrong.
When calling a method in Objective-C, the method lookup is done during runtime and not during compilation, which C++ does. In Objective-C a "message" is simply sent to the object, something like obj.executeCommand("Hey, can you execute function <name> for me?"). In C++ the object will be called directly, in a way like obj.<name>(). In the case of Objective-C the executeCommand() method is called, which exists. In C++'s case the function is called but it does not exist. These are methods that are linked on the compiler level, which means they both become memory addresses rather than names. executeCommand becomes 0x12345678 but it still uses the same message ("execute function <name>").
This is probably very confusing, but it's related to the way methods are implemented in different languages.
If you feel strongly about it, why not turn on -Werror?
I don't know the real answer but here is a use case that would go against it.
What if you implemented all of the protocol methods in a category???
Main interface declaration adopts the protocol however the protocol method implementation is in a category.
This is valid code but will show compile error if compiler was that strict !!
Objective-C is a dynamic language. The idea of what an implementation is, is different to a static language.
For the most part, it's in code that most of us implement inside the #implementation ... #end block.
But what if a method is not found? Then an object has a chance deal with it dynamically.
Imagine you have an interface for a sound effect player:
#protocol FX
- (void)playBeep;
- (void)playSiren;
- (void)playHonk;
#end
An implementation could have the files Beep.mp3, Siren.mp3, Honk.mp3 to play, but instead of implementing each of the methods, it could override -forwardInvocation: and parse the selector string, something like this pseudocode:
NSString *selName = NSStringFromSelector([invocation selector]);
if ([selName startsWith:#"play"]) {
NSString filename = fileNameFromSelector(selName);
[self playSoundFileNamed:filename];
}
This may seem contrived, but once you start using the dynamic features of the language, you will start finding more and more places where it makes sense. And by sense I mean, does this effort help in the long run?
In the above case, just add a -sound* method name to the interface, and drop in a appropriately named sound file. It just works.
Another example from personal experiments: how to deal with Core Data entities in a more natural way. I want to do this:
NSArray *people = [Person findAllWithNameLike:#"B%"];
instead of mucking about with predicates, fetch requests etc.
But I don't want to define every permutation of method in code.
How about if I wanted to build an XML builder? I would look at a dynamic approach. It has served Groovy Builders well (look at Groovy/Grails for examples).
One last example: I have a traits system where I can define behaviours in the form of groups of methods and have my objects assimilate this behaviour. So, while the compiler doesn't see an implementation for the interface my object conforms to, the implementation is injected into it from a trait class, using the Objective-C runtime. Why would I do this? I find many delegate methods are boiler plate, but at the same time, a single base class for each situation is not flexible enough. Instead of cut and paste from code samples, my 'samples' compile and run :) and any changes are reflected across all projects using the trait.
To really understand why all this is available to you, it is worth playing around with a Smalltalk environment (search Pharo or Squeak). This is where Objective-C has its roots.
And finally, to stop these warnings:
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wprotocol"
#implementation ... #end
#pragma clang diagnostic pop
Because there are times when there are bogus "required" methods in a poorly designed protocol.
They should have been optional but someone insisted they are "required".
Thusly making this a run time issue rather than a compile bug is very very wise.
Not knowing Obj-C I could use some help to traslate this one line of code:
[[TVOutManager sharedInstance] startTVOut];
into a C# version I can use in MonoTouch.
I've managed to get the XCode project compiled to a static library, now I'm trying to figure out how to turn it on... The orginal project is posted here: http://www.touchcentric.com/blog/
TIA,
Rick
[obj myMsg] is Objective-C syntax for sending the myMsg message to the obj instance. It is, at first blush, a lot like obj.myMsg() in C#. Objective-C uses message passing rather than function calls, however, so the two are actually very different semantically. You can often gloss over the differences, but if you are going to do any significant work on OS X or iOS, it's worth reading the Objective-C language guide carefully. I'm not a MonoTouch/MonoMac expert, but I believe that the answer to your specific question is:
TVOutManager.sharedInstance.startTVOut();
assuming sharedInstance is mapped as a static property of type TVOutManager, or
TVOutManager.sharedInstance().startTVOut();
if sharedInstance is mapped as a class method in Objective-C.