Obj-C methods: calling with parameters - c

I've been using C-style functions, but I just learned they can't see instance variables. So I was advised to convert them to Objective-C methods.
NSString* myfunc ( int x )
becomes:
- (NSString *)myfunc:(int)x
and
myString = myfunc(x);
becomes
myString = [myString myfunc:x];
??
This compiles with ominous warnings, but does not work. What have I misunderstood?

It looks like your call is incorrect. Perhaps try:
NSString *myString = [self myfunc:x];

As far as I understand, you send the -myfunc: message to a NSString object. So the -myfunc: method should be declared in NSString class (or a category of NSString).
If this is what you want to do, you don't need to return the object itself as the result of the method: you can modify its instance variables in the method implementation. The method call (or message sending) looks like:
[myString myfunc:x];
If you want to send the message to an object of another class and return a string, your method declaration is correct but must appear in your class implementation and the receiver of the message (this is the item on the left in the square brackets) must be of that class:
#implementation MyClass
-(NSString *)myfunc:(int)x
{
NSString * returnString;
...// do something with x, returnString and instance variables
return returnString;
}
#end;
...
MyClass * myobj = [[MyClass alloc] init];
NSString * myString = [myobj myfunc:42];

As a second answer, I am trying to understand your problem through all your recent questions.
At the beginning, there was a C function returning a pointer to a NSString object:
NSString * myfunc( int x )
{
... // Do something with x
NSString * myString = #"MYDATA";
... // Do something with myString
return myString;
}
Then, you wanted to add in that function some code about an UIImage object:
image1.image = [UIImage imageNamed:#"image1.png"];
You were advised to convert the function to a method. If you want to access .image instance variable, this method has to belong to the class of image1 object (let's say this is AlanImage class). Something like this:
#interface AlanImage : NSObject {
UIImage image;
}
- (NSString *) myfuncWithParam: (int) x;
#end;
#implementation AlanImage
- (NSString *) myfuncWithParam: (int) x
{
NSString * myString = #"MYDATA";
image = [UIImage imageNamed:#"image1.png"];
return myString;
}
#end
Third, you didn't know what was the receiver of the method. My investigations tend to lead to your image object as a good candidate:
aNiceString = [image myfunc:aNiceInteger];
Finally (this question), not getting a satisfying answer, you reworded your third question, with success this time as it happens.
I am curious to get a more complete view of your project in order to give you some hints. Anyway, it seems that you are learning Objective-C and object oriented concepts: congratulations and stay motivated!

You haven't worked out what Object Oriented Programming is. With [theObject method] you can only call methods belonging to the specific instance.

I am not sure that following trick correctly work for a "general" objective-c, but in apple implementation you can do such:
#interface SomeClass: NSObject {
int m_someVariable;
...
};
- (NSString *) someMethod;
...
#end
#implementation SomeClass
...
//pure c function with extra one parameter
//for accessing to instance variables
static NSString privatePlainCeeMethod(SomeClass *my, int fortyTwo) {
NSString *str;
//access to a instance variable as for a usual
//cee structure field: my->fieldName
...
return [NSString stringWithFormat:#"someVariable:%d, fortyTwo:%d",
my->m_someVariable, fortyTwo];
};
- (NSString *) someMethod {
...
return privatePlainCeeMethod(self,42);
};
...
#end
I use such trick to divide a big objc method on observable private simple functions. These functions (a) do not pollute class interface and (b) are invoked faster than objc method.

Related

Most efficient way of getting large std::vector into Swift?

I have an Objective-C class that populates a std:vector with millions of points. The structure of the vector is:
typedef std::vector<CGPoint> CGContour;
typedef std::vector<CGContour> CGContours;
So a CGContour is a vector of CGPoints and CGContours is a vector of the CGContour vector.
I need to access this data in a Swift class somehow. I don't want to use an NSArray because it has a huge overhead compared to using vector (it is like 10x as big and slow).
What would be the most efficient way to get millions of CGPoints accessible in Swift from my Objective-C class?
Edit:
I am populating my CGContours vector like this:
contourVector = CGContours(contours.size());
populatedContourNum = 0
//contours is OpenCV's contours
for( long c = 0; c < contours.size(); c++) {
if (populatedContourNum >= contourVector.size()) {
contourVector.resize(contourVector.size() + 1);
}
contourVector[populatedContourNum] = CGContour(contours[c].size());
for( long pointNum = 0; pointNum < contours[c].size(); pointNum++ )
{
contourVector[populatedContourNum][pointNum] = CGPointMake(contours[c][pointNum].x * scale,
contours[c][pointNum].y * scale);
}
populatedContourNum++;
}
Some parts are not clear enough but I will try to show you some example.
First of all, you need to prepare a class which can access your contourVector. (I cannot see if it is an instance field or a global variable, if it is an instance field, you may use the existing class.)
Create a header for the prepared class, again you may utilize the existing header, but this header needs to be compiled both in C-context and in C++ context. So, if your existing header contains some declaration which cannot be compiled in C-context, you may need separated two headers or some #ifs.
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
#interface YourClass : NSObject
- (NSInteger)contoursSize;
- (NSInteger)contourSizeAtIndex:(NSInteger)index;
- (CGPoint *)contourAtIndex:(NSInteger)index;
//...
#end
NS_ASSUME_NONNULL_END
Then add 3 methods to the class specified in the header:
#import "YourClass.h"
#import <vector>
typedef std::vector<CGPoint> CGContour;
typedef std::vector<CGContour> CGContours;
static CGContours contourVector;
#implementation YourClass
- (NSInteger)contoursSize {
return contourVector.size();
}
- (NSInteger)contourSizeAtIndex:(NSInteger)index {
return contourVector[index].size();
}
- (CGPoint *)contourAtIndex:(NSInteger)index {
return contourVector[index].data();
}
#end
Please do not forget to include the header inside your Project-Bridging-Header.h:
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//
#import "YourClass.h"
You need to create a Swift side wrapper class, as you cannot create UnsafeBufferPointer in Objective-C.
class YourClassWrapper {
let yourInstance = YourClass()
var count: Int {
return yourInstance.contoursSize()
}
subscript(index: Int) -> UnsafeBufferPointer<CGPoint> {
guard 0..<count ~= index else {fatalError("Index \(index) out of bounds \(0..<count)")}
let start = yourInstance.contour(at: index)
let count = yourInstance.contourSize(at: index)
return UnsafeBufferPointer(start: start, count: count)
}
}
With these preparations above, you can access each CGPoint as:
let wrapper = YourClassWrapper()
let point = wrapper[0][1]
Or you can get the pointer to the first element in CGContour as:
let ptr = wrapper[0].baseAddress!
You may need to modify some parts to fit this into your actual code. Hope you can make it.

How do I access an array from one file in another file?

I am really new to Xcode. I don't quite understand exactly what it means when you initialize variables in certain places, but my code works so this isn't the issue... for now. Anyway, here is a my .h file. Everywhere there is a "----" it just means there is code there.
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
NSInteger charactersLocked[3] = {0,0,1};
int charSel = 0;
#interface Tutorial : UIViewController
{
-------
}
------
#end
So I need to access the array charactersLocked in a different .m file, lets call it File2 and this one File1. When I try to #import "File1.h" in File2.m, the program crashes and gives me this error for both charactersLocked and charSel:
duplicate symbol _charactersLocked in:
/Users/me/Library/Developer/Xcode/DerivedData/SpaceRace-
apawbkpiogvbvddranqfltyybuqr/Build/Intermediates/SpaceRace.build/Debug-
iphoneos/SpaceRace.build/Objects-normal/arm64/Tutorial.o
/Users/me/Library/Developer/Xcode/DerivedData/SpaceRace
apawbkpiogvbvddranqfltyybuqr/Build/Intermediates/SpaceRace.build/Debug-
iphoneos/SpaceRace.build/Objects-normal/arm64/Space.o
I have no idea what this is. I've tried looking for solutions online, but none of them seem to work. I am not importing the .m file by accident. If there is an easier way to just get access to that specific array, please let me know. Sorry if this post was formatted horribly, it is my first time so bear with me. Thank you.
The short answer to your question is located in this answer; you need to declare your variables as extern for the compiler to know that you want to use it in multiple files.
This is very rarely done in Objective-C though, because its heritage as an object-oriented programming language means that global state in programs is most often handled in class methods or singleton classes. Without knowing too much about your program, I am going to guess that you want a singleton class, something like CharacterLocker, which would look like this:
CharacterLocker.h
#interface CharacterLocker : NSObject
{
NSInteger charactersLocked[3];
}
+ (id) sharedObject;
#property NSInteger* charactersLocked;
#end
CharacterLocker.m
#implementation CharacterLocker
#synthesize charactersLocked;
+ (void) sharedObject
{
static CharacterLocker *singleton = nil;
// Required so that multiple calls to sharedObject don't create two
static dispatch_once_t pred;
dispatch_once(&pred, ^{ singleton = [[CharacterLocker alloc] init]; });
return singleton;
}
- (id) init
{
if ( self = [super init] )
{
charactersLocked[0] = 0;
charactersLocked[1] = 0;
charactersLocked[2] = 1;
}
return self;
}
#end
Then, in your code, you call [CharacterLocker sharedObject].charactersLocked to access the array.

Sorting NSMutableArray with NSDictionaries that contains Numbers as String?

Have a little Problem and can´t find a working solution :(
I have a NSMutableArray like:
{
Entfernung = 129521;
"Event_DATE" = "2014-03-23";
"Event_ID" = 1;
"Event_KAT" = 1;
"Event_NAME" = achtzehn;
},
{
Entfernung = 112143;
"Event_DATE" = "2014-03-24";
"Event_ID" = 2;
"Event_KAT" = 2;
"Event_NAME" = neunzehn;
}
How can i sort this Array with the object "Entfernung"?
Thx 4 help!
Gerhard
Try something like this;
NSArray *stuff = .... //your array here;
NSSortDescriptor *sorter = [NSSortDescriptor sortDescriptorWithKey:#"Entfernung" ascending:YES comparator:^NSComparisonResult(id obj1, id obj2) {
//depending on the number stored in the string, you might need the floatValue or doubleValue instead
NSNumber *num1 = #([(NSString*)obj1 integerValue]);
NSNumber *num2 = #([(NSString*)obj2 integerValue]);
return [num1 compare:num2];
}];
NSArray *sortedStuff = [[stuff sortedArrayUsingDescriptors:#[sorter]];
The easiest I'd say would be to define a compare method on Entfernung class and then use - (void)sortUsingSelector:(SEL)comparator If you already have a function which accepts two objects (say your NSDictionary object) then I'd do the sort like this - (void)sortUsingFunction:(NSInteger (*)(id, id, void *))compare context:(void *)context
Give a man a fish, and he can eat today. Tell him how to fish, and he has to do the work himself for the rest of his life...
In Xcode, look at the help menu. In the help menu, you find an item "Documentation and API reference". There you type in "NSMutableArray", then you search for "sort". Which gives you five methods:
– sortUsingDescriptors:
– sortUsingComparator:
– sortWithOptions:usingComparator:
– sortUsingFunction:context:
– sortUsingSelector:
You can click on each one and read the description. The most straightforward to use is sortUsingComparator: which comes with a nice bit of sample code that you adapt for your purposes.

"NSMutableData data retain" on NSURLConnection - how calm this works?

On a lot of NSURLConnection examples I see the following lines:
NSURLConnection *theConnection = [[NSURLConnection alloc]initWithRequest:theRequest delegate:self];
if(theConnection)
{
webData = [[NSMutableData data]retain];
}
else
...
I wonder - what is this supposed to do? and why does it work? I thought that data is an accessor method, and since your not calling it on an instanciated object, it will return nil, and by retaining it you actually do nothing.
This is the way I have seen to get data on connections like this:
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:[NSURLRequest requestWithURL:url] delegate:self startImmediately:YES];
if( connection )
{
while (!finished) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
}
finished is an ivar that gets set to YES on connectionDidFinishLoading:
Can anyone clear this up for me? Which should be used and what's the difference?
[NSMutableData data] is not an accessor but a so-called class method. You probably know [NSMutableData alloc], that too is a class method and means it is tied to the class but not an instance. The typical way to denote that a method is a class method is by prefixing it with a plus: +[NSMutableData data].
In this case, the method is inherited from the NSData class (but does return an NSMutableData instance, since you're calling it on that class).
An implementation might look like this:
#interface NSMutableData
+ (id)data
{
return [[[self alloc] init] autorelease];
}
#end
Note that self in this case is the NSMutableData class.
In other languages like C++, C# and Java (AFAIK) these would be methods that you specify with the static keyword.

MapKit based app crashing when loading from plist

I'm writing a program which uses MapKit to display a map which will load custom annotations from a plist file. Each annotation is a dictionary item in the root array, with a title, subtitle, latitude, and longitude. When I hard-coded in the annotations for test purposes, the program worked beautifully. But with the addition of the MapDemoAnnotation class and my attempt to read in the property list, the program crashes upon launch.
Here is my annotation implementation:
#import "MapDemoAnnotation.h"
#implementation MapDemoAnnotation
#synthesize coordinate;
#synthesize title;
#synthesize subtitle;
-(id)initWithDictionary:(NSDictionary *)dict{
self = [super init];
if(self!=nil){
coordinate.latitude = [[dict objectForKey:#"latitude"] doubleValue];
coordinate.longitude = [[dict objectForKey:#"longitude"] doubleValue];
self.title = [dict objectForKey:#"name"];
self.subtitle = [dict objectForKey:#"desc"];
}
return self;
}
-(void)dealloc{
[title release];
[subtitle release];
[super dealloc];
}
#end
I'm guessing the viewDidLoad method in my RootViewController class is the problem, though.
- (void)viewDidLoad {
[super viewDidLoad];
MKMapView *mapView = (MKMapView*)self.view;
mapView.delegate = self;
mapView.mapType=MKMapTypeHybrid;
CLLocationCoordinate2D coordinate;
coordinate.latitude = 39.980283;
coordinate.longitude = -75.157568;
mapView.region = MKCoordinateRegionMakeWithDistance(coordinate, 2000, 2000);
//All the previous code worked fine, until I added the following...
NSString *plistPath = [[NSBundle mainBundle] pathForResource:#"Locations" ofType:#"plist"];
NSData* data = [NSData dataWithContentsOfFile:plistPath];
NSMutableArray* array = [NSPropertyListSerialization propertyListFromData:data
mutabilityOption:NSPropertyListImmutable
format:NSPropertyListXMLFormat_v1_0
errorDescription:nil];
if (array) {
NSMutableDictionary* myDict = [NSMutableDictionary dictionaryWithCapacity:[array count]];
for (NSDictionary* dict in array) {
MapDemoAnnotation* annotation = [[MapDemoAnnotation alloc]initWithDictionary:dict];
[mapView addAnnotation:annotation];
[annotation release];
}
NSLog(#"The count: %i", [myDict count]);
}
else {
NSLog(#"Plist does not exist");
}}
The program crashes for reasons I cannot figure, but I figure I must have done something wrong in reading in the property list or else in the MapDemoAnnotation class. Am I missing something obvious, or making a novice mistake?
My code is largely borrowed, so I could be way off base with how I'm approaching it.
Thanks in advance!
The third parameter in the call to propertyListFromData is wrong. The compiler must be giving you a "makes pointer from integer without a cast" warning there because the format parameter expects a pointer to a NSPropertyListFormat variable (so the method can return the format to you). So you need to do:
NSPropertyListFormat propertyListFormat;
NSMutableArray* array = [NSPropertyListSerialization
propertyListFromData:data
mutabilityOption:NSPropertyListImmutable
format:&propertyListFormat
errorDescription:nil];
However, the documentation mentions that the above method is obsolete and you should use propertyListWithData:options:format:error: instead.
However, it's much easier to just call NSArray's initWithContentsOfFile: method instead:
NSString *plistPath = [[NSBundle mainBundle] pathForResource...
NSArray *array = [[NSArray alloc] initWithContentsOfFile:plistPath];
if (array) {
//your existing code here...
}
else {
NSLog(#"Plist does not exist");
}
[array release];

Resources