ARC issue with CorePlot - objective-c

I installed everything according to README file and imported all necessary libraries. Still, when implementing this method:
- (CPTLayer *)dataLabelForPlot:(CPTPlot *)plot recordIndex:(NSUInteger)index {
CPTMutableTextStyle *labelText = nil;
labelText= [[CPTMutableTextStyle alloc] init];
labelText.color = [CPTColor grayColor];
return [[CPTTextLayer alloc] initWithText:#"Test" style:labelText];
}
I receive errors:
ARC Semantic issue - Receiver 'CPTTextLayer' for class message is a forward declaration
and
ARC Semantic issue - Receiver 'CPTTextLayer' for instance message is a forward declaration
I read in many posts, that this is the fault of missing Quartz library, though I have it imported in the project and included in the class: #import <QuartzCore/QuartzCore.h>.
When I return nil instead of this, everything works, but hey, I need those data labels to work!
Anybody knows how to make it work?

Normally forward class error comes when that particular class is not imported in the current class and an #class is declared in .h file. If #class is also not present, it normally gives an unknown type error. So in this case as mentioned in comments, it is clear that the import statement for CPTTextLayer is missing.

I think that you forget to import CPTTextLayer.h on your code

Related

In Objective-C is there a way to get a list of the methods called by a method?

I have been doing some research online and have found that using the ObjectiveC package in Objective C you can get a list of all the methods on a class using class_copyMethodList(), and I see you can get the implementation (IMP) of a method using instanceMethodForSelector:. The Apple documentation here has been helpful so far but I'm stuck and not sure what I'm really looking to find.
I want a list of the methods/functions called in a given method's implementation so I can build a call tree.
Any suggestions? Thanks in advance!
This solution is kind of hard way, and will cause a line of code in every method You can also make use of sqlite and save the tracked methods..
MethodTracker.h
#interface MethodTracker : NSObject
#property (nonatomic) NSMutableArray *methodTrackArr;
+ (MethodTracker *)sharedVariables;
#end
MethodTracker.m
#implementation MethodTracker
static id _instance = nil;
+ (MethodTracker *)sharedVariables
{
if (!_instance)
_instance = [[super allocWithZone:nil] init];
return _instance;
}
// optional
- (void)addMethod:(NSString *)stringedMethod
{
// or maybe filter by: -containObject to avoid reoccurance
[self.methodTrackArr addObject:stringedMethod];
NSLog("current called methods: %#", methodTrackArr);
}
#end
and using it like:
OtherClass.m
- (void)voidDidLoad
{
[super viewDidLoad];
[[MethodTracker sharedVariables] addMethod:[NSString stringWithUTF8String:__FUNCTION__]];
// or directly
[[MethodTracker sharedVariables].methodTrackArr addObject:[NSString stringWithUTF8String:__FUNCTION__]];
}
- (void)someOtherMethod
{
// and you need to add this in every method you have (-_-)..
[[MethodTracker sharedVariables] addMethod:[NSString stringWithUTF8String:__FUNCTION__]];
}
i suggest you import that MethodTracker.h inside [ProjectName]-Prefix.pch file.
Sorry, for the double answer, i deleted the other one and i have no idea how did that happen..
Hope this have helped you or at least gave you an idea.. Happy coding,
Cheers!
I think in the runtime track method is possible, but function not.
I have been build a tool DaiMethodTracing for trace all methods activity in single class for some of my need. This is based on objective-c method swizzling. So, there is an idea to do this
List all Classes in your application.
swizze all the methods in each class.
filter the method you want to trace.
finally, you may got the method call path.

Why is NSClassFromString returning nil or not in these two cases?

I'm working with CocosBuilder 2.1 and Cocos2d-iPhone 2.0. I've gotten CocosBuilder to compile, and I'm having a weird problem when using their one-text-label example in my project.
Here's the code in question, from CCBReader.m line 823:
Class class = NSClassFromString(className);
if (!class)
{
NSLog(#"CCBReader: Could not create class of type %#",className);
return NULL;
}
This fails with the text "Could not create class of type CCLabelTTF". But if I change the code like this:
Class class = NSClassFromString(className);
if (!class)
{
CCLabelTTF* tempLabel = [[CCLabelTTF alloc] init];
[tempLabel release];
NSLog(#"CCBReader: Could not create class of type %#",className);
return NULL;
}
It works. I don't see anyone else having problems with CocosBuilder in this spot, so what's going on?
The weird thing is that this change can only be affecting it at compiler level, because the added code is inside the error segment, right?
because you did not use CCLabelTTF at all in you project, so the runtime did not load the class for you.
it works after you did the hack because your project now do use the CCLabelTTF class so the runtime will load it.
to solve this problem, add -ObjC to your linker flag, check details in following links
http://developer.apple.com/library/mac/#qa/qa1490/_index.html
https://stackoverflow.com/a/2615407/642626
from the apple documentation:
The class object named by aClassName, or nil if no class by that name is currently loaded. If aClassName is nil, returns nil.
Either you variable "className" is nil, or class was not loaded in runtime before this call.
Try to force load this class with this:
[CCLabelTTF class];
anywhere in the code.
For future: try searching your question before creating new one.

Objective-c add support for new classes to old devices

The problem: every new iOS adds a lot of new useful classes. For example, UIRefreshControl. I want to add support for this class in iOS5 build.
Not cool solution: In all classes that must use UIRefreshControl, I can check for current iOS version and use inline replacement for that classes, for example:
pseudocode
...
- (void)viewDidLoad
{
...
if([[UIDevice currentDevice].systemVersion floatValue] < 6.0)
{
self.refreshControl = [[MyCustonRefreshControl_for_iOS5 alloc] init];
}
else
{
self.refreshControl = [[UIRefreshControl alloc] init];
}
...
}
This solution is't cool, because I must add same code in all classes where I want to use latest iOS features.
Possible cool solution:
1) get or create your own 100% compatible class, for example for UIRefreshControl you can use CKRefreshControl (https://github.com/instructure/CKRefreshControl);
2) use Objective-C runtime to define replacement class as main class when App starts.
pseudocode
...
// ios 5 compatibility
#include <objc/runtime.h>
#import "CKRefreshControl.h"
...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
...
// pre-ios 6 compatibility
if([[UIDevice currentDevice].systemVersion floatValue] < 6.0)
{
// register refresh control
Class clazz = objc_allocateClassPair([CKRefreshControl class], "UIRefreshControl", 0);
objc_registerClassPair(clazz);
}
...
}
I think that this way is really cool, but this code won't work.
You may want to make one consistent interface with different ways of doing the job. You need a strategy design pattern to solve your problem. Then you need to check for version only once - at initialisation of object which is doing iOS version specific job.
If all method calls are identical (and no class/"static" methods to speak of), simply use a "factory" method to create the objects and then use them "normally".
Otherwise, I'd probably use a "wrapper" class that reroutes calls to either the builtin support or your "replacement", based on one of the tests Filip's post.
The second soultion should work fine
There's can be some issues when ARC is enabled, so, you should move allocate_pair code to some class, that is compiled with -fno-objc-arc flag
For more information, look here (in comments):
http://www.mikeash.com/pyblog/friday-qa-2010-11-6-creating-classes-at-runtime-in-objective-c.html
#abuharsky, [CKRefreshControl]https://github.com/instructure/CKRefreshControl has been updated and now does exactly what you are asking for. All you need to do is:
self.refreshControl = [[UIRefreshControl alloc] init];
Let us know if that doesn't work for you.

A bit of annoying warnings that still let the app work but would like to remove

I tried out an app to test bluetooth communication. It is a simple app that just sends a message in text form from one iDevice to another. Originally, this app had about 6 warnings but I fixed all but two. They are the same but deal with different delegates. One is for the GKPeerPickerControllerDelegate and the other for the GKSessionDelegate. Say the Picker error is for the GKPeerPickerController named picker, when you type (more complete example to follow):
picker.delegate = self;
the compiler says:
Passing '*const___strong' to parameter of incompatible type 'id'.
For the GKSession named session, typing
session.delegate = self;
makes the compiler say:
Sending '*const___strong' to parameter of incompatible type 'id'.
These only pop in the button to send and peerPickerController. I know that these warnings do not impede on the app's ability to function but I would like to completely update this for Xcode 4.2. This app was originally written for Xcode back when iOS 3.0 was new. Yes, I am a bit picky when it comes to writing or practicing code, it must not contain any errors/warnings whenever possible.
These are the code blocks where the warning occur:
-(IBAction)btnConnect:(id)sender{
picker = [[GKPeerPickerController alloc] init];
picker.delegate = self; //Warning here
picker.connectionTypesMask = GKPeerPickerConnectionTypeNearby;
[connect setHidden:YES];
[disconnect setHidden:NO];
[picker show];
}
-(void)peerPickerController:(GKPeerPickerController *)PCpicker didConnectPeer:(NSString *)peerID toSession:(GKSession *)session{
self.currentSession = session;
session.delegate = self; //Warning here
[session setDataReceiveHandler:self withContext:nil];
PCpicker.delegate = nil;
[PCpicker dismiss];
}
Edit:
The header has this:
#interface BTViewController : UIViewController{
GKSession *currentSession;
IBOutlet UITextField *txtMessage;
IBOutlet UIButton *connect;
IBOutlet UIButton *disconnect;
GKPeerPickerController *picker;
}
I believe whatever class self is may not be adopting the GKPeerPickerControllerDelegate and GKSessionDelegate formal protocols. Can you post your interface header?
EDIT
Casting to id will clear the warnings, but you really didn't "fix" anything...looking at the class header, it is not adopting the protocols that the delegates are expecting.
Modify your interface to adopt those protocols:
#interface BTViewController : UIViewController <GKPeerPickerControllerDelegate, GKSessionDelegate> {
What about session.delegate = (id)self. Maybe you just need to cast self as ID instead of const____strong.
EDIT: At the bequest of the OP, an explanation is in order. Type id is necessary for the protocol, because the protocol itself is literally typecast to id itself (id<GKSessionDelegate> etc.). My theory (because I am not using ARC in any of my projects) Is that the compiler gets very exacting so it can guarantee that your class is safe for release. You probably initialized your class in a non-id way... Of course I have no idea how, if anyone knows; I'd be happy to let them edit this answer.
EDIT 2: as Teddy said, adopting the protocols in your header file also silences this warning. I apologize for thinking it was implied that you had adopted the protocols.

Question about instantiating object

I am new to Objective C and Cocoa. Really don't like the syntax as I'm from Java and C#. I'm trying to do something simple and I get the following error:
I import this in using
#import "Defaults.h"
-(void) awakeFromNib{
Defaults *theDefaults = [[Defaults alloc] init];
}
-(IBAction) addPlanets:(id)sender{
[theDefaults setValue:[planetsButton titleOfSelectedItem] forKey:#"planets"];
NSLog([planetsButton titleOfSelectedItem]);
}
The error I get is
Unknown Receiver theDefaults; Did you mean "Defaults"?
Can someone help me on what this is?
theDefaults doesn't exist in the scope of addPlanets:. You need to make it a global or an instance variable, rather than creating it in awakeFromNib and immediately leaking it.