Objective-C iOS 6 delegate NSString query - objective-c

I'm trying to use a delegate to pass a value from one VC to another. I think I'm am misunderstanding the way it is supposed to work.
In my main ViewController.h I have this:
#protocol defaultLocationChoice <NSObject>
- (NSString *) locChoice;
#end
In both my PreferencesViewController.h and ChooseServerViewController.h I have defaultLocationChoice declared in the #interface section and the property assinged like so:
#property (nonatomic, assign) id <defaultLocationChoice> locationDelegate;
Both are synthesized also.
When the user segues from PreferencesViewController to ChooseServerViewController the prepare for segue code is:
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"toServerChoice"]) {
ChooseServerViewController *viewController = (ChooseServerViewController *)segue.destinationViewController;
viewController.locationDelegate = self;
}
}
When a cell choice is made in ChooseServerViewController I call:
[self locChoice];
Which is:
- (NSString *) locChoice {
NSLog(#"Cell Vale Loc choice %#",cellValue);
return cellValue;
}
The NSLog verifies the correct value is returned.
Now, as I think I understand it, the value of LocChoice in the delegate is now the value returned, no?
When the user goes back (NavController) the PreferencesViewController has:
-(void) viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
defaultLocation = [locationDelegate locChoice];
[self.tableView reloadData];
}
I was expecting the value of defaultLocation to now equal the value passed to locChoice. However when the table reloads the cell in question is still blank, implying what I exepct to happen isn't happening.
Any ideas?

If I followed your code properly, you do not need to adopt the mentioned protocol in your ChooseServerViewController, only PreferencesViewController.
The reasoning is you want to send data back to the previous view controller. Try:
#protocol defaultLocationChoice <NSObject>
- (void) locChoice:(NSString*)choice;
#end
Have your PreferencesViewController implement that method so it receives the selection. You will have to store that in an appropriate instance variable.
// in PreferencesViewController.m
-(void)locChoice:(NSString*)choice {
self.choice = choice; // this just my example
}
When the choice is made (in ChooseServerViewController) to send the choice back, call:
// this is in 'ChooseServerViewController.m' some where appropriate
[self.delegate locChoice:cellValue];
Your implementation is simply doing nothing with cell value (not even storing it, just logging it). When you return to PreferencesViewController, you will now have the selected value and that view controller can what it wants with it.
Protocols are somewhat analgous to interfaces in Java or C#, but more flexible.
Some more concepts about delegation.
Working with Protocols.
UPDATE:
The declaration for ChooseServerViewController should look like:
#import "FileWithProtocolDecalration.h"
#interface ChooseServerViewController
.
.
.
#property ( nonatomic,assign) id<defaultLocationChoice> delegate;
.
.
.
#end

I think you do have some misunderstanding there
protocol and delegates are something that is passed around. in other words somebody need to be receiver and somebody need to be the sender. in your case.
update your protocol to this
#protocol defaultLocationChoice <NSObject>
- (void)locChoice:(NSString *)updateString; // the method from delegate and implementer must be exact
#end
and set implement the protocol to ViewController as a receiver
#interface VCReceiver : UIViewController <defaultLocationChoice>
then later in VCReceiver
- (void)viewDidLoad {
ChooseServerViewController *vcSender = [[ChooseServerViewController alloc] init];
[vcSender setLocationDelegate:self]; // this is like saying. i have implemented method from protocol in this file (self)
}
- (void)locChoice:(NSString *)updateString {
// update the VCReceiver here
// or access vcSender value
// or use the updateString value
}
then in ChooseServerViewController locChoice: method (the one from your example) replace with this one and call [self updateChoice] instead:
- (void)updateChoice {
if ([self.locationDelegate respondsToSelector:#selector(locChoice:)]) {
[self.locationDelegate locChoice:aStringToUpdate]; // this will call VCReceiver locChoice
}
it does not have to return anything because it is actually calling the VCReceiver method to tell it that ChooseServerViewController got the value ready to be read.

Related

Use Realm data to fill the UITableView (table)?

My solution which doesn't work - I get data with realm store it as array and reuse this array in cellForRowAtIndexPath:.
The problem is I should get data in the background thread but fill the table in main thread.
Note: I have already read that if I get the realm data in current thread then I can use them in this thread only. Otherwise I should create ThreadSafeReference for each realm object I need and reuse it in main thread. But I can't understand how to do it - the example is written with such way that they create an object before dispatch_async and use it inside this object (like passing a variable into the code block).
In my case I have a separate array which I should store and reuse in cellForRowAtIndexPath (which is not code block) and called multiple times. I also can't call dispatch_async with a thread I need inside it because the cell may become invalid.
How to solve this issue? Should I cache Realm objects manually? I accept both Swift and Objective-C languages
The following code should work for you:
// ViewController.h
#import <UIKit/UIKit.h>
#import "MyObject.h" // subclass of RLMObject
#interface MyViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
#property (weak, nonatomic) IBOutlet UITableView *myTableView;
#property RLMResults<MyObject *> *objectsList;
#end
And the implementation:
// ViewController.m
#import "MyViewController.h"
#implementation MyViewController {
- (void)viewDidLoad {
_objectsList = [MyObject allObjects]; // optionally sort, query, etc.
}
- (void)viewDidAppear {
[super viewDidAppear];
// Do any other setup
}
#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return _objectsList.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// Setup the cell with the object's information. It's up to you how
// to do it. Register a custom subclass of UITableViewCell, for example.
MyObject *thisCellObject = [objectsList objectAtIndex:indexPath.row];
UITableViewCell *cell = [self.myTableView dequeueReusableCellWithIdentifier:#"customIdentifier"];
// Title should be a property on your MyObject class
cell.textLabel.text = thisCellObject.title;
}
#pragma mark - UITableViewDelegate
// Implement the Delegate methods as you want it...
}
No need to invoke the Realm Objects from other threads of using Dispatch. The only case you'll get those "incorrect thread" errors would be if you pass a reference from you view controller to other class, like a background networking client or something similar.
Anyway those cases are avoidable too. If your objects got an ID, let's say from an API, you pass the ID to the other class, maybe the background sync client, and from that client perform a query for the object, like [MyObject objectsWhere:#"objectID == %#", idString];. The object is being called from the background process that will use it and therefore it's not going to fail.

Issue with subclass and superclass using same named properties

This is something very fascinating I observed today. Maybe that's how Objective-C works but I didn't know about this. See the following code below:
// ATableViewController.h
#interface ATableViewController : UITableViewController
#end
// ATableViewController.m
#interface ATableViewController ()
#property (nonatomic) int volly;
#end
#implementation ATableViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.volly = 5;
}
#end
// BTableViewController.h
#interface BTableViewController : ATableViewController
#end
// BTableViewController.m
#interface BTableViewController ()
#property (nonatomic) int volly;
#end
#implementation BTableViewController
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"%d", self.volly); // returns 5
}
#end
I am not sure why the above is valid. I do understand that I passed a message 'volly' to the object 'self' which in turn probably looked at the value from the super class but shouldn't these be initialized? Some explanation would be of great help. Thanks.
EDIT: This is a big problem IMO though. Considering I don't know any of the private properties defined in the super class, my own set of values might end up being different.
For example, a developer may set a boolean flag hasAppeared in viewDidAppear:. This same value will be set for my subclass instance in viewDidAppear: after the [super viewDidAppear:] call. This will be before I actually get to set it myself.
Currently, the solution is I know exactly the variable used by the super class and I can avoid using the same value but I deem this to be a larger issue than it seems.
EDIT 2: The behavior is consistent with binaries (with only headers) as well as with frameworks where implementation is available.
I am answering this without reading all of the comments.
There is no issue here. Both AViewController (AVC) and BViewController (BVC) each have their own private property named volly.
You created an instance of BVC. It can't see the volly property from its parent class (because it is private), just its own.
Now the fun begins.
The viewDidLoad method from BVC is called. It in turn calls [super viewDidLoad]; which of course calls the viewDidLoad from the AVC class. That method, in turn, calls self.volly = 5;.
The confusion seems to be with this line. Remember, self.volly = 5; is really a call to:
[self setVolly:5];
Both AVC and BVC have the (synthesized) setVolly: method. Since self is a pointer to an instance of a BVC object, the call to [self setVolly:5]; results in a call to the setVolly: method in the BVC class despite being called from a method in the AVC class.
Here's the code with some annotations:
The 'BVC' class:
- (void)viewDidLoad
{
[super viewDidLoad]; // calls the method in `AVC`
NSLog(#"%d", self.volly); // returns 5
}
The 'AVC' class:
- (void)viewDidLoad
{
[super viewDidLoad]; // calls the UITableViewController method
// The following is really [self setVolly:5];
// Since "self" is a "BVC", the private "volly" property of
// the "BVC" class is actually set here.
// The private "volly" property of the "AVC" class will still be
// 0 after this call.
self.volly = 5;
}
In the end, the subclass is not using the private property of the parent class. The original premise in the question's title is incorrect.

Class Cluster as a Singleton?

SORRY FOR THE LENGTH OF THIS POST; IT IS MEANT TO DOCUMENT MY JOURNEY WITH THIS PROBLEM.
I have a question about a shared object in a Cocoa app that needs to change from time to time and how best to store it so that it's accessible from a few different places. Bear with me.
Class Implementation
The shared object is implemented as a Class Cluster (i.e., https://stackoverflow.com/a/2459385/327179) that looks like the following (note that Document is merely a class name; it is not necessarily indicative of what my actual class does):
In Document.h:
typedef enum {
DocumentTypeA,
DocumentTypeB
} DocumentType;
#interface Document : NSObject {}
- (Document *) initWithDocumentType:(NSUInteger)documentType;
- (void) methodA;
- (void) methodB;
#end
In Document.m:
#interface DocumentA : Document
- (void) methodA;
- (void) methodB;
#end
#interface DocumentB : Document
- (void) methodA;
- (void) methodB;
#end
#implementation Document
- (Document *)initWithDocumentType:(NSUInteger)documentType;
{
id instance = nil;
switch (documentType) {
case DocumentTypeA:
instance = [[DocumentA alloc] init];
break;
case DocumentTypeB:
instance = [[DocumentB alloc] init];
break;
default:
break;
}
return instance;
}
- (void) methodA
{
return nil;
}
- (void) methodB
{
return nil;
}
#end
#implementation DocumentA
- (void) methodA
{
// ...
}
- (void) methodB
{
// ...
}
#end
#implementation DocumentB
- (void) methodA
{
// ...
}
- (void) methodB
{
// ...
}
#end
How The User Interacts with a Document
Via a menu item, the user can switch between DocumentA and DocumentB at will.
What Happens When A "Switch" Occurs
When the user switches from, say, DocumentA to DocumentB, I need two things to happen:
My primary NSViewController (MainViewController) needs to be able to use the new object.
My AppDelegate needs to update an NSTextField that happens to be located in the content border of the main window. (FWIW, I can only seem to assign an outlet for the NSTextField in the AppDelegate)
The Question(s)
I've seen singletons mentioned quite a bit as a way to have a global reference without cluttering up one's AppDelegate (primarily here and here). That said, I've not seen much info on overwriting such a singleton (in our case, when a user switches from DocumentA to DocumentB [or vice versa], this global reference would need to hold the new object). I'm not an expert on design patterns, but I do remember hearing that singletons are not meant to be destroyed and recreated...
So, given all this, here are my questions:
How would you store my Class Cluster (such that MainViewController and AppDelegate can access it appropriately)?
Am I mixing concerns by having both MainViewController (who uses Document heavily) and AppDelegate (who manages the primary window [and thus, my NSTextField]) have knowledge of Document?
Feel free to let me know if I'm thinking about this problem incorrectly; I want this implementation to be as orthogonal and correct as possible.
Thanks!
Status Update #1
Thanks to advice from #JackyBoy, here's the route I've taken:
Document is the one that, upon "switching", "notifies" AppDelegate and MainViewController by passing them the newly created instance.
Both AppDelegate and MainViewController can update the Document object via the Singleton instance as necessary.
Here are my new files (dumbed down so that y'all can see the crux of the matter):
In Document.h:
#import <Foundation/Foundation.h>
#class AppDelegate;
#class MainViewController;
typedef enum {
DocumentTypeA,
DocumentTypeB
} DocumentType;
#interface Document : NSObject
#property (weak, nonatomic) MainViewController *mainViewControllerRef;
#property (weak, nonatomic) AppDelegate *appDelegateRef;
+ (Document *)sharedInstance;
- (id)initWithParser:(NSUInteger)parserType;
#end
In Document.m:
#import "AppDelegate.h"
#import "Document.h"
#import "MainViewController.h"
#interface DocumentA : Document
// ...
#end
#interface DocumentB : Document
// ...
#end
#implementation Document
#synthesize appDelegateRef;
#synthesize mainViewControllerRef;
+ (Document *)sharedInstance
{
static XParser *globalInstance;
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
// By default, I return a DocumentA object (for no particular reason).
globalInstance = [[self alloc] initWithDocumentType:DocumentA];
});
return globalInstance;
}
- (id)initWithDocumentType:(NSUInteger)documentType
{
Document *instance = nil;
switch (parserType) {
case DocumentTypeA:
instance = [[DocumentA alloc] init];
break;
case DocumentTypeB:
instance = [[DocumentB alloc] init];
break;
default:
break;
}
// QUESTION: Is this right? Do I have to store these references
// every time a new document type is initialized?
self.appDelegateRef = (AppDelegate *)[NSApp delegate];
self.mainViewControllerRef = self.appDelegateRef.mainViewController;
[self.appDelegateRef parserSwitchedWithParser:instance];
[self.mainViewControllerRef parserSwitchedWithParser:instance];
return instance;
}
#end
#implementation Xparser_NSXML
// ...
#end
#implementation DocumentA
// ...
#end
Should I be bothered by the fact that Document has knowledge of the existence of AppDelegate and MainViewController? Additionally, should I be bothered by the fact that when the Document object updates, it re-notifies both AppDelegate and MainViewController (even though one of those initiated the update)?
As always, I appreciate everyone's eyeballs on this as my quest for the ideal implementation continues. :)
Status Update #2
A comment from #Caleb helped me understand that an NSNotification-based setup would be a lot less unwieldy for this particular problem.
Thanks, all!
I don't see he need for a shared object here, much less a singleton. Do you really need to find the current Document at arbitrary times from many different objects? Seems more like you just have two objects (app delegate and view controller) that both need to know about the current Document. Notifications provide an easy way to manage that: whenever a switch happens, you can post a NSNotification that includes the new Document. Any objects that need to know about the current Document will have registered for the "document switch" notification, and when the notification arrives they can stash a pointer to the Document in an instance variable or property.
I do remember hearing that singletons are not meant to be destroyed
and recreated...
Well, you can have references inside of it, so you are not actually "destroying" the singleton, but the objects he points to. I tend to leave the App Delegate without application logic, so I normally put it somewhere else. In your case, since you need to access something from different places, it makes sense to have one. About the cluster, you can still have it, you just ask the singleton to access it and return the appropriate object like so:
Document *myDocument = [[MySingleton defaultManager] createObjectWithType:aType];
You gain some things out of this:
you can access your cluster from any place in your app
you decouple things, only one entity knows about your cluster.
Inside the Singleton you can have a reference to you AppDelegate and interact with it.
Inside the Singleton you can have a reference to the objects that are being used (Document A, Document B)
One more thing, I would advise putting the cluster access method as a class method (instead of an instance one).

performSelectorOnMainThread method not call

I have created a method that is running in new thread.
[NSThread detachNewThreadSelector:#selector(setmostpopularReq:) toTarget:self withObject:mostPopulerstring];
After completed this method i send all data to main thread.
[self performSelectorOnMainThread:#selector(getmostpopularResponse:) withObject:self waitUntilDone:YES];
But some time my main thread method not calling.
i used
dispatch_sync(dispatch_get_main_queue(),^{[self getmostpopularResponse:mostPopularList];});
But this is also have the same problem some time its calling method or some time not calling.
Please help me in this.
I would advise you to create a delegate with which you could notify the main thread after the
completion of the detached thread
Also another solution would be to create an NSOperation and NSOperationQueue instead of a new thread. There you can schedule what you want. For me looks easier, though it depends on you.
Here is a link to help you more with NSOperation
https://developer.apple.com/library/mac/#featuredarticles/ManagingConcurrency/_index.html
I will write this really quickly.
#protocol RespondDelegate
- (void)notifyWithRespond:(NSData *)data;
#end
#interface ContactWebServiceOperation:NSOperation
#property (nonatomic, assign) id delegate;
#end
#implementation ContactWebServiceOperation
#synthesize delegate;
// initialize here.
- (id)initWithDelegate:(id)delegate;
{
if ([self = [super init]) {
self.delegate = delegate;
}
return self;
}
- (void)main
{
if (self.isCancelled) return;
if (nil != delegate) {
// Do your work here...
work();
// When finished notify the delegate with the new data.
[delegate notifyWithRespond:your_data_here];
// Or
[delegate performSelectorOnMainThread:#selector(processImageForDownloadOperation:)
withObject:self waitUntilDone:YES];
}
}
#end
// Now on the view that you want to present the received results
// you have to do one thing.
// Let's say that your view is called View1
#interface View1 : UIViewController<RespondDelegate>
// Here put whatever you like.
#end
#implementation View1
// Put here all your code.
- (void)notifyWithRespond:(NSData *)data
{
// Here you will handle your new data and you will update your view.
}
#end
If I understand correct this should work.
Also, you can change the NSData to whatever you like, as long as you perform the appropriate conversions later.
If it doesn't work take a look on the link from Apple, maybe I have some typo or something.
But in general it looks solid.

Method signature for a Selector

I'm new to the Objective C business (Java developer most of the time) and am woking on my first killer app now. :-)
At the moment I am somehow confused about the usage of selectors as method arguments. They seem to be a little bit different than delegates in C# for example.
Given the following method signature
-(void)execute:(SEL)callback;
is there a way to enforce the signature for the selector passed to such a method?
The method is expecting a selector of a method with the following signature
-(void)foo:(NSData*)data;
But the SEL (type) is generic, so there is a good chance to pass a wrong selector to the
execute method. OK at least at runtime one would see a funny behavior... but I would like to see a compiler warning/error when this happens.
The quick answer is: no, there is no way to have the compiler enforce the method signature of a method selector that is provided via a SEL argument.
One of the strengths of Objective-C is that it is weakly-typed language, which allows for a lot more dynamic behaviour. Of course, this comes at the cost of compile-time type safety.
In order to do what (I think) you want, the best approach is to use delegates. Cocoa uses delegates to allow another class to implement "callback"-type methods. Here is how it might look:
FooController.h
#protocol FooControllerDelegate
#required:
- (void)handleData:(NSData *)data forFoo:(FooController *)foo;
#end
#interface FooController : NSObject
{
id <FooControllerDelegate> * delegate;
}
#property (assign) id <FooControllerDelegate> * delegate;
- (void)doStuff;
#end
FooController.m
#interface FooController (delegateCalls)
- (void)handleData:(NSData *)data;
#end
#implementation FooController
#synthesize delegate;
- (id)init
{
if ((self = [super init]) == nil) { return nil; }
delegate = nil;
...
return self;
}
- (void)doStuff
{
...
[self handleData:data];
}
- (void)handleData:(NSData *)data
{
if (delegate != nil)
{
[delegate handleData:data forFoo:self];
}
else
{
return;
// or throw an error
// or handle it yourself
}
}
#end
Using the #required keyword in your delegate protocol will prevent you from assigning a delegate to a FooController that does not implement the method exactly as described in the protocol. Attempting to provide a delegate that does not match the #required protocol method will result in a compiler error.
Here is how you would create a delegate class to work with the above code:
#interface MyFooHandler <FooControllerDelegate> : NSObject
{
}
- (void)handleData:(NSData *)data forFoo:(FooController *)foo;
#end
#implementation MyFooHandler
- (void)handleData:(NSData *)data forFoo:(FooController *)foo
{
// do something here
}
#end
And here is how you would use everything:
FooController * foo = [[FooController alloc] init];
MyFooHandler * fooHandler = [[MyFooHandler alloc] init];
...
[foo setDelegate:fooHandler]; // this would cause a compiler error if fooHandler
// did not implement the protocol properly
...
[foo doStuff]; // this will call the delegate method on fooHandler
...
[fooHandler release];
[foo release];
To directly answer your question, no, the SEL type allows any type of selector, not just ones with a specific signature.
You may want to consider passing an object instead of a SEL, and document that the passed object should respond to a particular message. For example:
- (void)execute:(id)object
{
// Do the execute stuff, then...
if ([object respondsToSelector:#selector(notifyOnExecute:)]) {
[object notifyOnExecute:self];
}
// You could handle the "else" case here, if desired
}
If you want to enforce the data handling, use isKindOfClass inside your selector. This works a lot like instanceof which you are familiar with in Java.