I am resurrecting an "old" Realm objective c project from 2018.
I have to admit I forgot all my objective c knowledge in the meantime and especially I am mentally completely off Realm (Unfortunately I cannot even say what my last realm version was, I guess it was 3.x. Now I updated to 4.3.0).
I would be very grateful if you could give me a hint if there happened some breaking changes to Realm so that my following code (which used to run fine) is crashing now.
I am getting BAD_ACCESS in the constructor of a RealmObject
#implementation TransformationParameters
- (instancetype)init{
self = [super init];
if (self != nil){
[self reset]; // <--- BAD_ACCESS here ...
}
return self;
}
-(void) reset{
self.rotation = 0.0; // <--- BAD_ACCESS here
self.scale = 1;
self.translationX = 0;
self.translationY = 0.0;
}
and this is the corresponding header.
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <Realm/Realm.h>
#interface TransformationParameters : RLMObject
#property double translationX;
#property double translationY;
#property double scale;
#property double rotation;
-(CGAffineTransform) getAffineTransformForCIFilter:(CGSize)fullImageSize ;
-(CGAffineTransform) getAffineTransformForSKView:(CGSize)fullImageSize;
-(CGAffineTransform) getAffineTransformForUICombinationView:(CGSize)fullImageSize;
-(void) reset;
-(void) set:(TransformationParameters*) other;
#end
Here is the call stack:
This code did run well since my last deploy on many devices.
I apologize if my question is stupid, please bear with me then.
Related
I am learning Objective-C inheritance and my program is getting lost in a recursive loop and won't come out. It gets hung up when calling a getter function.
I am using XCode version: Version 6.2 (6C101)
My program is given below
Vehicle.h
#ifndef exercise_2_Vehicle_h
#define exercise_2_Vehicle_h
#import <Foundation/Foundation.h>
#interface Vehicle : NSObject
#property float speed;
-(void) start;
-(void) stop;
-(void) park;
#end
#endif
Vehicle.m
#import "Vehicle.h"
#implementation Vehicle
-(void) setSpeed:(float)speed {
self.speed = speed;
}
-(float) speed {
return self.speed;
}
-(void) start {
NSLog(#"Starting the vehicle");
}
-(void) stop {
NSLog(#"Stopping the vehicle");
}
-(void) park {
NSLog(#"Parking the vehicle");
}
#end
Car.h
#ifndef exercise_2_Car_h
#define exercise_2_Car_h
#import "Vehicle.h"
#interface Car : Vehicle
#property (nonatomic) NSString* make;
-(Car*) initMake: (NSString*) make;
-(NSString*) make;
#end
#endif
Car.m
#import "Car.h"
#implementation Car
-(Car*) initMake:(NSString *)make {
self = [super init];
if (self) {
self.make = make;
}
return self;
}
-(NSString*) make {
return self.make;
}
#end
main.m
#import <Foundation/Foundation.h>
#import "Car.h"
#import "Vehicle.h"
int main(int argc, const char * argv[]) {
#autoreleasepool {
// insert code here...
Car* car = [[[Car alloc] init] initMake: #"Camry"];
//[car setSpeed:45];
NSLog(#"The model initialized is ");
[car make];
// [car speed];
}
return 0;
}
The issue you have is caused by creating the property for speed:
#property float speed;
and overriding setSpeed: method.
When you create #property compiler adds two methods for you, in your example setSpeed and speed.
This command:
self.speed = speed;
is equal to:
[self setSpeed: speed];
and inside setSpeed you have this command again which cause the loop. In your example you can remove both methods (setSpeed and speed) because compiler will add it for you. If you need it because you want to do some customisation you should use _speed instead self.speed.
_speed is backed variable added by compiler when using #property.
Change your method to:
-(void) setSpeed:(float)speed {
_speed = speed;
}
to remove the infinite loop.
In the
- (NSString*)make;
use
return _make
instead. The same with the speed.
If you return "self.x" in a getter method, then it's going to try and call the method again because you're requesting it on self. XCode will automatically convert the properties into variables that can be accessed with an '_' character, so you don't need to do any extra work.
You could also ignore our advice and remove both the "speed" and "make" getter methods you have made, because XCode automagically creates them for you.
Okay. Tough to find the best starting point, here. The error XCode (4.3.2) in Lion is kicking back to me is:
Redefinition of 'a' with a different type
The author says when we declare this line (near the bottom of this page, in main)...
OwnedAppliance *a = [[OwnedAppliance alloc] init];
...that it should run fine. It doesn't. It kicks back the error above. I understand that, because OwnedAppliance has no init method in its implementation, the compiler will go up the hierarchy to OwnedAppliance's superclass, which is Appliance, and search for an init method there. It finds the overridden init, which contains only the following line...
[self initWithProductName:#"Unknown"];
...and runs that. Understood.
Ugh. Sorry, guys. I just tried to explain what I think might be happening. It took a dozen lines and I'd just scratched the surface. Rather than bore you with what I think is happening, I'll just ask:
What's going on with this code? Where does the initialization "path", for lack of a better term, end? Where does the redefinition (the error) occur?
/******************** Appliance.h ********************/
#import <Foundation/Foundation.h>
#interface Appliance : NSObject
{
NSString *productName;
int voltage;
}
#property (copy) NSString *productName;
#property int voltage;
-(id)init;
// Designated initializer
-(id)initWithProductName:(NSString *)pn;
...
#end
/******************** Appliance.m ********************/
#import "Appliance.h"
#implementation Appliance
#synthesize productName, voltage;
-(id)init
{
return [self initWithProductName:#"Unknown"];
}
-(id)initWithProductName:(NSString *)pn
{
self = [super init];
if (self) {
[self setProductName: pn];
[self setVoltage: 120];
}
return self;
...
#end
/******************** OwnedAppliance.h ********************/
#import "Appliance.h"
#interface OwnedAppliance : Appliance
{
NSMutableSet *ownerNames;
}
// Designated initializer
-(id)initWithProductName:(NSString *)pn
firstOwnerName:(NSString *)n;
...
#end
/******************** OwnedAppliance.m ********************/
#import "OwnedAppliance.h"
#implementation OwnedAppliance
-(id)initWithProductName:(NSString *)pn
firstOwnerName:(NSString *)n
{
self = [super initWithProductName:pn];
if (self) {
ownerNames = [[NSMutableSet alloc] init];
if (n) {
[ownerNames addObject:n];
}
}
return self;
}
-(id)initWithProductName:(NSString *)pn
{
return [self initWithProductName:pn
firstOwnerName:nil];
}
...
#end
/******************** main.m ********************/
#import <Foundation/Foundation.h>
#import "Appliance.h"
#import "OwnedAppliance.h"
int main(int argc, const char * argv[])
{
#autoreleasepool {
// Previously omitted problematic code:
Appliance *a = [[Appliance alloc] init];
NSLog(#"a is %#", a);
[a setProductName:#"Washing Machine"];
[a setVoltage:240];
NSLog(#"a is %#", a);
// The following line is where the error occurs:
OwnedAppliance *a = [[OwnedAppliance alloc] init];
...
}
return 0;
}
I've thought a lot about this question and how to ask it. I don't think it's a terribly dumb one. :) But my brain is fried from 9 hours of studying this stuff, so I apologize if this is a totally obvious question. TIA
EDIT: main() now contains the code that was actually causing the error. Thanks to Jacques for being good enough to catch it despite the omission.
The compiler's actually telling you that the variable itself, a, has been declared twice; the error has nothing to do with the assignment. Somehwhere else, in scope, you have another variable named a, which has a different type than OwnedAppliance *. Change the name(s) of one (or both) and the error will go away.
I'm learning Objective-C right now and in order to practice I wrote a simple random maze generator for OS X, which works fine. Next I tried to add some more interaction with buttons, but I'm having trouble with the instance variables as they don't retain the value I assign them. I have come across multiple questions about the same problem, but the solutions to those haven't solved my problem. I also tested if the same problem persists in a simplified version of the program, which it does.
I guess I'm doing something wrong, but I don't know what. Here's what I did:
Created a new project
Added a subclass of NSView called "TestClass"
Added a view with class TestClass in the window in MainMenu.xib
Added an object for TestClass in MainMenu.xib
Added a button to the view and set its tag to 1
Added the following code to TestClass.h and TestClass.m and connected the button to it:
TestClass.h:
#import
#interface TestClass : NSView
{
NSNumber *number;
NSButton *test;
}
#property (nonatomic, retain) NSNumber *number;
#property (assign) IBOutlet NSButton *test;
- (IBAction)testing:(id)sender;
#end
TestClass.m:
#import "TestClass.h"
#implementation TestClass
#synthesize number;
#synthesize test;
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code here.
}
return self;
}
- (IBAction)testing:(id)sender
{
self.number = [[NSNumber numberWithLong:[sender tag]] retain];
}
- (void) drawRect:(NSRect)dirtyRect
{
NSLog(#"%#", number);
}
#end
Whenever I press the button, NSLog just returns null several times.
I normally figure out everything by myself (eventually...), but this time it's really driving me insane, so is there anyone who can help me?
Put the NSLog in testing:, or just put a breakpoint there and see what's stored in number.
Note that self.number = [[NSNumber numberWithLong:[sender tag]] retain]; is double-retaining the NSNumber object (which is wrong), but that shouldn't cause any immediate error.
I'm tearing my hair out over this.. I've no idea what's going wrong.
I've created a very simple Coordinates2D class to store two NSInteger values, as well as a string representation for use with NSLog. I'm running this code in the iOS 4.3 iPad simulator bundled with the latest version of xCode.
For some reason the integer values passed to the initX:Y: constructor gets lost. The code below provides Coordinates2D and some code to print an arbitrary float value in its original form, cast as an int, cast as an NSInteger, and then inside the Coordinates2D object.
You should see, as I do, that the value gets lost inside the Coordinates2D constructor; the 'coords.x' argument in NSLog is printed as a random, large integer indicating its value has been lost in memory.
Can anyone help me see why this happens? I can't see what I'm doing wrong.
Many thanks!
Coordinates2D.h
#import <Foundation/Foundation.h>
#interface Coordinates2D : NSObject {
NSInteger x,y;
NSString *asString;
}
#property (nonatomic) NSInteger x,y;
#property (nonatomic, retain) NSString *asString;
-(void)updateStringRepresentation;
-(id)initX:(NSInteger)x Y:(NSInteger)y;
#end
Coordinates2D.m
#import "Coordinates2D.h"
#implementation Coordinates2D
#synthesize x,y,asString;
-(id)initX:(NSInteger)x_ Y:(NSInteger)y_ {
NSLog(#"coords: %i, %i",x_,y_);
if ((self = [super init])) {
self.x = x_;
self.y = y_;
NSLog(#"Coordinates stored %i as %i",x_,self.x);
[self updateStringRepresentation];
}
return self;
}
/*
-(void)setX:(NSInteger)newX {
x = newX;
[self updateStringRepresentation];
}
-(void)setY:(NSInteger)newY {
y = newY;
[self updateStringRepresentation];
}
*/
-(void)updateStringRepresentation {
self.asString = [NSString stringWithFormat:#"%i,%i",x,y];
}
-(void)dealloc {
[asString release];
[super dealloc];
}
#end
Example of problem:
Coordinates2D *coords = [[Coordinates2D alloc] initX:(NSInteger)(202.566223/200.00) Y:0.0f];
NSLog(#"202.566223/200.00 = %f, as int:%i, as NSInteger:%i, as Coordinates2D:%i",
202.566223/200.00, (int)(202.566223/200.00), (NSInteger)(202.566223/200.00), coords.x);
I read awhile ago that you should never use the property accessor in init methods.
I think you want to change:
#property (nonatomic) NSInteger x,y;
to:
#property (nonatomic, assign) NSInteger x,y;
That should fix the error, as it runs fine when I put it in an xcode project.
Members, scholars, code gurus.
My background is far from any computer programming thus my question may seems basic and somewhat trivial to you. Nevertheless it seems that I can't put my head around it.
I have googled and searched for the answer, just to get myself confused even more.
With that, I would kindly ask for a simple explanation suitable for a non technical person such as myself and for other alike arriving to this thread.
I have left a comment with the text "Here is the issue" below, referring to my question.
// character.h
#import <Foundation/Foundation.h>
#interface character : NSObject {
NSString *name;
int hitPoints;
int armorClass;
}
#property (nonatomic,retain) NSString *name;
#property int hitPoints,armorClass;
-(void)giveCharacterInfo;
#end
// character.m
#import "character.h"
#implementation character
#synthesize name,hitPoints,armorClass;
-(void)giveCharacterInfo{
NSLog(#"name:%# HP:%i AC:%i",name,hitPoints,armorClass);
}
#end
// ClassAtLastViewController.h
#import <UIKit/UIKit.h>
#interface ClassAtLastViewController : UIViewController {
}
-(void)callAgain;
#end
// ClassAtLastViewController.m
#import "ClassAtLastViewController.h"
#import "character.h"
#implementation ClassAtLastViewController
- (void)viewDidLoad {
//[super viewDidLoad];
character *player = [[character alloc]init];
player.name = #"Minsc";
player.hitPoints = 140;
player.armorClass = 10;
[player giveCharacterInfo];
[player release];
// Up until here, All peachy!
[self performSelector:#selector(callAgain) withObject:nil afterDelay:2.0];
}
-(void)callAgain{
// Here is the issue, I assume that since I init the player again I loss everything
// Q1. I loss all the data I set above, where is it than?
// Q2. What is the proper way to implement this
character *player = [[character alloc]init];
[player giveCharacterInfo];
}
Many thanks in advance, Kindly remember that my background is more related to Salmons breeding than to computer code, try and lower your answer to my level if it's all the same to you.
I loss all the data I set above, where is it than?
It's been freed (released). Notice:
character *player = [[character alloc]init]; // You create the character here...
// And then you initialize it...
// Then later...
[player release]; // You release it.
Even if you didn't release it, you still wouldn't be able to access it from callAgain, because you declare player in viewDidLoad. If you want it available to all methods in instances of ClassAtLastViewController, you should make it an instance variable.
What is the proper way to implement this
I don't know the specifics of your usage, but I imagine you want something like this:
#interface ClassAtLastViewController : UIViewController {
character *player; // Make player an instance variable
}
-(void)callAgain;
#end
#implementation ClassAtLastViewController
- (void)viewDidLoad {
//[super viewDidLoad];
player = [[character alloc]init]; // Initialize the instance variable
player.name = #"Minsc";
player.hitPoints = 140;
player.armorClass = 10;
[player giveCharacterInfo];
[self performSelector:#selector(callAgain) withObject:nil afterDelay:2.0];
}
-(void)callAgain{
[player giveCharacterInfo];
}
When you init the character in your callAgain function, you are actually creating a second instance of character. Even though the character created in callAgain has the same name as the character you created in viewDidLoad, it is a completely separate variable. The character you init in viewDidLoad only exists in the scope of the viewDidLoad function.
Also, when you call [player release] in viewDidLoad, you are removing that character instance from memory.
I think what you want to do is to create an instance variable that can be used throughout your class:
// ClassAtLastViewController.h
#import <UIKit/UIKit.h>
#interface ClassAtLastViewController : UIViewController {
character *player;
}
-(void)callAgain;
#end
// ClassAtLastViewController.m
#import "ClassAtLastViewController.h"
#import "character.h"
#implementation ClassAtLastViewController
- (void)viewDidLoad {
//[super viewDidLoad];
player = [[character alloc]init];
player.name = #"Minsc";
player.hitPoints = 140;
player.armorClass = 10;
[player giveCharacterInfo];
[self performSelector:#selector(callAgain) withObject:nil afterDelay:2.0];
}
-(void)callAgain{
// Here is the issue, I assume that since I init the player again I loss everything
// Q1. I loss all the data I set above, where is it than?
// Q2. What is the proper way to implement this
[player giveCharacterInfo];
}