ARC and Message Forwarding [duplicate] - iphone

This question already has answers here:
Error compiling with ARC when runtime programming dynamic method
(2 answers)
Closed 8 years ago.
I tried to implement Message Forwarding.
Xcode 5, ARC is ON, new default iPhone project.
I read a documentation here
I have two custom classes in my project: Hello and World.
#import <Foundation/Foundation.h>
#interface Hello : NSObject
- (void) say;
#end
#import "Hello.h"
#import "World.h"
#implementation Hello
- (void) say {
NSLog(#"hello!");
}
-(void)forwardInvocation:(NSInvocation *)invocation {
NSLog(#"forward invocation");
World *w = [[World alloc] init];
if ([w respondsToSelector:[invocation selector]]) {
[invocation invokeWithTarget:w];
} else {
[self doesNotRecognizeSelector: [invocation selector]];
}
}
-(NSMethodSignature*)methodSignatureForSelector:(SEL)selector {
NSLog(#"method signature");
NSMethodSignature *signature = [super methodSignatureForSelector:selector];
if (! signature) {
World *w = [[World alloc] init];
signature = [w methodSignatureForSelector:selector];
}
return signature;
}
#end
World is simple:
#import <Foundation/Foundation.h>
#interface World : NSObject
- (void) spin;
#end
#import "World.h"
#implementation World
- (void) spin {
NSLog(#"spin around");
}
#end
In my AppDelegate i wrote three simple lines:
Hello *me = [[Hello alloc] init];
[me say];
[me spin];
And compiler give me an error: AppDelegate.m:23:9: No visible #interface for 'Hello' declares the selector 'spin' and doesn't build a project. When I retype it: [me performSelector:#selector(spin)]; - it works fine.
Code [me spin] works when ARC is OFF only (but compiler generates a warning AppDelegate.m:23:9: 'Hello' may not respond to 'spin').
My questions: why? and How can I use ARC with message forwarding?

Try declaring me as id:
id me = [[Hello alloc] init];
[me say];
[me spin];

Related

Sending NSString to viewController returns a null [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions concerning problems with code you've written must describe the specific problem — and include valid code to reproduce it — in the question itself. See SSCCE.org for guidance.
Closed 9 years ago.
Improve this question
I sent a NSString to a viewController, tried to log it from another viewController, and it turned null. My code is below
Edit: Im deleting all code and showing my code from my application. Because I am still getting (null)
HabitViewController.h
#import <UIKit/UIKit.h>
#interface HabitViewController : UITableViewController {
NSString *cellName2;
}
#property(nonatomic,retain) NSString *cellName2;
#end
HabitViewController.m
#synthesize cellName2;
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"%#",cellName2);
}
DetailViewController.h
#import <UIKit/UIKit.h>
#interface DetailViewController : UIViewController {
NSString *cellName;
}
#property(nonatomic,retain) NSString *cellName;
#end
DetailViewController.m
#import "DetailViewController.h"
#import "HabitViewController.h"
#end
#implementation DetailViewController
#synthesize cellName;
#pragma mark - Managing the detail item
- (void)viewDidLoad
{
[super viewDidLoad];
cellName = #"Hello World";
HabitViewController *obj = [[HabitViewController alloc] init];
obj.cellName2 = cellName;
}
I left a lot of code out, because they had nothing to do with my problem.
Edit
Based on Jsdodgers comments and answer, I have updated My question :
habitViwController.h
#import <UIKit/UIKit.h>
#interface HabitViewController : UITableViewController {
}
#property(nonatomic,retain) NSString *cellName2;
#end
.m
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"%#",self.cellName2);
}
DetailViewController.h
#import <UIKit/UIKit.h>
#interface DetailViewController : UIViewController {
}
#property(nonatomic,retain) NSString *cellName;
#end
.m
#synthesize cellName;
- (void)viewDidLoad
{
[super viewDidLoad];
cellName = #"Hello World";
HabitViewController *obj = [[HabitViewController alloc] init];
obj.cellName2 = self.cellName;
[self configureView];
}
But I still dont have any success. Still says (null)
This is because you have two different variables in your ReceiverViewController.
One of them is called cellName2, which you are creating through NSString *cellName2. The other is called _cellName2 which you are creating through #property(nonatomic,retain) NSString *cellName2;.
The first you can call in your ReceiverViewController through cellName2.... The second, you can call through either _cellName2... or self.cellName2.
When you do obj.cellName2 = ..., you are setting the _cellName2, not cellName2. Thus, when you print cellName2, it is correctly null as you have not set it yet.
I would suggest completely removing the NSString *cellName2; from your code. Same goes for the cellName in your other class.
Based on your edited question, I think you have simply not synthesized cellName2 in your ReceiverViewController.
Use the #synthesize statement.
edit
Instantiating and setting the value of the Receiving View Controller:
ReceiverViewController *rvc = [[ReceiverViewController alloc] init];
rvc.stringValue = #"Hello world :)";
[self presentViewController:rvc animated:YES completion:nil];

confused category in objective-c concept

hi i'm wondering category in objective-c
i have 3 files
A_ViewController
A_ViewController+Category
B_ViewController
here's example code
1-1. A_ViewController.h
#interface A_ViewController {
// some instance Variables
}
//some public methods
#end
1-2 A_ViewController.m
#import "A_ViewController.h."
#implementation A_ViewController
// implementation public methods and private methods
#end
2-1. A_ViewController+Category.h
#interface A_ViewControler(Category)
-(void) categoryMethod;
#end
2-2. A_ViewController+Category.m
#import "A_ViewController.h"
#import "A_ViewController+Category.h"
#implementation A_ViewController(Category)
-(void) categoryMethod {
NSLog(#"it's A_ViewController+Category");
}
#end
3-1. B_ViewController.h
#interface B_ViewController {
// some instance variables
}
-(void) myMethod;
3-2. B_ViewController.m
#import "B_ViewController.h"
#import "A_ViewController.h"
#interface A_ViewController() // i think it's A_ViewController extension, not A_ViewController+Category, am i right?
-(void) categoryMethod;
#end
#implementation B_ViewController
-(void) myMethod
{
A_ViewController *obj = [[A_ViewController alloc] init];
[obj categoryMethod];
}
#end
i thought it's crashed because i'm not import A_ViewController+Category.h
and i'm not implement -(void) categoryMethod in B_ViewController.m
but it works fine, and no warning.
how [obj categoryMethod] can be linked??
if that's perfectly fine syntax, i have extension question.
if i have another category called A_ViewController+Category2
here's A_ViewController+Category.h
#interface A_ViewController(Category2)
-(void) categoryMethod;
#end
and A_ViewController+Category2.m
#import "A_ViewController.h"
#import "A_ViewController+Category2.h"
#implementation A_ViewController(Category2)
-(void) categoryMethod
{
NSLog(#"it's A_ViewController+Category2");
}
#end
and this situation, if i write a code like 3-2,
then [obj categoryMethod] can' be guaranteed
that comes from A_ViewController+Category or A_ViewController+Category2, right?
I'm struggling slightly to work out what you're trying to do but in regard to standard category behaviour.
If you want to call categoryMethod on an instance of A_ViewController from within B_BiewController you need to import the header that contains the category method #interface.
You can't declare the private category () on A_ViewController from within B_ViewController.m, as the private category or class extension is a special category.
B_ViewController.m should look like this
#import "B_ViewController.h"
#import "A_ViewController+Category.h"
#implementation B_ViewController
- (void) myMethod {
A_ViewController *obj = [[A_ViewController alloc] init];
[obj categoryMethod];
}
#end
Edit
I've just noticed your Category2 method name is the same as your Category method name. This is incorrect and undefined behaviour in Objective C.

iPhone SDK - Converting my delegate based function to blocks

I have a very simple class (currently used as a testing class), which uses delegate/protocol methods to interface with it's parent class. However, I would really like to convert this to use blocks. Yet I can't find a good resource or tutorial out there to help me figure out how to do this. All the blocks tutorials are just way to complicated, and I would really just like a small, concise example of how to do this.
I currently have the class:
#import <Foundation/Foundation.h>
#protocol TestObjectDelegate <NSObject>
#optional
-(void)testObjectSucceeded:(BOOL)passedTest;
-(void)testObjectedFailed:(NSError *)error;
#end
#interface TestObject : NSObject {
id<TestObjectDelegate> _delegate;
}
-(void)compare:(NSString *)stringA with:(NSString *)stringB;
#end
#import "TestObject.h"
#implementation TestObject
- (id)initWithDelegateController:(id<TestObjectDelegate>)delegate {
self = [super init];
if (self) {
_delegate = delegate;
}
return self;
}
-(void)compare:(NSString *)stringA with:(NSString *)stringB {
if ([stringA isEqualToString:stringB]) {
if(_delegate && [_delegate respondsToSelector:#selector(testObjectSucceeded:)]) {
[_delegate testObjectSucceeded:YES];
}
else {
[_delegate testObjectSucceeded:NO];
}
}
else {
if(_delegate && [_delegate respondsToSelector:#selector(testObjectedFailed:)]) {
[_delegate testObjectedFailed:nil];
}
}
}
#end
How could I begin to convert this to a blocks based function? Also, I know 'retain cycles' are something to watch out for when implementing a blocks function. What would I need to watch out for when converting this class to use blocks instead of delegate/protocols? Googling 'retain cycles' also gives some overly complicated answers.
Any starting pointers would be much appreciated?
Maybe this example gives you an idea:
typedef void (^MyCallbackBlock)(BOOL);
#interface TestObject : NSObject {
}
#property (nonatomic, copy) MyCallbackBlock myBlock;
#end
#import "TestObject.h"
#implementation TestObject
-(void) yourMethod
{
...
self.myBlock(YES); // call block with argument
...
}
- (void)dealloc
{
[myBlock release];
myBlock = nil;
[super dealloc];
}
#end
When using the object you can then define the block like this:
TestObject* theTestObject = [[TestObject alloc] init];
theTestObject.myBlock = ^(BOOL theParameter){
NSLog(#"foo");
};

Correct way to create/use a Singleton NSMutableArray for Xcode 4

I've reviewed (and tried) a bunch of the threads here regarding Singletons and NSMutableArrays. I'm new to Objective-C so please bear with me.
I simply want to create a few arrays that can be accessed from any view/.m file.
What is the best (or most concise) coding for a Singleton?
Below is what I have now and I get
1 warning at .m '#implementation' - "Incomplete implementation"
1 error at usage in a view .m file - "initializer element is not a compile-time constant"
This is the code I have now - my GlobalData.h file:
#import <Foundation/Foundation.h>
#interface GlobalData : NSObject {
NSMutableArray *listOfHeadings;
NSMutableArray *listOfItems1;
NSMutableArray *listOfItems2;
}
#property(nonatomic,retain)NSMutableArray *listOfHeadings;
#property(nonatomic,retain)NSMutableArray *listOfItems1;
#property(nonatomic,retain)NSMutableArray *listOfItems2;
+(GlobalData*)getInstance;
#end
My GlobalData.m file:
#import "GlobalData.h"
#implementation GlobalData
#synthesize listOfHeadings;
#synthesize listOfItems1;
#synthesize listOfItems2;
static GlobalData *instance=nil;
+(GlobalData *)getInstance
{
#synchronized(self)
{
if(instance==nil)
{
instance= [GlobalData new];
}
}
return instance;
}
#end
And in a view .m file (simplified):
#import GlobalData.h
GlobalData *globDat=[GlobalData getInstance]; //error occurs here
Can someone point out the trouble and if there's better coding, please enlighten me - thanks!
EDIT
Here's a few links I've tried to use:
Can i have a single NSMutableArray in my multiple views application?
iPhone help with singleton class
In this case, you might be doing more than you have to. Granted this certainly isn't always the best solution - but you can put your NSMutableArray as a property in your App Delegate and then easily refer to it from any view. By doing it this way - you aren't locking it in as a 'singleton' but there is a 'singleton instance' of it (this helps a great deal for testability).
I have simplified this process here:
YourAppDelegate.h
#property (nonatomic,retain) NSMutableArray *myArray;
YourAppDelegate.m
#synthesize myArray;
YourViewController.m
YourAppDelegate *appDelegate = (YourAppDelegate *)[[UIApplication sharedApplication] delegate];
NSMutableArray *myArrayFromAppDelegate = appDelegate.myArray;
From this point - you can do any manipulation on this value.
Here's the "modern" version of a single method to turn any class into a Singleton (in this case formatted as a code snippet). It works in iOS4.x or higher:
+(<#SingletonClassName#> *) sharedInstance
{
static <#SingletonClassName#> *_sharedClient = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_sharedClient = [[self alloc] init];
});
return _sharedClient;
}
But, do you really need a singleton of a single NSMutableArray? You could use the built-on singleton - your application delegate, which is got to by calling:
MyAppDelegate * appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate.myMutableArray addObject:...];
The error initializer element is not a compile-time constant is not related to how you create your singleton. The error is how you are accessing your singleton. You are doing this outside of a function:
GlobalData *globDat=[GlobalData getInstance];
This means that you are trying to initialize a global variable (globDat) as the value of the expression [GlobalData getInstance]. You can only initialize global variables to expressions that are "compile-time constants". That means things like 0 or "fred" or 8/2. The value of [GlobalData getInstance] cannot be computed at compile-time, so it cannot be used to initialize the global variable.
Instead, you need to just use [GlobalData getInstance] inside your function bodies wherever you are currently trying to use the globDat variable.
As for the warning, Incomplete implementation, I don't see what's missing. Perhaps you didn't post all of the code from GlobalData.h. Anyway, you should be able to click the warning (where it appears on the right side of the editor window) and have Xcode show you what's missing.
This is the way I create my Singleton:
Singleton.h
#import <Foundation/Foundation.h>
#interface Singleton : NSObject {
NSMutableArray *firstMutableArray;
NSMutableArray *secondMutableArray;
}
#property (nonatomic, retain) NSMutableArray *firstMutableArray;
#property (nonatomic, retain) NSMutableArray *secondMutableArray;
+ (id)sharedSingleton;
#end
Sigleton.m
#import "Singleton.h"
static Singleton *sharedMySingleton = nil;
#implementation Singleton
#synthesize firstMutableArray;
#synthesize secondMutableArray;
#pragma mark Singleton Methods
+ (id)sharedSingleton {
#synchronized(self) {
if (sharedMySingleton == nil) {
sharedMySingleton = [[super allocWithZone:NULL] init];
}
return sharedMySingleton;
}
+ (id)allocWithZone:(NSZone *)zone {
return [[self sharedSingleton] retain];
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
- (id)retain {
return self;
}
- (unsigned)retainCount {
return UINT_MAX;
}
- (oneway void)release {
// Never release
}
- (id)autorelease {
return self;
}
- (id)init {
if (self = [super init]) {
firstMutableArray = [[NSMutableArray alloc] initWithObjects:nil];
secondMutableArray = [[NSMutableArray alloc] initWithObjects:nil];
}
return self;
}
- (void)dealloc {
[firstMutableArray release];
[secondMutableArray release];
[super dealloc];
}
#end
Then, when you want to call your Singleton:
#import "Singleton.h"
Singleton *singleton = [Singleton sharedSingleton];
singleton.firstMutableArray = ...
singleton.secondMutableArray = ...

unrecognized selector sent to instance

I have an NSObject called FHSUploadManager, which is a singleton object. Everything has appears to be working, expect today I been getting some strange messages.
2011-09-16 13:26:05.892 FHMedia[6038:6903] -[FHSUploadManager initialize]: unrecognized selector sent to instance 0x6b96900
2011-09-16 13:26:06.975 FHMedia[6038:6903] *** NSInvocation: warning: object 0xb0352cb8 of class 'úè0°8s†Gà–!Ä' does not implement methodSignatureForSelector: -- trouble ahead
2011-09-16 13:26:06.983 FHMedia[6038:6903] *** NSInvocation: warning: object 0xb0352cb8 of class 'úè0°8s†Gà–!Ä' does not implement doesNotRecognizeSelector: -- abort
It does not look like anything is broken, but these messages have me concern. Has anyone seen this before? Anyone have an idea on how to debug this?
I have taken out some of the methods for privacy and space.
Here is my FHSUploadManager.h
#class ListObject;
#class MergedItem;
#class ServerSync;
#class AppDelegate_Shared;
#class RegisteredUser;
#interface FHSUploadManager : NSObject {
NSMutableArray *uploadItems;
NSMutableArray *objectIds;
// KVO values
BOOL isSyncing;
NSString *uploadingStatus;
ListObject *uploadObject;
AppDelegate_Shared *appDelegate;
ServerSync *sync;
}
#property (assign) BOOL isSyncing;
#property (assign) NSString *uploadingStatus;
#property (assign) ListObject *uploadObject;
#property (assign) AppDelegate_Shared *appDelegate;
#end
Here is FHSUploadManager.m
#import "FHSUploadManager.h"
#import "ListObject.h"
#import "Reachability.h"
#import "ServerSync.h"
#import "AppDelegate_Shared.h"
#import "ItemAttribute.h"
#import "CoreItem.h"
#import "Media.h"
#import "MergedItem.h"
#import "WebServices.h"
#import "NSManagedObject+XML.h"
#import "NSNotificationCenter+MainThread.h"
#import "PowerMeXMLParser.h"
#import "RegisteredUser.h"
#import "TBXML.h"
static FHSUploadManager* sharedInstanceFHSUploadManager = nil;
#implementation FHSUploadManager
#synthesize isSyncing;
#synthesize uploadingStatus;
#synthesize uploadObject;
#synthesize appDelegate;
- (void)dealloc {
[uploadItems release];
[uploadingStatus release];
[uploadObject release];
[objectIds release];
[sync release];
[super dealloc];
}
-(void)startUpload
{
if( !isSyncing )
{
self.isSyncing = YES;
[self performSelectorInBackground:#selector(uploadingInBackground) withObject:nil];
}
}
// !!! Other methods and not added here. !!!
#pragma mark - Apple Boiler Plate Singleton -
+ (FHSUploadManager*)sharedInstance {
#synchronized(self)
{
if (sharedInstanceFHSUploadManager == nil) {
sharedInstanceFHSUploadManager = [[super allocWithZone:NULL] init];
sharedInstanceFHSUploadManager.isSyncing = NO;
sharedInstanceFHSUploadManager.appDelegate = (AppDelegate_Shared*)[[UIApplication sharedApplication] delegate];
}
}
return sharedInstanceFHSUploadManager;
}
+ (id)allocWithZone:(NSZone *)zone {
return [[self sharedInstance] retain];
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
- (id)retain {
return self;
}
- (NSUInteger)retainCount {
return NSUIntegerMax; //denotes an object that cannot be released
}
- (void)release {
//do nothing
}
- (id)autorelease {
return self;
}
#end
Update After comment saying it was gone
It is back! I talked with a fellow programmer and he is wondering if I am stomping on some memory. So I am going to look into a little bit more.
Looks like you are not inheriting from NSObject...
The FHSUploadManager object class is deallocating. In the Edit Schemes Enable Zombie Objects. You will get log of the deallocated instance.
You may be accessing the object once it is freed.
Add a breakpoint on FHSUploadManager dealloc method.