This question already has answers here:
Under automatic reference counting, why are retain, release, and dealloc not allowed?
(4 answers)
Closed 9 years ago.
I'm using the latest xcode.
implementation file:
SimpleCar.m:
#import "SimpleCar.h"
#implementation SimpleCar
// set methods
- (void) setVin: (NSNumber*)newVin {
[vin release];
vin = [[NSNumber alloc] init];
vin = newVin;
}
- (void) setMake: (NSString*)newMake {
[make release];
make = [[NSString alloc] initWithString:newMake];
}
- (void) setModel: (NSString*)newModel {
[model release];
model = [[NSString alloc] initWithString:newModel];
}
// convenience method
- (void) setMake: (NSString*)newMake
andModel: (NSString*)newModel {
// Reuse our methods from earlier
[self setMake:newMake];
[self setModel:newModel];
}
//get methods
- (NSString*) make; {
return make;
}
- (NSString*) model;{
return model;
}
- (NSNumber*) vin;{
return vin;
}
-(void) dealloc
{
[vin release];
[make release];
[model release];
[super dealloc];
}
#end
interface file:
SimpleCar.h:
#import <Foundation/Foundation.h>
#interface SimpleCar : NSObject {
NSString* make;
NSString* model;
NSNumber* vin;
}
// set methods
- (void) setVin: (NSNumber*)newVin;
- (void) setMake: (NSString*)newMake;
- (void) setModel: (NSString*)newModel;
// convenience method
- (void) setMake: (NSString*)newMake
andModel: (NSString*)newModel;
// get methods
- (NSString*) make;
- (NSString*) model;
- (NSNumber*) vin;
#end
I get an error in the implementation file when I type "[vin release], [model release], [make release]" and I cannot run the program.
ARC is turned on, therefore memory management is automatic.
A modern definition of that class would be declared as:
#interface SimpleCar : NSObject
#property(copy) NSString *make;
#property(copy) NSString *model;
#property(copy) NSNumber *vin;
- initWithMake:(NSString*)make model:(NSString*)model vin:(NSNumber*)vin;
#end
And would be implemented as:
#implementation SimpleCar
- initWithMake:(NSString*)make model:(NSString*)model vin:(NSNumber*)vin
{
if (self = [super init]) {
_make = [make copy];
_model = [model copy];
_vin = [vin copy];
}
return self;
}
#end
You wouldn't typically implement a convenience method like setMake:andModel:. It just adds API footprint without really buying much in the way of convenience. It also raises questions like "What happens when I observe either make or model?".
Related
I have a number of derived classes whose common base-class conforms to NSCoding. I want to be able to easily encode an NSArray holding instances of the various deriving classes.
#interface Base : NSObject <NSCoding>
#end
#interface DerivedSingleton : Base
+(instancetype) sharedInstance;
#end
#interface DerivedNonSingleton : Base
#end
The deriving singleton should have only one instance in the running system. It doesn't actually have any state to encode in the coder. It's instance is created with the +(void) initialize class method.
DerivedSingleton *sharedInstance;
#implementation DerivedSingleton
+(void) initialize
{
sharedInstance = [DerivedSingleton new];
}
+(instancetype) sharedInstance
{
return sharedInstance;
}
#end
So, if I now make an array holding instances of the classes, and encode it:
NSArray *const array = #[
[DerivedSingleton sharedInstance],
[DerivedNonSingleton new],
[DerivedNonSingleton new]];
NSData *const arrayData = [NSKeyedArchiver archivedDataWithRootObject: array];
When I later decode it, I require references to the shared singleton to decode as references to the shared singleton…
NSArray *const decodedArray = [NSKeyedUnarchiver unarchiveObjectWithData: arrayData];
[decodedArray objectAtIndex: 0] == [DerivedSingleton sharedInstance];
I note that the NSCoding protocol wants me to implement initWithCoder: for the singleton, but during decode, I want this class to provide the shared instance, not a newly alloced object.
Something like this should work
- (instancetype)initWithCoder:(NSCoder *)decoder
{
self = [super init];
return [self.class shared];
}
I would do something similar with the singleton:
.h
#import <Foundation/Foundation.h>
#pragma mark - Interface
#interface SerializableSingleton : NSObject <NSCoding>
#pragma mark - Class methods
#pragma mark - Shared instance
+ (instancetype)sharedInstance;
#end
.m
#import "SerializableSingleton.h"
#pragma mark - Reference
static id _serializableSingletonSharedInstance = nil;
#pragma mark - Implementation
#implementation SerializableSingleton
#pragma mark - Class methods
#pragma mark - Shared instance
+ (instancetype)sharedInstance {
#synchronized([self class]) {
if (_serializableSingletonSharedInstance == nil) {
_serializableSingletonSharedInstance = [[[self class] alloc] init];
}
}
return _serializableSingletonSharedInstance;
}
#pragma mark - Instance methods
#pragma mark - <NSCoding>
- (id)initWithCoder:(NSCoder *)aDecoder {
#synchronized([self class]) {
if (_serializableSingletonSharedInstance == nil) {
if (self = [super init]) {
// decode the desired data...
}
_serializableSingletonSharedInstance = self;
}
}
return _serializableSingletonSharedInstance;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
// encode the desired data
}
#end
I'm new to objective C and have been learning with the book "IOS Programming Big Nerd Ranch Guide 4th edition". I keep getting a recurring error and I have been working to resolve it for the last few hours. After researching for a bit, I came here. Any help would be greatly appreciated.
"No visible #interface for 'BNRItemStore' declares the selector 'deleteImageForKey;'"
BNRItemStore.h
#import <Foundation/Foundation.h>
#class BNRItem;
#interface BNRItemStore : NSObject
#property (nonatomic, readonly) NSArray *allItems;
// Notice that this is a class method and prefixed with a + instead of a -
+ (instancetype)sharedStore;
- (BNRItem *)createItem;
- (void)removeItem:(BNRItem *)item;
- (void)moveItemAtIndex:(NSInteger)fromIndex
toIndex:(NSInteger)toIndex;
#end
BNRItemStore.m
#import "BNRItemStore.h"
#import "BNRItem.h"
#interface BNRItemStore ()
#property (nonatomic) NSMutableArray *privateItems;
#end
#implementation BNRItemStore
+ (instancetype)sharedStore
{
static BNRItemStore *sharedStore = nil;
// Do I need to create a sharedStore?
if (!sharedStore) {
sharedStore = [[super allocWithZone:nil] init];
}
return sharedStore;
}
// If a programmer calls [[BNRItemStore alloc] init], let him
// know the error of his ways
- (instancetype)init
{
#throw [NSException exceptionWithName:#"Singleton"
reason:#"Use +[BNRItemStore sharedStore]"
userInfo:nil];
return nil;
}
// Here is the real (secret) initializer
- (instancetype)initPrivate
{
self = [super init];
if (self) {
_privateItems = [[NSMutableArray alloc] init];
}
return self;
}
- (NSArray *)allItems
{
return [self.privateItems copy];
}
- (BNRItem *)createItem
{
BNRItem *item = [BNRItem randomItem];
[self.privateItems addObject:item];
return item;
}
- (void)removeItem:(BNRItem *)item
{
NSString *key = item.itemKey;
if (key) {
[[BNRItemStore sharedStore] deleteImageForKey:key];
}
[self.privateItems removeObjectIdenticalTo:item];
}
- (void)moveItemAtIndex:(NSInteger)fromIndex
toIndex:(NSInteger)toIndex
{
if (fromIndex == toIndex) {
return;
}
// Get pointer to object being moved so you can re-insert it
BNRItem *item = self.privateItems[fromIndex];
// Remove item from array
[self.privateItems removeObjectAtIndex:fromIndex];
// Insert item in array at new location
[self.privateItems insertObject:item atIndex:toIndex];
}
#end
BNRImageStore.h
#import <Foundation/Foundation.h>
#interface BNRImageStore : NSObject
+ (instancetype)sharedStore;
- (void)setImage:(UIImage *)image forKey:(NSString *)key;
- (UIImage *)imageForKey:(NSString *)key;
- (void)deleteImageForKey:(NSString *)key;
#end
BNRImageStore.m
#import "BNRImageStore.h"
#interface BNRImageStore ()
#property (nonatomic, strong) NSMutableDictionary *dictionary;
#end
#implementation BNRImageStore
+ (instancetype)sharedStore
{
static BNRImageStore *sharedStore = nil;
if (!sharedStore) {
sharedStore = [[self alloc] initPrivate];
}
return sharedStore;
}
// No one should call init
- (instancetype)init
{
#throw [NSException exceptionWithName:#"Singleton"
reason:#"Use +[BNRImageStore sharedStore]"
userInfo:nil];
return nil;
}
// Secret designated initializer
- (instancetype)initPrivate
{
self = [super init];
if (self) {
_dictionary = [[NSMutableDictionary alloc] init];
}
return self;
}
- (void)setImage:(UIImage *)image forKey:(NSString *)key
{
self.dictionary[key] = image;
}
- (UIImage *)imageForKey:(NSString *)key
{
return self.dictionary[key];
}
- (void)deleteImageForKey:(NSString *)key
{
if (!key) {
return;
}
[self.dictionary removeObjectForKey:key];
}
#end
You are declaring the method deleteImageForKey in your BNRImageStore class, not in your BNRItemStore.
Check your implementation of removeItem: in BNRItemStore.m
- (void)removeItem:(BNRItem *)item
{
NSString *key = item.itemKey;
if (key) {
[[BNRItemStore sharedStore] deleteImageForKey:key];
}
[self.privateItems removeObjectIdenticalTo:item];
}
I assume you meant to refer to "BNRImageStore" and not BNRItemStore.
Apart from the typo, you should understand that Objective-C objects respond to selectors. Every Objective-C object has an array of selectors that it responds to. When you see the error: "No visible #interface for 'BNRItemStore' declares the selector 'deleteImageForKey;'" you should understand that the compiler does not see the selector you specified as being understood by the class in the error.
Im getting only this failure after having built the project.
Im using the XCode 4.6.3
class.m
#import "Car.h"
//constructor
-(id)init //<----- ***MISSING CONTEXT FOR METHOD DECLARATION***
{
self = [super init];
if(self){
self.brand = #"";
self.model = #"";
self.vin = 0;
}
return self;
class.h contains no error.
#import <Foundation/Foundation.h>
#interface Car : NSObject
{
NSString *brand, *model;
NSNumber *vin;
}
//set
-(void) setBrand:(NSString *) newBrand;
-(void) setModel:(NSString *) newModel;
-(void) setVIN:(NSNumber *) newVIN;
//get
-(NSString *) getBrand;
-(NSString *) getModel;
-(NSNumber *) getVIN;
//methods
-(void) accelerateTo100;
-(void) fuelConsuming;
-(void) hardStop;
#end
Can you help me with this. Thanks alot.
Answer is what #CodaFi explained. Try this
#import "Car.h"
#implementation Car
-(id)init
{
self = [super init];
if(self){
[self setBrand : #""];
[self setMode1 : #""];
[self setVIN : #""];
}
return self;
}
#end
Implementations of methods related to the Car class are always wrapped in #implementation Car and terminated with an #end. You're declaring and implementing methods without telling the compiler which class they belong to.
Check that you don't have an #import "..." within the #implementation section.
i have a static class witch has two property,like below ...
#interface Global : NSObject
{
BarcodeScanner* scanner;
NSInteger warehouseID;
}
#property(assign) BarcodeScanner* scanner;
#property(assign) NSInteger warehouseID;
+(Global *)sharedInstance;
#end
#import "Global.h"
#implementation Global
#synthesize scanner,warehouseID;
+ (Global *)sharedInstance
{
static Global *globalInstance = nil;
if (nil == globalInstance) {
globalInstance = [[Global alloc] init];
globalInstance.scanner = [[BarcodeScanner alloc] init];
globalInstance.warehouseID = 1;
}
return globalInstance;
}
-(void) dealloc
{
[super dealloc];
}
#end
now when i analyze project in Xcode i got warning for memory leak for scanner and warehouseID properties , and when i try to release them in dealloc method like ...
[[[Global sharedInstance] scanner]release];
i got warning "incorrect decrement of the reference count of an object..."
how should i resolve this problem.
so thanks for any help.
The warning is because your code does not match the rules Analyzer uses. To avoid the warning
make the scanner property retain
change the the instantiation or BarcodeScanner to be autorelease
add a release for scanner in dealloc
Example (reformatted just to save space):
#class BarcodeScanner;
#interface Global : NSObject {
BarcodeScanner* scanner;
NSInteger warehouseID;
}
#property(retain) BarcodeScanner* scanner;
#property(assign) NSInteger warehouseID;
+(Global *)sharedInstance;
#end
#implementation Global
#synthesize scanner,warehouseID;
+ (Global *)sharedInstance {
static Global *globalInstance = nil;
if (nil == globalInstance) {
globalInstance = [[Global alloc] init];
globalInstance.scanner = [[[BarcodeScanner alloc] init] autorelease];
globalInstance.warehouseID = 1;
}
return globalInstance;
}
-(void) dealloc {
[scanner release];
[super dealloc];
}
#end
just leave it to autorelease pool
globalInstance.scanner = [[[BarcodeScanner alloc] init] autorelease];
Ok, I'm still getting used to how Objective-c works.
Lets suppose I'm making a todo list app. Instead of just reading from a plist and loading it into a table, some people say that you should create a class, lets call it ToDo that contains for example:
NSString *title;
NSString *description;
Ok, fine. Now how would I use such a class to load my data from a plist or something? I don't understand how creating a little class helps. Can anyone explain to me how this works?
Just creat a subclass of NSObject with NSCoding protocol(if you want to save it in a plist)
Example: *.h file
#interface ToDo : NSObject <NSCoding> {
NSString *title;
NSString *toDoDescription;
}
#property (copy) NSString *title;
#property (copy) NSString *toDoDescription;
#end
Example: *.m file
#implementation ToDo
#synthesize title, toDoDescription;
- (id)init
{
if ((self = [super init])) {
[self setTitle:#"none"];
[self setToDoDescription:#"none"];
}
return self;
}
- (void)dealloc
{
[title release];
[toDoDescription release];
[super dealloc];
}
// Next two methods and coding protocol are needed to save your custom object into plist
- (id)initWithCoder:(NSCoder *)aDecoder
{
if ((self = [super init])) {
title = [[aDecoder decodeObjectForKey:#"title"] copy];
toDoDescription = [[aDecoder decodeObjectForKey:#"toDoDescription"] copy];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:title forKey:#"title"];
[aCoder encodeObject:toDoDescription forKey:#"toDoDescription"];
}
#end
Use NSKeyedArchiver to covert your object into NSData. And then add it to a plist.