App crashing while working with class and not going to catch - objective-c

In my AppDelegate.m, I am doing something like this
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
#try {
// initalizing Meeting config
MeetingConfig *config = [[MeetingConfig alloc] init];
NSLog(#"Initalized Meeting Config: %#", config);
[config setRoomName:#"test123"];
NSLog(#"SetRoom name for Meeting config: %#", config.roomName);
NSString *clientId = #"";
NSLog(#"Unused Client id is: %#", clientId);
//Call UIView from here
}#catch (NSException *exception) {
NSLog(#"exception: %#", exception);
}
return YES;
}
Where my MeetingConfig.m file looks like this
#implementation MeetingConfig
- (id) init
{
if (self = [super init]) {
self.apiBase = #"https://api.in";
self.showSetupScreen = false;
self.autoTune = true;
}
return self;
}
- (void) setAuthToken:(NSString *)authToken
{
self.authToken = authToken;
}
- (void) setApiBase:(NSString *)apiBase
{
self.apiBase = apiBase;
}
// more code
and MeetingConfig looks like this
#import <Foundation/Foundation.h>
#interface MeetingConfig : NSObject
#property (nonatomic, assign) NSString* roomName;
#property (nonatomic, assign) NSString* authToken;
#property (nonatomic, assign)Boolean autoTune;
#property (nonatomic, assign)NSString* apiBase;
#property (nonatomic, assign)Boolean showSetupScreen;
- (void) setRoomName:(NSString *)roomName;
- (void) setAuthToken:(NSString *)authToken;
- (void) setShowSetupScreen:(Boolean)showSetupScreen;
- (void) setAutoTuneEnabled:(Boolean)autoTune;
- (id) init;
#end
Can someone help me in determining what I could be doing wrong here? and why doesn't it log exception in NSLog? Also, I am super new to objective C (i have been asked to stick with Objective c) and if anyone have any suggestion in regards to the code then please let me know.
Error

You're using assign for reference/pointer types: #property retain, assign, copy, nonatomic in Objective-C
They should probably be declared copy, because this is a kind of value object, I think.
No exceptions were caught because no exceptions were thrown. Throwing/catching exceptions for control flow is not common in Objective-C
You don't need to write explicit setter functions for #properties
You should prefer to use BOOL type instead of Boolean, with values of YES/NO instead of true/false.
You should return instancetype not id from init, at least in reasonably modern Objective C
Consider making an initialiser that takes all the properties (initWithRoomName:clientID:) and make them read only once set
You don't need to declare -(id) init in your header since it gets that from NSObject

Related

objective-c: Using NSManagedObject for saving data with CoreData

Is it possible to extend an derived class from NSManagedObject? I'm asking this because I tried to do it. My entity looks like this:
So this means a class similar to the following code should be generated:
#import <Foundation/Foundation.h>
#interface Player : NSManagedObject
#property (nonatomic, copy) NSNumber* orderNumber;
#property (nonatomic, copy) NSString *name;
#end
.m file
#import "Player.h"
#implementation Player
#dynamic name, orderNumber;
#end
This two variables are saved to the SQLite database.
Now since I need some additional variables for the player I just added them to the class. It still worked.
#import "Player.h"
#implementation Player
#dynamic name, orderNumber;
- (id) init
{
self = [super init];
if (self != nil)
{
[self reset];
}
return self;
}
#synthesize isStillInGame = _isStillInGame;
- (void) reset
{
_isStillInGame = TRUE;
}
- (void) setOutOfGame
{
_isStillInGame = FALSE;
}
#end
But now when I change the isStillInGame bool, all instances of the Player Class are changed. Is this normal or do I have an error in my code?
A second question I can't answer is, why I can't access the object variables while debugging. When I try to watch an Player instance variable I just see this:
Is it possible to see more?

NSOperation with repeat option

I've developed a Category that gives the NSOperation the ability to be executed in the background at timed intervals. I would really appreciate getting some feedback on this, especially any potential problems with this approach that I'm not thinking of.
Thank you!
Here's the code:
NSOperation+Repeat.h
#import <Foundation/Foundation.h>
#interface NSOperation (repeat)
#property (readonly, nonatomic) NSTimeInterval repeatInterval;
#property (readonly, nonatomic) NSOperationQueue *repeatOperationQueue;
- (void)performUsingOperationQueue:(NSOperationQueue *)operationQueue;
- (void)performAtRepeatingInterval:(NSTimeInterval)interval usingOperationQueue:(NSOperationQueue *)operationQueue;
#end
NSOperation+Repeat.m
#import "NSOperation+repeat.h"
#import <objc/runtime.h>
static char const * const RepeatPropertiesKey = "RepeatProperties";
#implementation NSOperation (repeat)
#dynamic repeatInterval;
#dynamic repeatOperationQueue;
static NSString * RepeatIntervalKey = #"interval";
static NSString * RepeatOperationQueueKey = #"operationQueue";
static NSString * RepeatTimerKey = #"timer";
- (NSMutableDictionary *)repeatProperties {
NSMutableDictionary * properties = objc_getAssociatedObject(self, RepeatPropertiesKey);
if (properties == nil) {
properties = [NSMutableDictionary new];
objc_setAssociatedObject(self, RepeatPropertiesKey, properties, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
return properties;
}
- (NSTimeInterval)interval {
NSNumber * interval = [[self repeatProperties] objectForKey:RepeatIntervalKey];
return [interval doubleValue];
}
- (NSOperationQueue *)repeatOperationQueue {
NSOperationQueue * operationQueue = [[self repeatProperties] objectForKey:RepeatOperationQueueKey];
return operationQueue;
}
- (void)performUsingOperationQueue:(NSOperationQueue *)operationQueue {
[operationQueue addOperation:[self copy]];
}
- (void)performAtInterval:(NSTimer *)timer {
[self performUsingOperationQueue:self.repeatOperationQueue];
}
- (void)performAtRepeatingInterval:(NSTimeInterval)interval usingOperationQueue:(NSOperationQueue *)operationQueue {
// Save interval and operationQueue in repeatProperties
[self.repeatProperties setValue:[NSNumber numberWithDouble:interval] forKey:RepeatIntervalKey];
[self.repeatProperties setValue:operationQueue forKey:RepeatOperationQueueKey];
// Create timer to call performAtInterval on self
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:(interval*60)
target:self
selector:#selector(performAtInterval:)
userInfo:nil
repeats:YES];
// Save the timer in repeatProperties
[self.repeatProperties setValue:timer forKey:RepeatTimerKey];
[self performUsingOperationQueue:operationQueue];
}
#end
Here's an example of a NSOperation subclass that can repeat:
MSScheduleImportOperation.h
#import <Foundation/Foundation.h>
#import "NSOperation+Repeat.h"
#interface MSScheduleImportOperation : NSOperation <NSCopying>
#property (readonly, strong, nonatomic) NSString* employeeId;
- (id)initWithEmployeeId:(NSString *)employeeId;
#end
MSScheduleImportOperation.m
#import "MSScheduleImportOperation.h"
#implementation MSScheduleImportOperation
#synthesize employeeId = __employeeId;
- (id)initWithEmployeeId:(NSString *)employeeId {
self = [super init];
__employeeId = [employeeId copy];
return self;
}
- (id)copyWithZone:(NSZone *)zone {
MSScheduleImportOperation* copy = [[MSScheduleImportOperation alloc] initWithEmployeeId:self.employeeId];
return copy;
}
- (void)main
{
...
}
#end
The Apple documentation says:
An operation object is a single-shot object—that is, it executes its task once and cannot be used to execute it again.
So the first problem is that there might be internals that stop it from working. Although, I see you try to get around the problem by making a copy.
This leads us to the other problem is that NSOperation is not advertised to conform to NSCopying.
[operationQueue addOperation:[self copy]];
This line should throw an exception.
Instead of a category on NSOperation where the object copies itself and adds the copy to an NSOperationQueue - it would be simpler to manage this at a higher level. For example:
+[RepeatingOperation operationBlock:(InitOperationBlock)operationBlock
queue:(NSOperationQueue*)queue
interval:(NSTimeInterval)interval];
where InitOperationBlock would be a block where the operation was created and configured.
The main benefit is the API would be harder to mess up. For example in category in the original post, performUsingOperationQueue: will fail silently if you forget to set repeatOperationQueue.

In Objective-C, how do I pass a property as an argument for a function and then call the setter/getter methods?

The code is probably the best way to see what I am trying to do:
AcInfo.h:
#interface AcInfo : NSManagedObject {
#private
}
#property (nonatomic, retain) NSString *registrationNumber;
#end
AcInfo.m:
#implementation AcInfo
#dynamic registrationNumber;
#end
AnotherClass.h:
#interface AnotherClass : NSObject {
}
#property (nonatomic, retain) AcInfo *detailItem;
#property (nonatomic, retain) IBOutlet UITextField *registrationNumberTextField;
- (void)setDetailItemValueFromUIElement:(id *)uiElement forAcInfoTarget:(id *)acInfoTarget;
#end
AnotherClass.m:
#import "AcInfo.h"
#implementation AnotherClass
#synthesize detailItem, registrationNumberTextField;
- (void)viewDidLoad
{
[super viewDidLoad];
registrationNumberTextField.text = #"Test";
// I expect this to set detailItem.registrationNumber to the value of
// registrationNumberTextField.text (Test) but it doesn't change anything!
setDetailItemValueFromUIElement:registrationNumberTextField forAcInfoTarget:detailItem.registrationNumber;
}
- (void)setDetailItemValueFromUIElement:(id *)uiElement forAcInfoTarget:(id *)acInfoTarget
{
if ([(id)uiElement isKindOfClass:[UITextField class]]) {
// This doesn't do anything when it returns!
(NSString *)acInfoTarget = (UITextField *)uiElement.text
return;
}
}
#end
In short, I want acInfoTarget to call the getter [detailObject registrationNumber] and the setter [detailObject setRegistrationNumber] in the setDetailItemValueFromUIElement: function...
You can set or read properties by name using
// setter
NSString *propertyName = #"myProperty";
[object setValue:newValue forKey:propertyName];
// getter
id value = [object valueForKey:propertyName];
This is slower than using the normal dot notation, though, and it's frequently (though not always) a sign of poorly-designed code.
Also note that id is a pointer type, so you probably don't actually mean "(id*)".
Your code wants to look something like this, I think:
- (void)setDetailItemValueFromUIElement:(id)uiElement forAcInfoTarget:(NSString*)acInfoTarget {
if ([(id)uiElement isKindOfClass:[UITextField class]]) {
NSString *newValue = ((UITextField*)uiElement).text;
[self.detailItem setValue:newValue forKey:acInfoTarget];
}
}
Properties are just syntax sugar for a couple of accessor methods. They are not, in essence, variables so you shouldn't treat them as such. If you want to affect a property, then what you wanting to do is call a method. So you should pass a id and selector parameter and not pointer to a variable type.

Incomplete Implementation Example Help!

I am working on an example from a book that I got and it doesnt seem to be working I am getting the warning Incomplete implementation. When I run the program I get an error singal "EXC_BAD_ACCESS". The warning is in the .m file at the line return [NSString stringWithFormat:#"Name:... Does anyone know what I am doing wrong?
my .m file
#import "RadioStation.h"
#implementation RadioStation
+ (double)minAMFrequency {
return 520.0;
}
+ (double)maxAMFrequency {
return 1610.0;
}
+ (double)minFMFrequency {
return 88.3;
}
+ (double)maxFMFrequency {
return 107.9;
}
- (id)initWithName:(NSString *)newName atFrequency:(double)newFreq atBand:(char)newBand {
self = [super init];
if (self != nil) {
name = [newName retain];
frequency = newFreq;
band = newBand;
}
return self;
}
- (NSString *)description {
return [NSString stringWithFormat:#"Name: %#, Frequency: %.1f Band: %#", name, frequency, band];
}
- (void)dealloc {
[name release];
[super dealloc];
}
#end
My .h file
#import <Cocoa/Cocoa.h>
#interface RadioStation : NSObject {
NSString *name;
double frequency;
char band;
}
+ (double)minAMFrequency;
+ (double)maxAMFrequency;
+ (double)minFMFrequency;
+ (double)maxFMFrequency;
-(id)initWithName:(NSString*)name
atFrequency:(double)freq
atBand:(char)ban;
-(NSString *)name;
-(void)setName:(NSString *)newName;
-(double)frequency;
-(void)setFrequency:(double)newFrequency;
-(char)band;
-(void)setBand:(char)newBand;
#end
radiosimulation.m file:
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
// insert code here...
NSMutableDictionary* stations = [[NSMutableDictionary alloc] init];
RadioStation* newStation;
newStation = [[RadioStation alloc] initWithName:#"Star 94"
atFrequency:94.1
atBand:'F'];
[stations setObject:newStation forKey:#"WSTR"];
[newStation release];
NSLog(#"%#", [stations objectForKey:#"WSTR"]);
newStation = [[RadioStation alloc] initWithName:#"Rocky 99"
atFrequency:94.1
atBand:'F'];
[stations setObject:newStation forKey:#"WKFR"];
[newStation release];
NSLog(#"%#", [stations objectForKey:#"WKFR"]);
[stations release];
[pool drain];
return 0;
You are declaring the following property accessor/mutators (getter/setters) but are not implementing them in your .m file.
-(NSString *)name;
-(void)setName:(NSString *)newName;
-(double)frequency;
-(void)setFrequency:(double)newFrequency;
-(char)band;
-(void)setBand:(char)newBand;
You need to implement all 6 of these methods in the .m file if you want to remove the warning about incomplete implementation.
You are effectively saying in the .h file that this is what your object is going to do, then not doing it in the .m. It won't generate an error, as objective-c messaging means that the message will be handed up to NSObject to deal with, which will also not have any matching implementation, and the messages will just be silently ignored. I don't like the way that this is only shown as a warning - but there you go.
That said, I wouldn't create the properties like this (there are neater ways of doing this in objective-c using #property), I would remove those method declarations in the .h and replace them with:
#property (nonatomic, retain) NSString *name;
#property (nonatomic, assign) double frequency;
#property (nonatomic, assign) char band;
These property declarations go in the same place as method declarations.
and then add the following to the .m file:
#synthesize name;
#synthesize frequency;
#synthesize band;
This will avoid having to write all that boilerplate accessor/mutator code that you are currently missing. Again, these go in the same region of the code as method implementations. Effectively the compiler is going to create name and setName methods automatically.
This code is untested - but should point you in the right direction for tidying up the incomplete implementation. It may fix your access error too - but that may require more detailed look at a stack trace.
Another point I'm not sure the code as written even needs to use get/set methods or properties. You might try removing the method declarations from the .h and see if it works. It seems that all the accesses to name, frequency and band are all from within the object.

Help with a method that returns a value by running another object's method

I have a Class that runs the following method (a getter):
// the interface
#interface MyClass : NSObject{
NSNumber *myFloatValue;
}
- (double)myFloatValue;
- (void)setMyFloatValue:(float)floatInput;
#end
// the implementation
#implementation
- (MyClass *)init{
if (self = [super init]){
myFloatValue = [[NSNumber alloc] initWithFloat:3.14];
}
return self;
}
// I understand that NSNumbers are non-mutable objects and can't be
// used like variables.
// Hence I decided to make make the getter's implementation like this
- (double)myFloatValue{
return [myFloatValue floatValue];
}
- (void)setMyFloatValue:(float)floatInput{
if ([self myFloatValue] != floatInput){
[myFloatValue release];
myFloatValue = [[NSNumber alloc] initWithFloat:floatInput;
}
#end
When I mouse over the myFloatValue object during debugging, it does not contain a value. Instead it says: "out of scope".
I would like to be able to make this work without using #property, using something other than NSNumbers, or other major changes since I just want to understand the concepts first. Most importantly, I would like to know what mistake I've apparently made.
I can see a couple of mistakes:
The line #implementation should read #implementation MyClass
The function setMyFloatValue is missing a closing ] and } —it should read:
- (void)setMyFloatValue:(float)floatInput{
if ([self myFloatValue] != floatInput){
[myFloatValue release];
myFloatValue = [[NSNumber alloc] initWithFloat:floatInput];
}
}
I've just tested it in Xcode and it works for me with these changes.
Why not just set property in interface and synthesize accessors in implementation?
#interface MyClass : NSObject {
float *myFloat
}
#property (assign) float myFloat;
#end
#implementation MyClass
#synthesize myFloat;
#end