I have a very small obj program
Header test.h is
#import <Foundation/Foundation.h>
#interface Token : NSObject {
#private
NSString * literal;
size_t line;
size_t column;
}
#property (readonly) size_t line;
#property (readonly) size_t column;
#property (readonly) NSString * literal;
+ (id)newReturnTokenAtLine: (size_t) line column: (size_t) column;
- (id)initWithLine: (size_t)aLine withColumn: (size_t)aColumn;
#end
#end
And the implementation in test.m is
#import "test.h"
#implementation Token
#synthesize line;
#synthesize column;
#synthesize literal;
+ (id)newReturnTokenAtLine: (size_t) aLine column: (size_t) aColumn {
Token * tok = [Token alloc];
return (Token*) [tok initWithLine: aLine column: aColumn];
}
- (id) initWithLine: (size_t) aLine withColumn: (size_t) aColumn {
line = aLine;
column = aColumn;
return self;
}
#end
My problem is that it seems the objective C compiler thinks that the initWithLine is not defined
test.m:13:27: error: instance method '-initWithLine:column:' not found (return type defaults to 'id') [-Werror,-Wobjc-method-access]
return (Token*) [tok initWithLine: aLine column: aColumn];
^~~~~~~~~~~~~~~~~~~~~~~~~~
./test.h:5:12: note: receiver is instance of class declared here
#interface Token : NSObject {
^
1 error generated.
Am I missing something obvious?
I try to have this in an automake setup. Thus configure.ac is
define(MINIOBJC_CONFIGURE_COPYRIGHT,[[
public domain
]])
AC_INIT([miniobjc], [0.0.1])
AC_CONFIG_SRCDIR([test.m])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_AUX_DIR([build-aux])
AM_INIT_AUTOMAKE([foreign serial-tests])
AC_PROG_CC
AC_PROG_OBJC
AC_PROG_LIBTOOL
AC_CONFIG_FILES([Makefile])
AC_CONFIG_FILES([env],[chmod +x env])
AM_SILENT_RULES
AC_SUBST(OBJCFLAGS)
AC_SUBST(CFLAGS)
AC_OUTPUT
and Makefile.am is
lib_LTLIBRARIES = libminiobjc.la
libminiobjc_la_SOURCES = test.h test.m
libminiobjc_la_OBJCFLAGS = $(AM_CFLAGS) -Werror=objc-method-access
In Objective-C the name of a method includes all argument labels and the semicolons. -initWithLine:column: doesn't exist, use -initWithLine:withColumn: instead or replace
- (id) initWithLine: (size_t) aLine withColumn: (size_t) aColumn
by
- (id) initWithLine: (size_t) aLine column: (size_t) aColumn
Related
I wrote two programs during a training. But one exercise task drives me crazy. Not the task itself but the program and the behavior of it.
The first program is to calculate the BMI of a person. Here it works all fine.
main.m
#import <Foundation/Foundation.h>
#import "Person.h"
int main (int argc, const char * argv[])
{
#autoreleasepool {
// Erstellt eine Instanz von Person
Person *person = [[Person alloc]init];
// Gibt den Instanzvariablen interessante Werte
[person setWeightInKilos:93.2];
[person setHeightInMeters:1.8];
// Ruft die Methode bodyMassIndex auf
float bmi = [person bodyMassIndex];
NSLog(#"person (%dKg, %.2fm) has a BMI of %.2f", [person weightInKilos],
[person heightInMeters], bmi);
}
return 0;
}
Person.h
#interface Person : NSObject
{
// Sie hat zwei Instanzvariablen
float heightInMeters;
int weightInKilos;
}
// Sie können diese Instanzvariablen anhand folgender Methoden setzen
#property float heightInMeters;
#property int weightInKilos;
// Diese Methode berechnet den Body-Mass-Index
- (float)bodyMassIndex;
#end
Person.m
#import "Person.h"
#implementation Person
#synthesize heightInMeters, weightInKilos;
- (float)bodyMassIndex
{
float h = [self heightInMeters];
return [self weightInKilos] / (h * h);
}
#end
This program was written by the author of the training.
My task is to write a program what is equal.
In my opinion it looks exactly the same:
main.m
#import <Foundation/Foundation.h>
#import "StocksHolding.h"
int main (int argc, const char * argv[])
{
#autoreleasepool {
StocksHolding *stock1 = [[StocksHolding alloc]init];
[stock1 purchaseSharePrice:1];
/*Here I geht the error "Instance method '-purchaseSharePrice:' not found (return type
defaults to 'id')*/
NSLog(#"%i", [stock1 purchaseSharePrice]);
}
return 0;
}
StockHoldings.h
#import <Foundation/Foundation.h>
#interface StocksHolding : NSObject
{
int purchaseSharePrice;
float currentSharePrice;
int numberOfShares;
}
#property int purchaseSharePrice;
#property float currentSharePrice;
#property int numberOfShares;
- (float)costInDollars;
- (float)valueInDollars;
#end
StockHoldings.m
#import "StocksHolding.h"
#implementation StocksHolding
#synthesize purchaseSharePrice, currentSharePrice, numberOfShares;
- (float)costInDollars
{
return purchaseSharePrice * numberOfShares;
}
- (float)valueInDollars
{
return currentSharePrice * numberOfShares;
}
#end
AS you can see... almost no differences except the names of the variables and methods.
Where is the error?
I was sitting for 3 hours at this question.
Please give me a helping hand.
Thanks
Christian
The problem is that you are not using the generated setter method.
purchaseSharePrice is a property.
The default setter is setPurchaseSharePrice: and the default getter is purchaseSharePrice.
So you can just do this
[stock1 setPurchaseSharePrice:1];
or this
stock1.purchaseSharePrice = 1;
In addition, when you want to get the value using the generated getter you can do
int myPrice = [stock1 purchaseSharePrice];
or this
int myPrice = stock1.purchaseSharePrice;
As you can see for both setting and getting, having a property allows you to use dot syntax with the property name directly, while using method syntax requires you to use the method names generated by the property.
I am trying to make a new Objective-C root class on the GNU runtime. Here is what I have so far:
foo.h:
#include <objc/objc.h>
#interface Foo {
Class isa;
int bar;
}
+ (id) alloc;
+ (id) newWithBar: (int) bar;
- (id) initWithBar: (int) bar;
- (void) p;
- (void) dispose;
#end
foo.m:
#import <foo.h>
#include <stdio.h>
#implementation Foo
+ (id) alloc {
return class_createInstance(self, 0);
}
+ (id) newWithBar: (int) bar {
return [[self alloc] initWithBar: bar];
}
- (id) initWithBar: (int) bar_ {
bar = bar_;
}
- (void) p {
printf ("bar=%d\n", self->bar);
}
- (void) dispose {
object_dispose(self);
}
#end
and a little test program, main.m:
#import <foo.h>
int main(int argc, char *argv[]) {
Foo *foo = [Foo newWithBar: 3];
[foo p];
[foo dispose];
return 0;
}
When I compile foo.m, I get the following warning:
foo.m: In function ‘+[Foo alloc]’:
foo.m:7:3: warning: return makes pointer from integer without a cast [enabled by default]
Why? When I dive into the header files, I can see that class_createInstance returns id. What am I doing wrong here?
You need to include the header for the objective C runtime. The default behaviour of the compiler is to assume undeclared functions return an int.
#include <objc-auto.h>
Sorry - answer above is for OS X/iOS. For GNU you need to include runtime.h as well as objc.h
#include <objc/runtime.h>
I have some old C code that looks like this:
#include <stdio.h>
#include <strings.h>
main()
{
FILE *output;
struct socket_cpacket
{
char type; /* CP_SOCKET */
char version;
char udp_version; /* was pad2 */
char pad3;
unsigned socket;
};
struct socket_cpacket sockPack;
bzero(&sockPack,sizeof(sockPack));
sockPack.type = 27;
sockPack.version = 4;
sockPack.udp_version = 10;
sockPack.pad3 = 0;
sockPack.socket = 0;
output = fopen("/tmp/sockPack.bin", "wb");
fwrite(&sockPack, sizeof(sockPack), 1, output);
}
I'd like to duplicate this functionality in obj-c and I started down the path of using NSCoding protocol.
CP_Socket.h
#import <Foundation/Foundation.h>
#interface CP_Socket : NSObject <NSCoding>
{
#private
char type;
char version;
char udp_version;
char pad3;
unsigned int socket;
}
#property (readonly) char type;
#property (readonly) char version;
#property (readonly) char udp_version;
#property (readonly) char pad3;
#property unsigned int socket;
typedef enum {
mTYPE = 27,
mVERSION = 4,
mUDP_VERSION = 10,
} cpSocketEnum;
#end
And CP_Socket.m
#import "CP_Socket.h"
#implementation CP_Socket
#pragma mark ======== properties =========
#synthesize type;
#synthesize version;
#synthesize udp_version;
#synthesize pad3;
#synthesize socket;
- (id)init {
NSLog(#"init");
if( !( self = [super init] ) )
return nil;
type = mTYPE;
version = mVERSION;
udp_version = mUDP_VERSION;
pad3 = 0;
socket = 0;
return self;
}
#pragma mark ======== Archiving and unarchiving methods =========
//
// Archives and Serializations Programming Guide for Cocoa
// http://bit.ly/PAaRsV
//
// NSCoding Protocol Reference
// http://bit.ly/PAb1Rd
//
- (void)encodeWithCoder:(NSCoder *)coder
{
NSLog(#"encodeWithCoder");
[coder encodeBytes:[self type] length:1 forKey:#"type"];
//[coder encodeBytes:[self version] length:1 forKey:#"version"];
//[coder encodeBytes:[self udp_version] length:1 forKey:#"udp_version"];
//[coder encodeBytes:[self pad3] length:1 forKey:#"pad3"];
//[coder encodeInt:[self socket] forKey:#"socket"];
}
- (id)initWithCoder:(NSCoder *)coder
{
NSLog(#"initWithCoder");
}
#end
First problem, [coder encodeBytes:[self type] length:1 forKey:#"type"]; throws a warning. Incompatible integer to pointer conversion sending 'char' to parameter of type 'const uint8_t *.
How do I encode a char?
I tried [coder encodeInt:[self type] forKey:#"type"]; but char != int.
Going with the code to further understand how it work; the file the obj-c code generates is 280 bytes and looking inside the file I see what looks like name-mangled class identifiers.
I've tried NSKeyedArchiver and NSArchiver with the same results.
I don't know where to go from here. The C-code generates a 8 byte file. I'd like the obj-c code to do the same while using some of the OO stuff like the NSCoding protocol.
I feel like I'm going to have to extend the NSCoder object to make this work.
Any help would be appreciated.
The first argument to encodeBytes:length:forKey: is expected to be a pointer to the buffer you want to encode, so take the address of your ivar:
[coder encodeBytes:&type length:1 forKey:#"type"];
Or make a temp variable, put the result of the property access in that, and take its address.
Using encodeInt:forKey: should work too (with a cast), but it'll inflate the size of your data file.
If you really wanted to, you could certainly extend NSCoder with a category:
#implementation NSCoder (BTEncodeChar)
- (void)BTencodeChar: (char)c forKey: (NSString *)key
{
[self encodeBytes:&c length:1 forKey:key];
}
#end
I dont know much about NSCoding, but obj C interops with C just fine. Take your existing code put it in a function with params and call it.
Error: Accessing unknown getter method?
Thanks...
#import <Foundation/Foundation.h>
#interface puppy : NSObject {
int mack;
int jack;
}
-(puppy *) waldo: (puppy *) f;
-(void) setMack: (int) m;
-(void) setJack: (int) j;
#end
///////////////////////////////////////////////////
#import "puppy.h"
#implementation puppy
-(void) setJack: (int) j{
jack = j;
}
-(void) setMack: (int) m{
mack = m;
}
-(puppy*) waldo: (puppy *) f{
return (f.jack + f.mack); // Error: <-- Accessing unknown "jack" getter method
// Error: <-- Accessing unknown "mack" getter method
}
You have not specified getter method for jack and mack. Instead of writing own getter/setter you can use property for them.
#interface puppy : NSObject {
int mack;
int jack;
}
-(puppy *) waldo: (puppy *) f;
// use property
#property (nonatomic, assign) int mack;
#property (nonatomic, assign) int jack;
#end
#implementation puppy
#synthesize jack, mack;
-(puppy*) waldo: (puppy *) f{
return (f.jack + f.mack);
}
#end
You do not need those set methods now. Both getters and setter are synthesized for you. And not asked in the question, you should return int from method waldo.
You haven't implemented the methods jack and mack.
- (int) jack { return jack; }
- (int) mack { return mack; }
But I'd recommend just using #property and #synthesize with no ivar.
When you do f.jack, it translates to [f jack]. You need to add a - (int)jack method to your interface for this to work. Poorly worded perhaps, I also meant the method needs to be implemented. Same is the case of mack
But that said, dot notation is for properties. Isn't apt.
It would be easier if you defined properties for mack and jack and synthesized those methods.
I could not use the pData[4096] to pass it to the other function from main.
data.m
------
#implementation data
static int msgID;
static char pData[4096]="\0";
+ (void)initialize
{
//some initialisations
msgID =123;
}
-(void)SwapEndian:(uint8_t*)pData withBOOLValue:(BOOL)bIsAlreadyLittleEndian
{
NSLog("%s %s",pData,bIsAlreadyLittleEndian);
}
#end
main.m
-------
[dat SwapEndian:dat.pData withBOOLValue:TRUE];
I am getting pData undeclared. As pData is declared as static inside the Data
implementation i tried with dat.pData to pass it from main.But when i do it i am getting
Request for member 'pData' with BOOL value TRUE is not a structure or union.
It is difficult to determine what the code is supposed to do, but here is how to create an Objective-C object that holds an integer identifier and a 4096-character array. Please note that this sort of thing is usually discouraged. Unless you have a really specific reason for using int and char[], the identifier should be NSInteger and the data should be an NSData or NSString object.
I have also used some of the "standard" naming conventions. If you are writing Cocoa code, it helps to drink a lot of the Kool-Aid.
Message.h:
#interface Message : NSObject
{
int identifier;
char data[4096];
}
#property (nonatomic, assign) int indentifier;
#property (nonatomic, readonly) char * data;
- (void)swapEndian:(BOOL)flag;
#end
Message.m:
#implementation Message
#synthesize identifier;
#synthesize data;
- (id)init
{
if ((self = [super init]) == nil) { return nil; }
identifier = 0;
data[0] = '\0';
return self;
}
- (void)swapEndian:(BOOL)flag
{
NSLog(#"%s %d", data, flag);
}
#end
main.m:
#import "Message.h"
...
Message * message = [[[Message alloc] init] autorelease];
message.identifier = 123;
[message swapEndian:YES];