Error: "Unrecognized selector" when using addObjects: on an NSMutableArray - objective-c

When executing
[self.blockViews addObject:curBlockView];
I get an error
2011-07-01 13:35:26.240 Block Breaker[42061:207] -[__NSArrayI addObject:]: unrecognized selector sent to instance 0x4e037a0
I am pretty new to Objective-C. Is it something in my init method?
//
// GameEngine.h
// Block Breaker
//
// Created by Chris Muench on 7/1/11.
// Copyright 2011 N/A. All rights reserved.
//
#import <Foundation/Foundation.h>
#interface GameEngine : NSObject {
NSMutableArray *blockViews;
int numBlockRows;
int score;
}
#property (nonatomic, copy) NSMutableArray *blockViews;
#property int numBlockRows;
#property int score;
- (void) setup;
- (void) setupBlocks;
#end
//
// GameEngine.m
// Block Breaker
//
// Created by Chris Muench on 7/1/11.
// Copyright 2011 N/A. All rights reserved.
//
#import "GameEngine.h"
#import "Block.h"
#import "BlockView.h"
#implementation GameEngine
#synthesize blockViews;
#synthesize numBlockRows;
#synthesize score;
- (id) init
{
if ((self = [super init]))
{
self.blockViews = [[NSMutableArray alloc] init];
self.numBlockRows = 2;
self.score = 0;
}
return self;
}
- (void) setup
{
[self setupBlocks];
}
- (void) setupBlocks
{
float blockWidth = 10;
float blockHeight = 10;
float rowSpacing = 2;
float colSpacing = 2;
float currentX = 0;
float currentY=10;
float screenWidth = 200;
for (int rowCounter=0;rowCounter<self.numBlockRows;rowCounter++)
{
while(currentX <=screenWidth)
{
Block *curBlock = [[Block alloc] initWithWidth:blockWidth height:blockHeight];
BlockView *curBlockView = [[BlockView alloc] initWithFrame:CGRectMake(currentX, currentY, curBlock.width, curBlock.height)];
curBlockView.block = curBlock;
[self.blockViews addObject:curBlockView];
currentX+=blockWidth+colSpacing;
[curBlock release];
[curBlockView release];
}
currentX=0;
currentY+=blockHeight+rowSpacing;
}
}
#end

When you copy an NSMutableArray using the copy method, or a synthesized setter for which the property was specified as copy, you get an immutable copy, which means you essentially end up with a plain NSArray.* There is a method mutableCopy which will preserve the mutability, but I don't believe there's any way to specify that for a property.
If you want your array to be mutably copied when you set it, you'll have to write your own setter method, and specify that method in the property declaration.
#property (nonatomic, copy, setter=setBlockViewsByCopying) NSMutableArray * blockViews;
- (void) setBlockViewsByCopying: (NSMutableArray *)newBlockViews {
NSMutableArray * tmp = [newBlockViews mutableCopy];
[blockViews release];
blockViews = tmp;
}
A side note, as #InsertWittyName mentioned in a comment, your code initializing blockViews will create a leak, because you have two claims of ownership on the array you're creating -- one for the alloc and one for the retain or copy that you get using the property:
self.blockViews = [[NSMutableArray alloc] init];
// ^ One claim ^ Two claims
// Only one release later, when the property is set again!
// LEAK!
You should instead do:
self.blockViews = [NSMutableArray array];
// Creates an object you don't own which you then make one claim
// on using the setter
*Though as it is a class cluster, you really get some unspecified concrete subclass.

Copy should retain, If I remember correctly.
Anyway using copying cannot be optimal, every time you call the accessor (set), you got a copy, and, as well pointed out above, is immutable.
Adding is fine, but remember to release the array when done.

Did you retain your array ??

Related

How can I pass a NSString parameter to a function?

I want to initialize an object. The problem is how to pass the NSString correctly.
Object code:
#import "ClaseHoja.h"
#implementation ClaseHoja
#synthesize pares;
#synthesize nombre;
-(id)init
{
self=[super init];
if(self){
}
return self;
}
-(id)initWithValues:(NSString*)nom par:(int)par
{
if([super init]){
pares=par;
nombre=nom;
}
return self;
}
When I call the function I do this:
NSString *nombre="Hello";
int par=20;
ClaseHoja *ch = [ClaseHoja alloc] initWithValues:nombre par:numPares]];
I would suggest:
Add the missing # to #"Hello" and fix the [] in your alloc/init call.
If you're using Xcode, I'd let the compiler synthesize the properties for you. No #synthesize is needed. If you're using a stand-alone LLVM on some other platform, though, you might need it, but by convention, you'd specify an ivar with a preceding _.
I'd define nombre to be copy property and explicitly copy the nombre value passed to your init method. You don't want to risk having a NSMutableString being passed to your method and having it unwittingly mutated without your knowledge.
I'd suggest renaming the initWithValues:par: to be initWithNombre:pares:, to eliminate any doubt about what properties are being updated.
You don't need init without parameters. You can just rely on the one provided by NSObject.
You'd generally use NSInteger rather than int.
In your custom init method, you want to make sure to do if ((self = [super init])) { ... }
Thus:
// ClaseHoja.h
#import Foundation;
#interface ClaseHora: NSObject
#property (nonatomic, copy) NSString *nombre;
#property (nonatomic) NSInteger pares;
- (id)initWithNombre:(NSString*)nombre pares:(NSInteger)pares;
#end
And
// ClaseHoja.m
#import "ClaseHoja.h"
#implementation ClaseHoja
// If you're using modern Objective-C compiler (such as included with Xcode),
// you don't need these lines, but if you're using, for example stand-alone
// LLVM in Windows, you might have to uncomment the following lines:
//
// #synthesize nombre = _nombre;
// #synthesize pares = _pares;
- (id)initWithNombre:(NSString*)nombre pares:(NSInteger)pares {
if ((self = [super init])) {
_pares = pares;
_nombre = [nombre copy];
}
return self;
}
#end
And you'd use it like so:
NSString *nombre = #"Hello";
NSInteger pares = 20;
ClaseHoja *ch = [[ClaseHoja alloc] initWithNombre:nombre pares:pares];
You need to pass like this. Another thing you miss # sign before the string.
NSString *nombre = #"Hello"; int par=20;
ClaseHoja *ch = [[ClaseHoja alloc]initWithValues:nombre par:par];

no visible #interface for NSMutable Array declares selector 'addStock'

I cannot figure out why the addStock method is not working for my NSMutableArray object "giuPort" . I have properly connected all the class files. How do I make it so that the interface is visible / correct this error that comes up for each of the times I try using the addStock method?
The following snippet from my main.m file that is rendering the error is:
NSMutableArray *giuPort = [[NSMutableArray alloc]init];
[giuPort addStock:apple];
[giuPort addStock:lvs];
[giuPort addStock:verizon];
the class .h file in which I declare the NSMutableArray, etc:
#interface BNRPortfolio : NSObject
{
NSMutableArray *_stocks;
}
#property (nonatomic, copy) NSArray *stocks;
#property (nonatomic) float valueOfPort;
//instance methods
-(void)addStock:(BNRStockHolding *)s;
-(float)valueOfPort;
#end
the class .m file in which I implement the NSMutableArray, etc:
#implementation BNRPortfolio
// array get set stuff
-(void)setStocks:(NSArray *)s
{
_stocks = [s mutableCopy];
}
-(NSArray *)stocks
{
return [_stocks copy];
}
// instance methods
-(void)addStock:(BNRStockHolding *)s {
// check to see if array exists
if (!_stocks) {
_stocks = [[NSMutableArray alloc]init];
}
[_stocks addObject:s];
}
-(float)valueOfPort {
//take sum of all the stocks in this port
float sum = 0;
for (BNRStockHolding *s in _stocks) {
sum += [s valueInDollars];
}
return sum;
}
#end
The -addStock: method is a method of the BNRPortfolio class. You are attempting to call it on an instance of NSMutableArray. There's no such method on NSMutableArray, which is what the compiler is complaining about.
Apparently, you want to allocate and initialize an instance of BNRPortfolio and then call -addStock: on that.

Singleton set in AppDelegate loses it value when allocated in another class

I have a iPad application where I'm attempting to use a singleton. This is the code in the .h file:
//-------------------------------------------
//-- singleton: timeFormat
#interface SingletonTimeFormat : NSObject {
}
#property (nonatomic, retain) NSNumber *timeFormat;
+ (id)sharedTimeFormat;
#end
This is the code from the .m file:
//-------------------------------------------
//-- SingletonTimeFormat
#implementation SingletonTimeFormat {
}
#synthesize timeFormat;
//-- sharedColorScheme --
+ (id)sharedTimeFormat {
static dispatch_once_t dispatchOncePredicate = 0;
__strong static id _sharedObject = nil;
dispatch_once(&dispatchOncePredicate, ^{
_sharedObject = [[self alloc] init];
});
return _sharedObject;
}
-id) init {
self = [super init];
if (self) {
timeFormat = [[NSNumber alloc] init];
}
return self;
}
#end
I load the value (either 12 or 24) in AppDelegate - didFinishLaunchingWithOptions, then when I want to get the value of timeFormat I use this:
SingletonTimeFormat *stf = [[SingletonTimeFormat alloc]init];
if([stf.timeFormat isEqualToNumber: [NSNumber numberWithInt:12]]) {
which returns 0 (it was set correctly in AppDelegate, but apparently when I do the alloc in another class, it loses it's value. So obviously it's not working! (I have several other singletons that have the same pattern, but so far they appear to be working.
What's wrong here and how do I fix it?
You don't want to call your singleton using alloc init. With this singleton, all references to it should be through its sharedTimeFormat method, which will init the object if necessary, and will return the singleton instance otherwise.
In other words, it doesn't appear that you're referencing the instance of the object stored in the static sharedObject variable, which means that it's stored value will not necessarily be the same.

NSArray of weak references (__unsafe_unretained) to objects under ARC

I need to store weak references to objects in an NSArray, in order to prevent retain cycles. I'm not sure of the proper syntax to use. Is this the correct way?
Foo* foo1 = [[Foo alloc] init];
Foo* foo2 = [[Foo alloc] init];
__unsafe_unretained Foo* weakFoo1 = foo1;
__unsafe_unretained Foo* weakFoo2 = foo2;
NSArray* someArray = [NSArray arrayWithObjects:weakFoo1, weakFoo2, nil];
Note that I need to support iOS 4.x, thus the __unsafe_unretained instead of __weak.
EDIT (2015-02-18):
For those wanting to use true __weak pointers (not __unsafe_unretained), please check out this question instead: Collections of zeroing weak references under ARC
As Jason said, you can't make NSArray store weak references. The easiest way to implement Emile's suggestion of wrapping an object inside another object that stores a weak reference to it is the following:
NSValue *value = [NSValue valueWithNonretainedObject:myObj];
[array addObject:value];
Another option: a category that makes NSMutableArray optionally store weak references.
Note that these are "unsafe unretained" references, not self-zeroing weak references. If the array is still around after the objects are deallocated, you'll have a bunch of junk pointers.
The solutions to use a NSValue helper or to create a collection (array, set, dict) object and disable its Retain/Release callbacks are both not 100% failsafe solutions with regard to using ARC.
As various comments to these suggestions point out, such object references will not work like true weak refs:
A "proper" weak property, as supported by ARC, has two behaviors:
Doesn't hold a strong ref to the target object. That means that if the object has no strong references pointing to it, the object will be deallocated.
If the ref'd object is deallocated, the weak reference will become nil.
Now, while the above solutions will comply with behavior #1, they do not exhibit #2.
To get behavior #2 as well, you have to declare your own helper class. It has just one weak property for holding your reference. You then add this helper object to the collection.
Oh, and one more thing: iOS6 and OSX 10.8 supposedly offer a better solution:
[NSHashTable weakObjectsHashTable]
[NSPointerArray weakObjectsPointerArray]
[NSPointerArray pointerArrayWithOptions:]
These should give you containers that hold weak references (but note matt's comments below).
An example (updated 2 Feb 2022)
#import <Foundation/Foundation.h>
static BOOL didDealloc = NO;
#interface TestClass : NSObject
#end
#implementation TestClass
-(void)dealloc {
didDealloc = YES;
}
#end
int main(int argc, const char * argv[]) {
NSPointerArray *pa = [NSPointerArray weakObjectsPointerArray];
#autoreleasepool {
TestClass *obj = TestClass.new;
[pa addPointer:(__bridge void * _Nullable)(obj)]; // stores obj as a weak ref
assert([pa pointerAtIndex:0] != nil);
assert(!didDealloc);
} // at this point the TestClass obj will be deallocated
assert(didDealloc);
assert([pa pointerAtIndex:0] == nil); // verify that the weak ref is null now
return 0;
}
If you run this you'll find that after adding the TestClass object to the pointer array pa, then releasing that object again, the pointer (which is internally a weak object ref) is now set to null as desired.
However, note that calling [pa compact] at the end will not remove the nil pointer as I'd have expected.
I am new to objective-C, after 20 years of writing c++.
In my view, objective-C is excellent at loosely-coupled messaging, but horrible for data management.
Imagine how happy I was to discover that xcode 4.3 supports objective-c++!
So now I rename all my .m files to .mm (compiles as objective-c++) and use c++ standard containers for data management.
Thus the "array of weak pointers" problem becomes a std::vector of __weak object pointers:
#include <vector>
#interface Thing : NSObject
#end
// declare my vector
std::vector<__weak Thing*> myThings;
// store a weak reference in it
Thing* t = [Thing new];
myThings.push_back(t);
// ... some time later ...
for(auto weak : myThings) {
Thing* strong = weak; // safely lock the weak pointer
if (strong) {
// use the locked pointer
}
}
Which is equivalent to the c++ idiom:
std::vector< std::weak_ptr<CppThing> > myCppThings;
std::shared_ptr<CppThing> p = std::make_shared<CppThing>();
myCppThings.push_back(p);
// ... some time later ...
for(auto weak : myCppThings) {
auto strong = weak.lock(); // safety is enforced in c++, you can't dereference a weak_ptr
if (strong) {
// use the locked pointer
}
}
Proof of concept (in the light of Tommy's concerns about vector reallocation):
main.mm:
#include <vector>
#import <Foundation/Foundation.h>
#interface Thing : NSObject
#end
#implementation Thing
#end
extern void foo(Thing*);
int main()
{
// declare my vector
std::vector<__weak Thing*> myThings;
// store a weak reference in it while causing reallocations
Thing* t = [[Thing alloc]init];
for (int i = 0 ; i < 100000 ; ++i) {
myThings.push_back(t);
}
// ... some time later ...
foo(myThings[5000]);
t = nullptr;
foo(myThings[5000]);
}
void foo(Thing*p)
{
NSLog(#"%#", [p className]);
}
example log output:
2016-09-21 18:11:13.150 foo2[42745:5048189] Thing
2016-09-21 18:11:13.152 foo2[42745:5048189] (null)
If you do not require a specific order you could use NSMapTable with special key/value options
NSPointerFunctionsWeakMemory
Uses weak read and write barriers appropriate for ARC or GC. Using NSPointerFunctionsWeakMemory object references will turn to NULL on last release.
I believe the best solution for this is to use NSHashTable or NSMapTable. the Key or/and the Value can be weak. You can read more about it here: http://nshipster.com/nshashtable-and-nsmaptable/
To add weak self reference to NSMutableArray, create a custom class with a weak property as given below.
NSMutableArray *array = [NSMutableArray new];
Step 1: create a custom class
#interface DelegateRef : NSObject
#property(nonatomic, weak)id delegateWeakReference;
#end
Step 2: create a method to add self as weak reference to NSMutableArray. But here we add the DelegateRef object
-(void)addWeakRef:(id)ref
{
DelegateRef *delRef = [DelegateRef new];
[delRef setDelegateWeakReference:ref]
[array addObject:delRef];
}
Step 3: later on, if the property delegateWeakReference == nil, the object can be removed from the array
The property will be nil, and the references will be deallocated at proper time independent of this array references
The simplest solution:
NSMutableArray *array = (__bridge_transfer NSMutableArray *)CFArrayCreateMutable(nil, 0, nil);
NSMutableDictionary *dictionary = (__bridge_transfer NSMutableDictionary *)CFDictionaryCreateMutable(nil, 0, nil, nil);
NSMutableSet *set = (__bridge_transfer NSMutableSet *)CFSetCreateMutable(nil, 0, nil);
Note: And this works on iOS 4.x too.
No, that's not correct. Those aren't actually weak references. You can't really store weak references in an array right now. You need to have a mutable array and remove the references when you're done with them or remove the whole array when you're done with it, or roll your own data structure that supports it.
Hopefully this is something that they'll address in the near future (a weak version of NSArray).
I've just faced with same problem and found that my before-ARC solution works after converting with ARC as designed.
// function allocates mutable set which doesn't retain references.
NSMutableSet* AllocNotRetainedMutableSet() {
CFMutableSetRef setRef = NULL;
CFSetCallBacks notRetainedCallbacks = kCFTypeSetCallBacks;
notRetainedCallbacks.retain = NULL;
notRetainedCallbacks.release = NULL;
setRef = CFSetCreateMutable(kCFAllocatorDefault,
0,
&notRetainedCallbacks);
return (__bridge NSMutableSet *)setRef;
}
// test object for debug deallocation
#interface TestObj : NSObject
#end
#implementation TestObj
- (id)init {
self = [super init];
NSLog(#"%# constructed", self);
return self;
}
- (void)dealloc {
NSLog(#"%# deallocated", self);
}
#end
#interface MainViewController () {
NSMutableSet *weakedSet;
NSMutableSet *usualSet;
}
#end
#implementation MainViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
weakedSet = AllocNotRetainedMutableSet();
usualSet = [NSMutableSet new];
}
return self;
}
- (IBAction)addObject:(id)sender {
TestObj *obj = [TestObj new];
[weakedSet addObject:obj]; // store unsafe unretained ref
[usualSet addObject:obj]; // store strong ref
NSLog(#"%# addet to set", obj);
obj = nil;
if ([usualSet count] == 3) {
[usualSet removeAllObjects]; // deallocate all objects and get old fashioned crash, as it was required.
[weakedSet enumerateObjectsUsingBlock:^(TestObj *invalidObj, BOOL *stop) {
NSLog(#"%# must crash here", invalidObj);
}];
}
}
#end
Output:
2013-06-30 00:59:10.266 not_retained_collection_test[28997:907]
constructed 2013-06-30 00:59:10.267
not_retained_collection_test[28997:907] addet to
set 2013-06-30 00:59:10.581 not_retained_collection_test[28997:907]
constructed 2013-06-30 00:59:10.582
not_retained_collection_test[28997:907] addet to
set 2013-06-30 00:59:10.881 not_retained_collection_test[28997:907]
constructed 2013-06-30 00:59:10.882
not_retained_collection_test[28997:907] addet to
set 2013-06-30 00:59:10.883 not_retained_collection_test[28997:907]
deallocated 2013-06-30 00:59:10.883
not_retained_collection_test[28997:907]
deallocated 2013-06-30 00:59:10.884
not_retained_collection_test[28997:907]
deallocated 2013-06-30 00:59:10.885
not_retained_collection_test[28997:907] * -[TestObj
respondsToSelector:]: message sent to deallocated instance 0x1f03c8c0
Checked with iOS versions 4.3, 5.1, 6.2.
Hope it will be useful to somebody.
If you need zeroing weak references, see this answer for code you can use for a wrapper class.
Other answers to that question suggest a block-based wrapper, and ways to automatically remove zeroed elements from the collection.
If you use a lot this comportment it's indicated to your own NSMutableArray class (subclass of NSMutableArray) which doesn't increase the retain count.
You should have something like this:
-(void)addObject:(NSObject *)object {
[self.collection addObject:[NSValue valueWithNonretainedObject:object]];
}
-(NSObject*) getObject:(NSUInteger)index {
NSValue *value = [self.collection objectAtIndex:index];
if (value.nonretainedObjectValue != nil) {
return value.nonretainedObjectValue;
}
//it's nice to clean the array if the referenced object was deallocated
[self.collection removeObjectAtIndex:index];
return nil;
}
I think an elegant solution is what Mr. Erik Ralston propose on his Github repository
https://gist.github.com/eralston/8010285
this are the essential steps:
create a category for NSArray and NSMutableArray
in the implementation create a convenience class with a weak property. Your category will assign the objects to this weak property.
.h
#import <Foundation/Foundation.h>
#interface NSArray(WeakArray)
- (__weak id)weakObjectForIndex:(NSUInteger)index;
-(id<NSFastEnumeration>)weakObjectsEnumerator;
#end
#interface NSMutableArray (FRSWeakArray)
-(void)addWeakObject:(id)object;
-(void)removeWeakObject:(id)object;
-(void)cleanWeakObjects;
#end
.m
#import "NSArray+WeakArray.h"
#interface WAArrayWeakPointer : NSObject
#property (nonatomic, weak) NSObject *object;
#end
#implementation WAArrayWeakPointer
#end
#implementation NSArray (WeakArray)
-(__weak id)weakObjectForIndex:(NSUInteger)index
{
WAArrayWeakPointer *ptr = [self objectAtIndex:index];
return ptr.object;
}
-(WAArrayWeakPointer *)weakPointerForObject:(id)object
{
for (WAArrayWeakPointer *ptr in self) {
if(ptr) {
if(ptr.object == object) {
return ptr;
}
}
}
return nil;
}
-(id<NSFastEnumeration>)weakObjectsEnumerator
{
NSMutableArray *enumerator = [[NSMutableArray alloc] init];
for (WAArrayWeakPointer *ptr in self) {
if(ptr && ptr.object) {
[enumerator addObject:ptr.object];
}
}
return enumerator;
}
#end
#implementation NSMutableArray (FRSWeakArray)
-(void)addWeakObject:(id)object
{
if(!object)
return;
WAArrayWeakPointer *ptr = [[WAArrayWeakPointer alloc] init];
ptr.object = object;
[self addObject:ptr];
[self cleanWeakObjects];
}
-(void)removeWeakObject:(id)object
{
if(!object)
return;
WAArrayWeakPointer *ptr = [self weakPointerForObject:object];
if(ptr) {
[self removeObject:ptr];
[self cleanWeakObjects];
}
}
-(void)cleanWeakObjects
{
NSMutableArray *toBeRemoved = [[NSMutableArray alloc] init];
for (WAArrayWeakPointer *ptr in self) {
if(ptr && !ptr.object) {
[toBeRemoved addObject:ptr];
}
}
for(WAArrayWeakPointer *ptr in toBeRemoved) {
[self removeObject:ptr];
}
}
#end

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