WatchKit thread issue between classes - objective-c

I have two classes named InterfaceController and LoadInterfaceController.
I'm calling InterfaceController's uiChange function from my LoadInterfaceController:
InterfaceController *interfaceController = [InterfaceController alloc];
//[interfaceController performSelectorOnMainThread:#selector(uiChange) withObject:nil waitUntilDone:true];
[interfaceController uiChange];
The function is called, but the UI in InterfaceController isn't modified.
- (void)uiChange {
NSLog(#"uiChange was called");
//... make changes to the UI ...
}
If the function is called from a function originating from InterfaceController class the UI is changed, respectively.
I have tried calling uiChange on the main thread (as explained here), but the UI isn't responding. How may I specify the thread used for InterfaceController's UI?

The same issue as here. Do not initialise controllers on your own, let Watch do it as a user flow happens.
I'd suggest adding into your architecture a Pub/Sub pattern. The NSNotificationCenter class is a good example that implements one. It allows parts of application to communicate between each other and it is used really often for controllers communication as well.
Here is a good example of communication between an AppDelegate and controller that I provided answering to another question recently. But if you really need I could adopt it for your example.

Related

Typhoon Storyboard Integration

I am using a StoryBoard in my application. When I first started integrating Typhoon, I listed the Assemblies in the plist like so:
<key>TyphoonInitialAssemblies</key>
<array>
<string>ApplicationAssembly</string>
<string>CoreComponents</string>
</array>
This worked fine as I was injecting into the AppDelegate.
Now, if I need to inject into the various view controllers, it appears I have to remove the UILaunchStoryboardName and UIMainStoryboardFile from the application plist file, and use a TyphoonStoryboard like so:
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSString *storyboardName = ...
TyphoonComponentFactory *factory = ...
TyphoonStoryboard *storyboard = [TyphoonStoryboard
storyboardWithName:storyboardName factory:factory bundle:nil];
self.window = ...
self.window.rootViewController = [storyboard instantiateInitialViewController];
[self.window makeKeyAndVisible];
return YES;
}
However, I'm confused where I obtain the TyphoonComponentFactory. Since I already list the assemblies in the plist, can I somehow use that?
it appears I have to remove the UILaunchStoryboardName and UIMainStoryboardFile from the application plist file, and use a TyphoonStoryboard like so
Incorrect. You can combine UIMainStoryboardFile (UILaunchStoryboardName) and TyphoonInitialAssemblies keys in your info.plist file.
In that case, created storyboard will be TyphoonStoryboard and has typhoon factory (created with specified in plist assemblies).
You can use storyboards exactly as you'd normally use them, with the added benefit that dependencies will also be injected, according to the definitions in your one ore more TyphoonAssembly classes.
As Aleksey says in his answer, as long as plist integration is used, along with the usual UILaunchStoryboardName and UIMainStoryboardFile, then Typhoon will ensure that any Storyboard is a TyphoonStoryboard. Use exactly as with a normal storyboard, with the added benefit that dependencies will be injected according to the definitions in your TyphoonAssembly classes.
The TyphoonComponentFactory will be retained by the storyboard and so will persist throughout the lifecycle of your app.
Outside of Storyboards: (ie MacOS apps, utilities, etc)
The TyphoonComopnentFactory is indeed designed to be retained throughout the full life-cycle of your app. (Although you could do something else if you wished).
Key concept:
You can use the TyphoonComponentFactory as is.
Also, any of your assembly interfaces can pose in front of the TyphoonComponentFactory. At build-time an assembly returns definitions. At run-time it returns built components.
There are two ways to retain the TyphoonComponentFactory when proceeding from one object-graph to another. We call this making of your components 'Typhoon aware'.
Approach 1: Inject the assembly:
- (MyAppDelegate *)appDelegate
{
return [TyphoonDefinition withClass:[MyAppDelegate class]
configuration:^(TyphoonDefinition *definition)
{
//Other injections . . .
[definition injectProperty:#selector(factory) with:self];
}];
}
The above example injects the TyphoonComponentFactory into a property called factory.
When you inject the assembly it can be used as a TyphoonComponentFactory.
It can also be used as any of your assembly types. For example, you could declare a property components of type CoreCompopnents and inject the assembly as that.
More info on this feature can be found in the User Guide here.
Approach 2: Use callback hook:
Another way of making a component 'Typhoon aware' is to use Typhoon's callback hooks. by overriding NSObject category methods:
typhoonSetFactory:(id)thefactory
As with the other approach above, the factory can be used as a TyphoonComponentFactory or any of your assembly interfaces my pose in front, both of the following are fine:
typohoonSetFactory:(TyphoonComponentFactory*)factory
{
//Do something with factory
}
typhoonSetFactory:(ApplicationAssembly*)assembly
{
//Do something with assembly
}
Of the two approaches, use the one that suits you best. We recommend the former, as it 'non-invasive' meaning your own classes don't directly call any Typhoon APIs. If you ever wished to migrate away from Typhoon, you would simply provide an alternative implementation of the assembly.
Proceeding from one object graph to another:
Once a component is 'Typhoon aware' using either of the above methods, we can use this to proceed from one object graph to another.
The default scope for Typhoon is TyphoonScopeObjectGraph, meaning you can load a view controller, including any delegates and circular references. Upon completion, it will be discarded from memory.
Meanwhile any components of TyphoonScopeSingleton (or TyphoonScopeWeakSingleton) will be retained.
More information on this feature is in the User Guide here.
Summary:
The assembly follows normal Objective-C/Swift memory rules. So as long as its being used by at least one of your classes, it will continue to persist. Using the process of 'proceeding from one object graph to another' described above means that it will persist throughout the life-cycle of your app.
stackoverflow.com/questions/26492175/typhoon-storyboard-integration

How to pass self to an object class and get called when it's done?

I currently have a UIViewController and a NSObject class.
What i want to do is to tell the NSObject class to perform an action and then tell the UIViewController when it has finished it's action.
I'm calling the object to perform it's action like so:
[fooObject performActionWithDelegate:self];
The performActionWithDelegate function basically only takes the UIViewcontroller's delegate to perform a callback.
-(void)performActionWithDelegate:(id)d{
// bar is declared in the fooObject header file
// id bar;
[bar setDelegate:d];
[bar performCallback];
}
Where performCallback is a simple NSLog()-statement in the UIViewController:
-(void)performCallback{
NSLog(#"Successfully performed a callback");
{
Now, i'd like this to work. My first guess is that this is not the best approach to this problem.
The full scope of the problem is that the fooObject is supposed to perform a httppost to a webservice to update one of it's properties and then inform the uiviewcontroller if the operation was successful or not.
How do i achieve this?
Any tips and/or pointers will be highly appreciated!
Thanks in advance.
Edit:
The actual problem is that the fooObject is not performing the callback.
Its not clear exactly what you are trying to accomplish. What you are doing seems related to two different design patterns:
Delegate
Asynchronous callback
Delegate: You would use a delegate if there is some reason to separate out some of the functionality of your UIViewController into another object. Instead of the UIViewController doing something it asks another object to do it. This is commonly used for code reuse so you can have the same UIViewController serve in different cases and just change the delegate to change some of its behavior.
Asynchronous callback: This allows an operation to occur in the background while you are doing other things and then be notified by calling a method of your object when the operation completes. You can do this without involving other objects.
In your case, why do you want to perform an HTTP post to a web service outside of our UIViewController? Do you just want to separate the network code from UI code? In this case, you don't really need a delegate, just call the method on the other object from your UIViewController and when it returns, its done. It can pass back any result you need in other parameters. Returning values by setting properties on the calling object is not generally a very good design. Even if you do this the UIViewController isn't really a "delegate".
On the other hand if you are concerned about blocking the main thread while the HTTP post is in process then you will want to use something like asynchronous callback. The easiest way to do this is to use Grand Central Dispatch. Conceptually you could do something like this:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self doLongHTTPPost];
dispatch_async(dispatch_get_main_queue(), ^{ [self longHTTPPostDone]; });
});
This will call doLongHTTPPost in the background and then at some later time after it is complete it will call longHTTPPostDone on the main thread where it is safe to take UI actions.

How does one implement an event based state machine where the events are self generated?

Is there a recommended way of implementing a series of activities such that the app remains responsive but the activities aren't all chained together in a nested manner and without using a thread.
Let me try and explain - suppose I have a model class which uses a downloader class to download a zip file, then when its downloaded the model unzips the file, then does something with the unzipped files.
Now if the downloader class informs the model class the download is ready via a delegate like this:
In the downloader class :
- (void) connectionDidFinishLoading:(NSURLConnection *)connection {
// ...
[self.delegate zipFileDownloadingCompleted];
}
In the model class :
- (void) zipFileDownloadingCompleted {
[self unzipFile];
[self doSomethingElseWithFile];
[self doSomeOtherStuff];
}
But if unZipFile and doSomethingElseWithFile and doSomeOtherStuff could be lengthy activities which use an asynchronous API then maybe the model class will split these up and only call doSomethingElseWithFile once a delegate on unzipFile has been called, and only call doSomeOtherStuff once a delegate has been called on doSomethingElseWithFile and so on.
But is this a valid approach, seems to me everything is chained together and its still synchronous.
How could unZipFile and doSomethingElseWithFile and doSomeOtherStuff be broken up into separate chunks of activity? Is it possible for the app to make itself jump out of the run loop at the end of one activity and then jump back in to do the next activity?
If you're familiar with Brew then what I mean by this is perform one activity during one run through a HandleEvent() invocation, then self-schudule an event so that HandleEvent() will get called again to process the next activity and so on - so the app remains responsive at all time.
I would like to avoid threads if possible, I think event based coding is less complex and less error prone than threads.
I don't know if I explained that very well, hopefully you get the gist.
One approach is to use performSelectorInBackground:withObject to execute long-running tasks asynchronously. You could replace your delegate's zipFileDownloadCompleted as follows:
- (void) zipFileDownloadCompleted {
[self performSelectorInBackground:#selector(processAsync) withObject:nil];
}
- (void) processAsync {
if (!interrupt) {
[self unzipFile];
[self doSomethingElseWithFile];
[self doSomeOtherStuff];
}
}
Then in each long-running sub-task:
- (void) unzipFile {
if (!interrupt) {
...
}
}
I know you want to avoid threads, but this is about as easy as they get.
You may decide to put callbacks in those three methods to alert you to error conditions; you'd beef up processAsync with checks before initiating each step to fail cleanly, and so on. See the interrupt stuff in the edited examples (you'd use something more robust, manageable and safe than a global of course.)
You might be looking for -[NSRunLoop performSelector:target:argument:order:modes:] (apple docs). I would check out this SO Q&A for more, specifically Brad Larson, he knows his stuff.

Core data delegate saving pattern

I am using CoreData in iOS.
I have a modal AddViewController, with a RootViewController as the delegate.
Should I do the saving of the managed object context in the root controller, or in the actual modal controller itself?
I am seeing examples of passing the data back to the rootViewController, but can't see how this will work with data validation failures, or more complex scenarios that need the managed object context.
// AddViewController.m
- (void)save
{
[[self delegate] controller:(id)controller didFinishWithSave:(BOOL)save withName(NSString *)name;
}
// RootViewController.m
- (void)controller:(id)controller didFinishWithSave:(BOOL)save
{
if (save)
{
// save context
}
[self dismissModalViewControllerAnimated:YES];
}
As at the moment I am dismissing the modal using the delegate protocol.
Any advice on the best practices?
Thanks
I know this is a little late, but for others who come across this, I'd add a little more to Levend's answer.
Yes, you should have a separate manager class to handle the operations (possibly the class itself).
I would think that if your modal needed to handle validations, before calling on the delegate, it would validate the object. If it had an error, you could handle it right there. If it passed validations, then you could pass the valid object to the delegate. Thus the delegate can make the assumption that any object that is getting passed to it is a valid one.
As to which class you should save it, I think that is just a preference thing. But I would suggest you have a save method in the core data model itself.
Something I came across recently is the mogenerator which is supposed to help with managing CoreData classes. I haven't tired it yet, but it sounds good.
From an architecture point of view, you should create a separate manager class responsible for core data operations. From technical point of view, it isnt matter where you save(root, or modal VC) as long as you do it on the same thread where the data origins.
With MVC in mind I would let the M(odel) perform saving of the context as well as fetching data from it.

How to refer to the calling class in Objective-C

Can you refer to the sender of a message without passing the sender as a parameter?
This is simplified code for the sake of discussion:
// mainTableViewController.m
[dataModel loadData]; //Table is requesting data based on user input
// dataModel.m
-(void) loadData{
// I want to store the sender for later reference
sendingTableViewController = ???? ;
}
- (void) connectionDidFinishLoading:(NSURLConnection *)connection {
// Web data is loaded. Ask the sending tableViewController to
// reload it's data.
[sendingTableViewController.tableView reloadData];
}
I'm still getting used to how to refer to methods and properties that are the responsibility of another object. I want to send a message to dataModel to load some data using NSURLConnection. But I don't just want to return the data because I don't want to sit around waiting for the data to load. I want to send a message to the mainTableViewController once connectionDidFinishLoading is called.
Since the loadData method may be called from any number of tableViewControllers I can't just say [mainTableViewController reloadData].
Follow-Up Question
Great Information! I love the no-judgement nature of StackOverflow.
So the mainTableViewController would be the Delegate of the dataModel?
Would it be correct to say that the dataModel class defines the informal protocol?
I currently instantiate my dataModel class from within my mainTableViewController. So I could change my code like this:
// mainTableViewController.m
dataModel *myDataModel = [[dataModel alloc] initWithDelegate:self ];
// Does this method need to be defined in the mainTableViewController header file
// since I will already have defined it in the dataModel header file?
-(void) dataDidFinishLoading {
[self.tableView reloadData];
}
// dataModel.m
-(id) initWithDelegate:(id)aDelegate{
self.delegate = aDelegate;
}
-(void) connectionDidFinishLoading:(NSURLConnection *)connection {
[self.delegate dataDidFinishLoading];
}
Is it bad that my TableViewController is instantiating my dataModel, cause then my dataModel is owned by the TableViewController? Should I really instantiate the dataModel from the AppDelegate instead?
Thank You!
I daresay this isn't the correct way to think about the problem. Architecturally, by giving the data model knowledge of the table view controller, you are coupling your model layer to your controller layer. Violating separation of concerns is a bad thing.
In Cocoa, the use of delegate objects is used all over the place. A delegate object is an object that implements a particular protocol with callback methods that can be called when things or events (such as data loading from a remote location, in your case) occur. I recommend that you create a delegate property in your data model, have an interface that mainTableViewController (or any other class, really) implements, and assign that class as the delegate. Then, when the data is finished loading, call the appropriate method on self.delegate. In that callback method, you could then call [tableView reloadData].
Again, you do not want your data model to be coupled (meaning aware of) the existence of your controller classes.
Edit
I just re-read the last part of your question, about having multiple table controllers needing to listen for notification of the data being finished loading. For that, I suggest you use the Observer pattern in Cocoa by using NSNotificationCenter. You use use the notification center in the data model to send notifications to observers (you don't care who is observing; the notification center handles those details) and you'd also use it in your table controllers to subscribe to the notification. Delegates are a nice, simple solution if you only need one object to be directly called when something happens. Notifications are more complex and have more overhead, but give you the flexibility to have an arbitrary number of objects "listening" for a notification to be posted.
Follow-Up Response
A class doesn't define an informal protocol; the developer does. You could also define a formal protocol in a separate .h file and have the controller implement it if you want an enforceable contract. With a formal protocol, you can also use #optional on methods that don't have to be implemented by a class conforming to the protocol.
It is also not at all bad to instantiate the data model from within the table view controller. In fact, this is one very correct way to do it. Since the data model exists to encapsulate data that (presumably) a controller will want to display later, you can think of the controller as owning the data model. You may even consider making an instance variable (and perhaps a property, too) to store your data model. Besides that, your rewritten code looks good to me!
Do you mean the keyword self?
-(void)canHazCheeseburger:(BOOL)canHaz
{
if (canHaz) {
self.cheeseBurger = [[[CheeseBurger alloc] init] autorelease];
[cheeseBurger onNomNom];
}
}