I was upgrading some projects to use Xcode 4.6 and Clang LLVM compiler but I'm getting stuck with an error. I'm not the biggest obj-c geek so I'm a bit stuck here. I think this question touches base with my problem but doesn't quite give me a solution.
My class derives from NSTableView (#interface MyClass : NSTableView) but when I make the following call:
[self setDataSource:self];
I get the following error:
Cannot initialize a parameter of type 'id<NSTableViewDataSource>' with an lvalue of type 'MyClass *'
Using Xcode 3.2.6 had no issues with this call but now I'm stumped as to why I'm getting an error. I do add some table columns previous to this call and set some attributes but essentially I get the error from the call above.
Any help is appreciated.
For one, your table view should NOT be its own datasource. This breaks the MVC model that Cocoa uses. Views should only be concerned about displaying/presenting data, it should not store the data (that's the model's job) nor should it be the class that interfaces the view with the model (that's the controller's job).
Usually the datasource will be a NSViewController that conforms to the NSTableViewDataSource and the protocol:
#interface MyViewController : NSTableViewController <NSTableViewDataSource, NSTableViewDelegate>
Related
I've got a mixed Obj-C / Swift project. Whenever I hit a breakpoint in a Swift class, the Obj-C object variables view just shows values for parent classes, but not the subclass itself.
For instance, if I have the following Obj-C class:
#interface CameraPlayerCell
#property (nonatomic, strong) Camera* camera;
#end
When I hit a breakpoint in my Swift CollectionViewController implementation, the Xcode debugger values view shows:
Searched for this for about an hour, but apparently I don't know how to ask Google what I'm looking for (or they're just being Google & showing me what they think I want rather than what I actually want...)
I know there is a way to add an expression to the Variables View so that it will show the member variables for CameraPlayerCell. I've read an article somewhere and have done this before, but for the life of me I cannot remember how to do it.
Have you tried frame variable?
From Apple:
"You use the frame variable (f v) command to get a list of all the variables in the stack frame."
Example:
Cast the value:
po (CameraPlayerCell *)cell
Then you can access the subclass properties:
po ((CameraPlayerCell *) cell).camera
Works fine on my machine. Keep in mind that an Objective-C property is merely a shorthand for accessor methods for an ivar; it is the ivar that will appear in the variables list. (I assume that yours is automatically synthesized.)
This was discussed here; similar but not identical.
MyView is a Swift subclass of UIImageView. It compiles and its interface appears in the DerivedData/.../*-Swift.h file. But downcasting to it in Obj-C fails. The code:
MyView* myView = (MyView*)viewThatCameFromIB;
// The Custom Class declared in IB inspector as MyView.
results in this line in the Xcode Variable Viewer:
myView UIImageView * 0x7fc8e9417e00
This line of code executes with no failure. But sure enough, trying to use the MyView features on the myView variable crashes with unknown selector. Since the cast succeeded in Obj-C, before MyClass was ported, it should also after the port, n'est-ce pas?
I tried:
deleting and resetting the Custom Class in IB just in case.
breaking this line of code into multiple steps.
Now this worked:
instantiate a MyView directly with its init() method
That is, I got a MyView instance:
myView _TtC12YadaYada11MyView * 0x7f8bc05487d0
(Consequently, I can think of a workaround: write a Swift MyView constructor that takes a UIImageView and uses it to construct itself. But I shouldn't have to. Isn't that what the downcast would do behind the scenes?)
The problem seems to be caused (fixed) by clearing (setting) the Inherit Module From Target boolean for the MyView view, in the Custom Class section of the Identity Inspector. At least in the from-scratch test case. In my particular porting challenge, with 3,000+ files (and 50+ MyViews), there may be confounding factors. But for now, this is the answer.
I have code inheriting from UIActivity introduced in iOS 6 which compiles fines with Xcode 4.5 and works fine on iOS 6 and previous versions (I detect availability of the class at runtime). However, is it possible to make this code compile with Xcode 4.4, which does not include the UIActivity class in its SDK?
If I forward declare UIActivity the dealloc method doesn't compile because it calls super and the compiler warns me the class is already at the root of the inheritance tree. Maybe there is a way to make this class inherit from a proxy class which I define locally, and then at runtime somehow swizzle it and instantiate it as if it had been properly defined at compile time? The purpose of this is to compile code with Xcode 4.4 and have the binary run on iOS 6 using that phantom class.
I know I can use defines to prevent my subclass from compiling at all with Xcode 4.4 and previous, but that would mean the functionality won't be available on a device running iOS 6.
#interface UIActivityDummy : NSObject
//Copy UIActivity methods to avoid compiler warnings
#end
#implementation UIActivityDummy
#end
#interface MyClass : UIActivityDummy
#end
#implementation MyClass
+ (void) initialize {
Class activityClass = objc_getClass("UIActivity");
if (activityClass) {
class_setSuperclass([MyClass class], activityClass);
}
NSLog(#"%#", [[MyClass class] superclass]);
}
#end
Here, I just elaborating how we can get the class at run-rime. Hope it'll what you needed .Please check it.
just use:
objc_lookUpClass(myClass);// it check for the required class.
objc_getClass(myClass);//IT's what you needed.
Please check the Syntax, as I'm not sure. But, once a time I had used this and was also able to get the ivar and methods and was also able to add method at runtime.
In any concern get back to me. :)
I'm tearing my hair out trying to do the simplest of tasks... subclassing an NSAttributedString. Trying to call the super class's initWithAttributedString: method is causing an unrecognized selector sent to instance error.
MODAttributedString.h:
#import <Foundation/Foundation.h>
#interface MODAttributedString : NSAttributedString
#property (nonatomic, retain) NSDictionary *links;
+ (MODAttributedString*) attributedStringWithFormat:(NSString*)text args:(id)argOne, ... NS_REQUIRES_NIL_TERMINATION;
+ (MODAttributedString*) attributedStringWithFormat:(NSString*)text attributes:(NSDictionary*)attributeDict;
#end
The code that is causing the crash (I'll explain the reason I split the alloc from the init in a moment):
MODAttributedString *modString = [MODAttributedString alloc];
// Pausing debugger here and typing 'po modString' causes gdb error
modString = [modString initWithAttributedString:attributedString];
My only clue is that stepping over the alloc call, when I try to po modString, I'm given this error:
"The program being debugged hit an ObjC exception while in a function called from gdb.
If you don't want exception throws to interrupt functions called by gdb
set objc-exceptions-interrupt-hand-call-fns to off.
GDB has restored the context to what it was before the call.
To change this behavior use "set unwindonsignal off"
Evaluation of the expression containing the function (_NSPrintForDebugger) will be abandoned."
If I temporarily change the super class of MODAttributedString to a UIView, the alloc does not cause the gdb error (I stop the debugger prior to the init, which would obviously not work for anything other than an attributed string). However, common classes like NSArray, NSDictionary and NSAttributedString all fail with the same error.
In the method that calls the [MODAttributedString alloc] I use NSAttributedString as its own standalone class just fine. I am sure I'm including the MODAttributedString header in this .m file as well.
I'm using Xcode 4.2 and the iPhone 5 simulator. I've cleaned the project multiple times, tried creating a new project, tried using both LLVM GCC 4.2 and Apple LLVM 3.0, restarted Xcode and restarted my machine all to no success. I searched for this particular issue heavily before posting, but I only found issues related to properties, never to a superclass's public methods.
Is this a build settings issue? A configuration error? A compiler bug? I've subclassed common Apple classes hundreds of times, and for some reason this is the first time I've ever had an issue. Has anyone else ever had a similar problem? It's probably a really simple fix, but I just can't seem to figure it out on my own.
Thanks in advance!
It isn't "the simplest of things". You can't subclass NSAttributedString - it's part of a class cluster. This means (among other things) that the class returned when you instantiate is not necessarily the class you asked for. See What exactly is a so called "Class Cluster" in Objective-C?
It is possible, with great pain and difficulty, to subclass within a class cluster, but my advice is to write a wrapper class instead; you'll be much happier. Cocoa's dynamic redirection of unhandled methods makes this very easy.
I'm writing an Universal App that will run natively on both iPad and iPhone. I also need it to be targeted to older devices (those that cannot run 4.0) so 3.1 is a must.
I have already set up the Base SDK to the latest available version (4.2), and the Deployment Target to 3.1. I am making lots of runtime checks in order to call the corresponding methods only on the right device/version.
One of the things I am making use of in the iPad is an UISplitViewController. When assigning the splitViewController delegate, the compiler throws a warning because the class interface isn't explicitly adopting the UISplitViewControllerDelegate protocol and I'm afraid that if I declare it to make it so, the App will crash on older devices where there is no UISplitViewController/UISplitViewControllerDelegate.
What is the best way to supress the compiler warning? Should I declare an 'empty' UISplitViewControllerDelegate? If so, can I make it conditionally at runtime? Or should I just make the corresponding class interface conform to the protocol and not worry about older devices?
Best,
You can suppress the warning with a simple C cast:
foo.delegate = (id<UISplitViewControllerDelegate>)self;
I haven't tried this, but I'm pretty sure you can just go ahead and adopt the protocol unconditionally, even if the class may be used on an older runtime that does not have the protocol. And here's why:
All the information for defining a protocol is contained in the .h file that declares the #protocol. When you adopt a protocol, that protocol declaration is imported at some point in your .h file (presumably by #import <UIKit/UIKit.h>).
When the runtime needs to know something about a protocol, it references a "Protocol Object", which you would normally reference in source code by doing #protocol(MyProtocolName). And the compiler creates this protocol object (at compile time) when such a protocol reference is encountered, according to the section titled Protocol Objects in The Objective-C Programming Language documentation.
So knowing all that, if you adopt a protocol and you write any code that references the protocol object, that protocol object will be created by the compiler. Even if you're running on an older device, the compiler should've created that protocol object for you, so I don't think it'll cause a crash.
Hope that makes sense. If I have some time I can try this out to see if it holds in practice because I have devices running a range of iOS versions from 3.1 to 4.2.
Same problem if you want to use printing and stil have the app runnig before 4.2. Basically it works with this
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 40200
// code for iOS 4.2++
#interface PersonDetailViewController : UITableViewController <EditViewControllerDelegate, EditPickerViewControllerDelegate, UITextFieldDelegate, UIActionSheetDelegate, UINavigationControllerDelegate, UIImagePickerControllerDelegate, UIPrintInteractionControllerDelegate>{
#else
// code for iOS til 4.1
#interface PersonDetailViewController : UITableViewController <EditViewControllerDelegate, EditPickerViewControllerDelegate, UITextFieldDelegate, UIActionSheetDelegate, UINavigationControllerDelegate, UIImagePickerControllerDelegate>{
#endif
But... It looks like the InterfaceBuilder can't handle this. All outlets defines after this conditional definition ar gone in IB.
So any better solution?
Regards
Gerd