I've got a problem with calling methods in external files which I have imported into my project. The methods are for some reason not being called, even though the project compiles ok. And there is no error message/ output in the console.
Can someone help?? Here's the full problem:
(1) I downloaded the Flickr API (4 files) written by the author of this tutorial and drag&dropped into the Xcode file manager, specifying to copy and link the 4 files with my project.
* Flickr.h
* Flickr.m
* FlickrPhoto.h
* FlickrPhoto.m
(2) In the main view controller, I first import the external files
#import "Flickr.h"
#import "FlickrPhoto.h"
(3) Then I define a property to hold the object, in the #interface section:
#property (weak, nonatomic) Flickr *flickr;
(4) In viewDidLoad, I allocate a new instance of the object:
self.flickr = [[Flickr alloc] init];
(5) Then in a later method, I call one of the methods in the API:
[self.flickr searchFlickrForTerm:textField.text completionBlock:^(...) { ... }];
However, the method is not getting called: I have put a NSLog line right before this method call, and it prints to console. I also put an NSLog in the first line of the method:
- (void)searchFlickrForTerm:(...) term completionBlock: ...
and it is not printing anything.
Why is this method not being called???!!! Never had this problem before. Its really annoying.
Try changing your property to be strong instead of weak, and see if that fixes your issue:
#property (strong, nonatomic) Flickr *flickr;
If that fixes it, the issue was your property was being deallocated before you were able to use it. You wouldn't see any error, because a "weak" property ensures that a pointer is set to nil once the object is deallocated (and Objective-C doesn't throw errors on sending messages to nil).
Related
I've looked at a lot of posts on this and it usually seems to revolve around missing an import in the .h or the .m
In my case I am trying to import a swift objective C function but I believe the .h, .m and swift files are configured correctly (as is the generated swift-header).
My Swift class is flagged as #objc and extends NSObject.
When I import the class in the .h using forward declaration, and in the .m using the MyApp.h import, it can see the class. However, it cannot see the method I want and it gives me the error Receiver type 'class' for instance message is a forward declaration.
When I check the generated header file, the method is generated there (and the method is flagged as an #objc and returns an #objc compatible value).
Can you suggest what might be causing this issue?
Here is a reference of what my code is like:
Swift
#objc class ObjcHelper: NSObject {
#objc static let shared = ObjcHelper()
#objc public func getObjcFromNSString(nsString: NSString) -> ObjcType {
return ObjcType()
}
}
In the .h for the objective c file I want to use it in:
#class ObjcHelper
And in the .m I am importing the app header
#import <App-Swift.h>
When I try to use the code in the .m file the compiler can see this part fine:
[ObjcHelper shared] // Compiler sees this fine!
But if I try to call the method it doesn't autocomplete or find it even if I type it in.
If I look in the generated header, I see the method is here like so:
SWIFT_CLASS("_TtC7ObjcHelper")
#interface ObjcHelper : NSObject
SWIFT_CLASS_PROPERTY(#property (nonatomic, class, readonly, strong) ObjcHelper * _Nonnull shared;)
+ (\ObjcHelper * _Nonnull)shared SWIFT_WARN_UNUSED_RESULT;
- (enum ObjcType)getObjcFromNSStringWithNsString:(NSString * _Nonnull)nsString SWIFT_WARN_UNUSED_RESULT;
- (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;
#end
The code I expect to work that doesn't is as follow (and which generates the error):
ObjcType value = [[ObjcHelper shared] getObjcFromNSStringWithNsString: #"abc"]];
The issue is rather nuanced but it seems to have been solved.
In my project there are a number of targets and for the ObjcHelper it wasn't targeting one of the targets. I believe what was happening is that even though the bridging objective c helper file was created, there was an issue with a reference missing a 'required' target owner and this error propagates forward as not being able to find the class.
So if you are getting this issue, check to make sure that the Swift class you are trying to bring into objective-c has its target membership set to all the targets it needs (otherwise you might get a misleading error about forward class declaration).
I've got a custom class BoardMatchData, containing information about a chess match.
I've also got a custom UIViewController named BoardViewController, which is alloc'ed when a user selects a match from a list.
Here's a snippet from where I create the BoardViewController, set its delegate, and then set the new BoardMatchData:
Games *selectedGame = [[self fetchedResultsController] objectAtIndexPath:indexPath];
if (!self.bvc) {
NSLog(#"Alloc-ing a BVC");
self.bvc = [[BoardViewController alloc] init];
self.bvc.delegate = self;
}
[self.bvc setNewBoardMatchData:[MasterViewController boardMatchDataFromGame:selectedGame]];
When debugging, I can see this method setNewBoardMatchData being called, and it has valid data coming into it. However, later on within the BoardViewController, this boardMatchData always seems to be nil. Here's the setNewBoardMatchData method:
- (void)setNewBoardMatchData:(BoardMatchData *)newBoardMatchData {
NSLog(#"BMD is being set");
if (self.boardMatchData != newBoardMatchData) {
self.boardMatchData = newBoardMatchData;
[self configureView];
}
if (self.masterPopoverController != nil) {
[self.masterPopoverController dismissPopoverAnimated:YES];
}
}
And within BoardViewController.h, I just have an instance variable:
BoardMatchData *boardMatchData;
A method declaration:
- (void)setNewBoardMatchData:(BoardMatchData *)newBoardMatchData;
And then at the top of BoardMatchData.m, I have:
#interface BoardViewController ()
#property (strong, nonatomic) UIPopoverController *masterPopoverController;
#property (nonatomic,retain) BoardMatchData *boardMatchData;
- (void)configureView;
#end
#synthesize boardMatchData = _boardMatchData;
...my intent here was to make sure that the setter was only ever being called by itself, and not by some other object.
Is there something wrong with how I'm trying to set self.boardMatchData?
I'm not doing any retains/releases because I'm using ARC.
Edit:
Caleb - I did that #synthesize statement as part of my flailing around trying to find this bug. Originally I had:
#synthesize boardMatchData;
... which I just switched back to. The behaviour is the same; self.boardMatchData always ends up nil, even after I've set it.
I think now I have only one ivar, boardMatchData, and I'm always accessing it through self.boardMatchData.
How do I prevent this from becoming nil?
#synthesize boardMatchData = _boardMatchData;
This says that the ivar the accessors should use is _boardMatchData, but you've also got an ivar named boardMatchData. If you're using the accessors, only _boardMatchData will be set. Since Objective-C automatically clears any ivars when your object is created, theboardMatchData ivar will always be nil.
Your comment (that you posted as an answer which you shouldn't do) suggests that you work on two different instances.
Here are a couple of possible reasons for this:
self.bvc is just assign property instead of retain.
You load one from within a nib and one is constructed in your code
(as shown) - this is probably the most like one. Maybe you just
forgot to wire up the outlet.
Your set self.bvc to nil somewhere so that you keep creating new
instances.
Aha; I found this question with an almost identical problem:
Objective-C – Retained property after being set is nil?
There was no conclusion to that one, but the last suggestion was to "try logging the address of self in -viewDidLoad and -viewWillAppear and -queueFinished. Something like NSLog(#"self is %p", self); and making sure they are the same."
I did that myself and now see that in initWithNibName/configureView/setNewBoardMatchData, I'm seeing one pointer for self, and then when viewDidLoad runs, I'm getting a different one!
I'm not sure how or why yet, but this clearly appears to be the problem (a new instance of my class is being instantiated AFTER I've set boardMatchData).
Edit:
While the above led me to the path of finding this bug (I was getting multiple versions of my BoardViewController), it's not the complete answer. I wanted to add here should anyone find this and be in the same position.
I was actually using storyboarding in Xcode4, and the Apple provided master-detail template with Core Data.
When I was instantiating my detail controller (BoardViewController), I was doing an alloc/init. I should have simply been referencing [segue destinationViewController], as the segue already instantiated a version for me.
I did not provide enough context to actually get to the root
I've gotten to a point where I'm starting to think this is may actually be a bug in Xcode, but to be sure, I'm asking it here. I was working on my app that uses MapKit and CoreLocation, but at some point I started getting the warning "Property 'coordinate' requires method '-coordinate'". At first I thought I was doing something wrong, as I did use the property coordinate for an MKPointAnnotation, but after I commented that out, the warning remained.
In fact, after I've commented out pretty much everything, I still get the warning. It tells me the file name and line number (the line with #end), but if I search for coordinate in that file, there aren't any results. The .h doesn't declare the property either, so I'm really lost as to where this error is coming from... I can provide you with code, of course, but I've commented so much stuff out that it doesn't really make any sense to post it here. Just a few memory management methods without any actual content other than sending a message to super...
Xcode is correct in telling you that you're required to implement -coordinate. This is a non-optional method of the MKAnnotation protocol.
http://developer.apple.com/library/ios/#documentation/MapKit/Reference/MKAnnotation_Protocol/Reference/Reference.html
coordinate The center point (specified
as a map coordinate) of the
annotation. (required) (read-only)
#property (nonatomic, readonly)
CLLocationCoordinate2D coordinate
I believe the reason you can't synthesize coordinate is not because you didn't declare the property, but because you haven't told the compiler what storage to use.
Adding
CLLocationCoordinate2D coordinate;
to the fields (variables) section of your class interface will give the compiler the storage it is looking for.
Or you can point the compiler to other storage using this syntax:
#synthesize coordinate=myCoordinateVariable;
But none of that really matters, because you don't have to use synthesize.
Just implement the method yourself! The required part is readOnly so you only need to implement the getter.
-(CLLocationCoordinate2D)coordinate {
return myCoordinate;
}
#property and #synthesize are primarily shortcuts. #synthesize just says to the compiler - "Implement these accessors if I haven't". But normally you declare a property like this, right?
#implementation MyClass : NSObject {
NSString *someString;
}
#property (nonatomic, retain) NSString *someString;
and then you synthesize it. #synthesize creates the appropriate implementations for the declarations implied by #property:
-(NSString *)someString;
-(void)setSomeString:(NSString *);
and uses the storage you provided when you declared the instance variable, NSString *someString.
Incidentally, in Xcode 4 #synthesize automatically creates storage for you if it doesn't already exist.
I've had the same problem for over a year on one of my apps. Nobody has ever been able to offer an explanation. I just got to the point of adding a mapview to my latest app and had only gotten as far as adding the MapKit Framework to the project, declaring support for the MKMapViewDelegate and MKAnnotation protocols then I did the #imports for MapKit/MapKit.h and MapKit/MKAnnotation.h. Build the app and Bang! there's the warning.
So, I commented out the MKAnnotation protocol declaration and like magic the warning went away. The only conclusion I can come to is that this is an Xcode issue.
Very strange this problem. I just added the following line as Ball suggested and my warning disappeared.
#synthesize coordinate=myCoordinateVariable;
Thanks Ball for the info.
I get a bad access (objc_msgsend) when calling this line of code:
self.currentGameTeam = nil;
Where "currentGameTeam" is defined in the interface for a class called "MCState" as:
MNAvailableTeamContext *currentGameTeam;
And I synthesize a property for it:
#property (retain) MNAvailableTeamContext *currentGameTeam;
After setting NSZombieEnabled the console shows:
*** -[MNAvailableTeamContext release]: message sent to deallocated instance 0x5b3eba0
And the debugger trace shows that it comes from within the synthesized setter code:
#3 0x0001fa96 in -[MCState setCurrentGameTeam:] at MCState.m:44
I've looked at several other questions and threads and I can't find an answer that applies to my case. I don't understand why there would be a bad access if I've synthesized the property and I'm setting it to nil. What is especially odd is that there are at least 3 other properties in MCState which are defined and used in the exact same way as currentGameTeam, with the only difference being that they are different types:
MNUserContext *storedUser;
MNActiveGameContext *storedGame;
MNAvailableUserContext *storedGameUser;
MNAvailableTeamContext *storedGameTeam;
and
#property (retain) MNUserContext *currentUser;
#property (retain) MNActiveGameContext *currentGame;
#property (retain) MNAvailableUserContext *currentGameUser;
#property (retain) MNAvailableTeamContext *currentGameTeam;
and
#synthesize currentUser;
#synthesize currentGame;
#synthesize currentGameUser;
#synthesize currentGameTeam;
finally
self.currentUser = userContext;
self.currentGame = nil;
self.currentGameUser = nil;
self.currentGameTeam = nil; // Error occurs here
The rest of these all act normally - only currentGameTeam gives me trouble. Any ideas?
Somewhere, currentGameTeam is being released before you attempt to set it to nil. Setting a retained property to nil implies a release to be called. Calling release on an object that has already been released will result in a EXC_BAD_ACCESS. This is confirmed with your running with NSZombies enabled.
You can run with Instruments with the Zombies tool - it will give you more detail about all of the retains, releases and autoreleases leading up to the zombie call.
Do you have the ivar named currentGameTeam ?
I've had some bugs like this an usually tracked them down to a typo someplace where I meant to type currentGameUser but have typed currentGameTeam so I end up double-releasing one of the objects and not releasing another. I would try doing a Build and Analyze to and if that doesn't find anything try Run with Performance Tool > Leaks.
I say this since your code looks fine except you declare stored* and then declare and synthesize properties for current*, which looks like an inconsistency so there may be other places where this kinds of close-but-different typos may have occurred.
Last time set to nil should already set that to nil.
So the next time set to nil should not harmful. Not sure why crash.
I got the "objc_msgSend()" killer error message in my app and thanks to Hamster Emporium
i can figure out a little bit what was happening.
Now i found the "problem" and the "solution", but what i can't understand why my problem was really a problem.
Here is the scenario:
Object_A --> Object_B --> Object_C
The '-->' symbol represent the "create" action.
Class of Object_C looks like this:
#interface Class_C {
NSArray *items;
}
#property (nonatomic, retain) NSArray *tems;
#end
The property 'items' is set in Object_B through a 'setItems' method:
- (void)setItems:(NSArray *)items_ {
if (object_B) {
[object_B.taskItems release];
object_B.taskItems = items_;
}
[super setItems:items_];
}
Now, if I use this method as is I got the blasphemous 'objc_msgSend()' error BUT if I comment the release line everything goes well.
Note: the retainCount in the release line is 0, but the release execute without problems
You are getting that error because the taskItems member variable is being released twice. There is no need to manually release taskItems because using the dot syntax takes care of it automatically.
This line:
object_B.taskItems = items;
Invokes the property accessor for taskItems, in which the old value is automatically released before the new one is retained (or copied, depending on the property definition).
A very good general rule for Cocoa memory management is that you should only release an object if you created it (either by alloc/init or by copy). Releasing object_B.taskItems would violate that rule.
Uhm, wow. ok.
object_B.taskItems = items_;
is the same as calling
[object_B setTastItems: items_];
if taskItems is a property set to retain, you don't need to release it first since the property will do so. The way you have your code right now, it gets released twice.
Remember, properties are not the same as members in Objective-C. Properties are methods which access the private members of the class (and do fancy stuff like retain/release and #synchronized).
I had a similar problem, but in my case this was the scenario:
I made a controller that registers itself to listen for changes in a NSOperation attribute "isFinished", while the NSOperation was working my controller went away, when the NSOperation finished and tried to notify:
[self willChangeValueForKey:#"isFinished"];
I got
objc_msgSend() corrupt cache error
But it was because my Controller was out of scope, to fix it I wait for the results of NSOperation KVO and then move to next controller.