I know there are questions on here similar to this, but I have not been able to sort it out.
I have a view that has this in the .m above the implementation
CFDataRef CopyImagePixels(CGImageRef inImage){
return CGDataProviderCopyData(CGImageGetDataProvider(inImage));
}
Everything works fine, but I have another view that needs to access that same function, if I put it in /that/ views .m file, same location.. the compiler throws a duplicate symbol error..
The only file these two have in common that they include is:
#import "MopalAppDelegate.h"
I thought maybe putting the code in the AppDelegate, but that throws the same error when I attempt to build..
I am still quite new to obj-c, any suggestions would be greatly appreciated.
Thanks.
Edit: The error:
ld: duplicate symbol _CopyImagePixels in /Users/critter/Library/Developer/Xcode/DerivedData/Mopal-dtgtjbahdowmuderbstlmsiznwsi/Build/Intermediates/Mopal.build/Debug-iphonesimulator/Mopal.build/Objects-normal/i386/ViewerController.o and /Users/critter/Library/Developer/Xcode/DerivedData/Mopal-dtgtjbahdowmuderbstlmsiznwsi/Build/Intermediates/Mopal.build/Debug-iphonesimulator/Mopal.build/Objects-normal/i386/StudyListDetailController.o for architecture i386
collect2: ld returned 1 exit status
Command /Xcode4/Platforms/iPhoneSimulator.platform/Developer/usr/bin/gcc-4.2 failed with exit code 1
Your function is being declared and defined in the global scope. When you place the same function definition in two different .m files, you end up with two different functions (as far as the compiler is concerned) that have the same name in the same scope (global), leaving it with no way of knowing which one you intend to call when you say CopyImagePixels(myImage);. Hence the error message.
So there are a couple of options. One is to define your function as a private member function on the objects that use it, like:
#implementation MyClass
- (CFDataRef) copyImagePixels: (CGImageRef)inImage {
return CGDataProviderCopyData(CGImageGetDataProvider(inImage));
}
#end
The other (and less preferred) option is to move your function declaration to a shared header file, like MopalAppDelegate.h, and its implementation into your MopalAppDelegate.m file. This creates a function declaration that can be shared out to other classes, with a single definition in the .m file.
You want to put the function definition in a header that the two files share, implement it in the corresponding .m file, and import that header into both views.
But if that's all the function does, why not just call CGDataProviderCopyData directly in both places?
Related
Please see below edit for current (minor) issue
I'm trying to call methods (methods right, not functions?) "between" the MainViewController.m and the FlipsideViewController.m -- from one file/class to another.
I guess this is what's often referred to as "Call methods from another class". There are plenty of such questions around, I know, but I just can't get it to work properly.
In my case, I have several user defined methods/functions in both above mentioned files. Sometimes, I need to call a method from within the FlipsideViewController.m that lies within the MainViewController.m File:
// in MainViewController.m
- (void) calculateDays {
//executes caluculations
// inserts data into labels, etc
}
If I want to call this function simply from within the same file, I just do:
[self calculateDays];
That's easy, however, I want to call this function from within the FlipsideViewController.m file too, as well as vice versa. So how do I do this? This, this and this questions sort of answer it but it doesn't quite work to me. I'll explain why in just a second.
This is what I've tried and think should work:
MainViewController *mvs = [[MainViewController alloc] init]; //alloc init MVC
[mvs calculateDays]; //call "external" function
It gives me the error: "Unknown type name MainViewController". So I assume I have to include/import it somehow for it to work (just like in javascript or PHP). So I include it in the FlipSideViewController.m class:
#import "MainViewController.h"
Great no errors so far. Then I try to compile/build it and runs into another error:
"clang: error: linker command failed with exit code 1 (use -v to see invocation)"
"ld: 3 duplicate symbols for architecture armv7s"
This leads me to think that importing the MainViewController like that isn't the way to go as I then import lots of other stuff that may interfere with some code in the FlipSideViewController class.
I've tried similar solutions but nothing seems to work. Can anyone please explain to me what I'm doing wrong, and perhaps how to do this properly: Call methods between MainViewController.m and FlipsideViewController.m and vice versa.
The proposed solution by H2CO3 did solve most of the issues (XCode bugged for a while and give me random errors which forced me to rebuild the entire project) but there's still this one thing that doesn't quite work: change the content of a UILabel (UIOutlet). Please see if anyone of you can help me with this:
When the method is called from within self (i.e. [self calculateDay]), the value is successfully inserted into the UILabel. When called from FlipsideViewController, the value to be inserted exists and is processed successfully, but can't be inserted into the UILabel. Please se below.
Some loggings:
//method called from within self on viewDidLoad: [self calculateDay];
Processed value to update label with: 26
New value in outlet after having been inserted: 26
//method called from another (FlipsideViewController) class file: [mvs calculateDay];
Processed value to update label with: 26
New value in outlet after having been inserted: (null)
/*
This doesn't work either from that external file:
[[mvs LabelName] setText:#"Hello, update label!"]; no errors but no display either
*/
If you import the header instead, that should give you all the necessary declarations, but you won't have "duplicate symbol" linker errors. This is a "standard"/common practice for writing (Objective-)C code.
#import "MainViewController.h"
^
".h" instead of ".m" -+
(layman's terms) In Objective-C you can only use objects that each file knows about. In this example you are trying to use a MainViewController in the FlipsideController.m file. The FlipsideController.m has no idea what a MainViewController is, so it throws errors because it doesn't know what it is or how to use it. You have two options for telling the Flipsidecontroller what a MainViewController is, you can import the header (#import "MainViewController.h") which will give you full access to everything defined in the FlipSideController.h. (You should probably never import a .m unless you really know what your doing) You can also create a forward declaration - #class FilpsideControllerin the .h and import the file in the .m. This is useful to avoid circular imports etc.
I am reading about iOS programming and I bought the Programming iOS 4 book. There is a introductory part where among several things "Files" is mentioned.
I don't understand how the source files is put together. You have a header file with function declarations, then you have a corresponding file with the function definitions.
Let say you have a Car.h and Car.m & Person.h and Person.m.
Now, if you want to use the Car in the Person class you would import only the Car.h file. How is this sufficient? I don't understand the sequence it put together and builds a program. (Not thinking about the technical stuff, just h/m files.)
The .h or "header file" contains the interface.
The .m or "implementation file" contains the implementation.
Each implementation file is also called a "compilation unit" because the compiler compiles each one separately. Within each compilation unit, the compiler needs to know about types and methods. All it needs to know about a class to create the right code is information about the methods it implements.
So let's imagine you have these files:
Car.h
#import <Foundation/Foundation.h>
#interface Car : NSObject
- (void)drive;
#end
Car.m
#import "Car.h"
#implementation Car
- (void)drive {
NSLog(#"I'm driving!");
}
#end
Person.h
#import <Foundation/Foundation.h>
#class Car;
#interface Person : NSObject
#property (nonatomic, strong) Car *car;
- (void)start;
#end
Person.m
#import "Person.h"
#import "Car.h"
#implementation Person
#synthesize car;
- (void)start {
[car drive];
}
#end
Now when the compiler does its business, it compiles both Car.m and Person.m into Car.o and Person.o respectively. [These then get linked into the final binary, but that's beyond the scope of this question for now].
When it compiles Person.m, the compiler doesn't need to know how - (void)drive of Car is implemented, but it does need to know that it exists, that it is a method that takes no arguments and returns nothing. It doesn't care about the implementation, just that it exists. So you just need to #import the header file of Car to tell the compiler about the methods that exist on Car. The compiler knows that the implementation exists, because you've told it so, and then later on the linker will do it's business to correctly wire up the method call to the correct implementation. How the linker actually does that is a huge topic and I encourage you to go and read about it separately if you don't already understand it.
Note that it's the same for all of the standard NS classes that you use such as NSObject, NSString, etc. You just need to #import Foundation.h from the Foundation framework which tells the compiler about what these classes are and what methods are defined on them.
Creating an executable from a set of source code files is a two stage process.
Firstly, all of the .m files are individually compiled with the Objective-C compiler. This turns each one into a .o file which is an object code file. However, if the code in a .m file refers to things that are defined in other .m files, the compiler does not know about these so it just leaves unresolved references in the .o file.
The second stage is called linking. This takes all the .o files and combines them into an executable. When the linker finds unresolved references in one .o file, it checks all the others to resolve the reference.
Header files allow the compiler to have some information from outside the particular .m file it is currently compiling. So if you have two classes Foo and Bar they are conventionally defined in files Foo.m and Bar.m In order for the compiler to know what class Bar looks like when it is compiling Foo.m we put class Bars interface declaration in a header file (conventionally Bar.h) and import it into your .m file. If you see the line
#import "Bar.h"
it is literally as if the compiler has copy-pasted the entire header file into the source code file before compiling it.
What language have you been using until now? Many languages do it this way including c and c++. The m files are compiled into an actual program, and the h files provide a list of ways to interact with it. While you can still call the methods if you interact with the objective c runtime, the compiler will not guarantee their existence unless they are in the h file.
Now, I say guarantee, but if you dont provide an implementation in the m file, the sibling to the compiler, the linker will have a fit. It will try to make a jump into another m file based on its h file only to tragically discover that it is not there.
The benefits of splitting like this is that you can compile your source into a library and distribute it along with the h files and another application can use it without having the implementation source code.
In summary the m files compile into a lost island of bits and the h files are the map to get around it. If something is on the map that doesnt exist then you will get lost. If something exists but is not on the map then you will have a lot of trouble finding it.
Header files specify what messages ("methods" in other languages) can be passed to a class. That's all the compiler needs to know to compile your code; the linker will eventually wire everything up, so to speak, using the *.m files.
The compiler will handle that for you.
As you stated, a header file contains just the declarations.
Its like a interface to the actual code and that is the only thing Compiler needs to know to fetch the rest.
I'm on this step of the "Your First iOS Application" tutorial from Apple.
However, the line [self setMyViewController:aViewController]; has an error and the app appears as a blank black screen. The error message is 'HelloWorldAppDelegate' may not respond to '-setMyViewController' (2)
I've been following the tutorial carefully. How can I make this error go away? Why is it so ambiguous (it "may" not respond? under what circumstances will it?) and why am I getting this error in the first place? What step did I miss?
Go to your header-file and add - (void)setMyViewController:(UIViewController *)viewController;
Maybe you need to rename the parameter.
And btw. it's a warning not an error. Warnings are just for signalize that it could have problems if you haven't included the method.
If you declare a method in your .h file, the .m file gives out a warning if it isn't included. Don't worry it's not wrong if you forgot to declare a method in your .h file.
Are you running your code right after following that step? You should hold off doing so until you have finished following all steps on the page.
The Housekeeping section lists a step that you have to follow in order to make your property setter work:
In the #implementation block of the class, tell the compiler to synthesize the accessor methods for the view controller:
#synthesize myViewController;
After you finish adding the code as described by that section, running your code should work. If not, check your imports and your HelloWorldAppDelegate.h file — you may have missed something else too like declaring your #property.
Why is it so ambiguous (it "may" not respond? under what circumstances will it?)
It will respond if the compiler can find an implementation of the method, and the method is declared in the header file (unless it's a property accessor), and work as normal. If it does not, your program crashes.
and why am I getting this error in the first place?
You typically get that warning (it's not an error) if the property is not synthesized. By synthesizing it, the compiler creates the myViewController and setMyViewController: accessor methods in order for your code to access that property.
That should be a warning not an error.
Take heed of warnings, and you're right to want to eliminate them, but the code will compile and may run with warnings.
The warning could be occurring because there isn't a prototype for the method setMyViewController before it is referenced. The prototype is usually defined in the associated header '.h' file.
The prototype looks like the entry line of the method, up to, but not including the first '{', and with a ';' on the end.
Adding a prototype allows the compiler to verify you're calling the method correctly (and just as importantly, you typed it correctly ;-)
XCode has been acting really, really strange recently. It is telling me that various classes' methods and properties do not exist - but they do! This is happening both with a custom class, and a Core Data class. I have declared all of the methods and properties, including all the necessary #synthesize calls, and have predeclared the classes using #class in the files which use them and included the .h files, but when I try to access the methods & properties - it throws errors or warnings, along the lines "No '+newMatrix' method found", "'Collection' may not respond to '+newMatrix'", and "Request for member 'isLanguage' in something not a structure or a union." These have all be declared properly - what could be causing XCode to choke?
Check whether they are in the list of files being compiled. You might not have added the files.
For Core data did you include the Framework?
Make sure you're using the right import statements - these two are very different:
#import <SDKLibrary.h>
#import "CustomClass.h"
So, I read this post, and it's pretty much exactly what I was looking for. However... it doesn't work. I guess I'm not going to go with the singleton object, but rather making the array in either a Global.h file, or insert it into the _Prefix file.
Both times I do that though, I get the error:
Expected specifier-qualifier-list before 'static'
and it doesn't work. So... I'm not sure how to get it to work, I can remove extern and it works, but I feel like I need that to make it a constant.
The end goal is to have this Mutable Array be accessible from any object or any file in my project. Help would be appreciated!
This is the code for my Globals.h file:
#import <Foundation/Foundation.h>
static extern NSMutableArray * myGlobalArray;
I don't think I need anything in the implementation file. If I were to put that in the prefix file, the error was the same.
EDIT
So, I removed the .m file from Globals, and I just have the code about in Globals.h. Assuming I am going to continue with this terrible practice of having global variables (I know it's bad, I just want to test this out), I now have a new error. It says:
"Multiple storage classes in declaration specifiers"
If I remove "extern" it works and if I remove "static" it works, but having both doesn't... what now?
****Double Edit****
Aright, so I've tried adding the array to my UIApplication Delegate, but I'm doing it wrong because it isn't working. Could someone give me some example code as to where to place it an access it? I don't know if it should go in the implementation, or somewhere else, and once the array is initialized how to access it from the other files... Do I set a new variable to the array, or something?
Just a general programming suggestion--don't share an array. You have no control over it and it will be virtually impossible to trace if something changes it at a time and in a way you aren't expecting.
Instead, create an object with the array inside it and make that object a singleton (or better yet, make a factory for it).
Whenever you want to modify your array, call methods on the object to do so. If you do this, I bet you will find a lot of redundant code you can factor into this object (for instance, searching the array for a value--make a "search" method in the object instead and pass in a value).
It may seem like a lot of work you shouldn't have to do, but you'll find it's fairly fun work, and you should find that you DO have to do it once you see how much code belongs in this object...
Just add the array as a property of the application delegate, and access it like:
[[UIApplication sharedApplication] myArray];
The two (main) ways of making an array global are separate -- either you have a class with a method
static NSMutableArray *foo;
+(NSMutableArray *)foo {
return foo;
}
(in the .m file) with the static piece NOT in the header file, or just
static extern NSMutableArray * myGlobalArray;
with out the singleton wrapper (which I think is better as it saves you from having an extra bit of unnecessary code)
Either way, it is still a bad practice that I would try to avoid.
In general, the presence of a "Globals.h" file is a bad smell that there's an antipattern at work.
I would even advise against Bill K's advice and not use a Singleton pattern at all.
Instead, create the array in your app delegate, and pass it to your root view controller(s), and along the hierarchy to the components that need access to it.
This is what I was looking for:
http://derekneely.com/tag/app-delegate/
Thank you for pointing me in the right direction!
#import <Foundation/Foundation.h>
static extern NSMutableArray * myGlobalArray;
#interface Globals : NSObject {
}
#end