Transfer object from one application to another - objective-c

Is there a way to transfer object from one application to another? I mean something like that:
//FirstApp:
- (void)someFunction{
myClass *myObj = [[myClass alloc] init]
//do some work...
[self runSecondAppWithObj:myObj];
}
//SecondApp:
int main (int argc, const char * argv[])
{
#autoreleasepool {
myClass *obj = //get obj from firstApp
//do some another work...
}
return 0;
}
myClass not so simple, what is why I can't transfer all info with NSString -> char. Also I need exactly the first object in second app, and not its duplicate.
I imagine it like:
first app launches second app, after that first app talk to second: "Hey, #adr is the address to variable(pointer), go and take it". After, second app take variable(pointer) with it's address. But i don't know how to make it.

There are two options that immediately come to my mind for doing this (I would recommend implementing the first option):
Make myClass serializable: The basic idea here is that you implement the NSCoding protocol and then use NSKeyedArchiver for serializing it into an NSDictionary. The dictionary can then easily be converted to an interchangeable format, e.g. a plist (XML). You would then pass the XML text to your second application and deserialize it there using NSDictionary and NSKeyedUnarchiver. You can find good guides and examples about archiving and serialization in Cocoa in Apple's developer documentation.
Pass the object using some inter process communication mechanism: This is a bit more complex and I would rather recommend it for apps that talk to each other continuously – not for just passing an object to another app on launch. One way to do this is using distributed objects. This enables you to share objects between processes or even between different physical machines as if they were local (with some limitations.) For example to share the object in your first app you might do:
NSConnection *connection = [[NSConnection connectionWithReceivePort:[NSPort port]] sendPort:nil];
[connection setRootObject:theObject];
[connection registerName:#"com.example.whatever"];
And in the second app you would then call:
id theObject = (id)[NSConnection rootProxyForConnectionWithRegisteredName:#"com.example.whatever" host:nil];
[theObject someMethod];

Related

Store Objective-C classes in array and use them

Say I have two classes, BulbDevice and FanDevice, both are subclasses of Device and has a method signature like this:
+ (BOOL)isMyId:(NSInteger)someId;
If I wanted to create a class I could test it out:
if ([BulbDevice isMyId:someId]) {
Device *dev = [BulbDevice alloc] initWithId:someId];
}
But what I really want is to create a factory method inside a factory class, with minimum fuss when new device are added:
+ (Device)createDevice:(NSInteger)someId {
// say I have an array registered
NSArray *arr = #[[BulbDevice class], [FanDevice class]];
// Loop through it.
Device *device;
for (Class *c in arr) {
// The idea is kind of like this but I'm not sure how to make it work
if ([c isMyId]) {
device = [[c alloc] init];
}
}
}
The idea is that I only need to update arr in the factory method. So I think it is good to have something like this. But I am not sure how to make it work.
EDIT:
I took out the asterisk, but it won't work:
for (Class c in arr) {
// Now I want to access the isMyId which is a static method,
// but I how do I cast to that class? I mean not an object of the class, but to that class itself.
if ([(Device)c isMyId:]) {
}
}
But I still need a way to access that class method. Error says Used type 'Device' where arithmetic or pointer type is required, and even if it works, I want to access class method, not sending message to an object.
Or shall I store NSString in the array instead? But it is hard to find way to access the class method as well.
If I understand correctly what you are trying to achieve, then your approach seems to be correct.
There is only one thing that needs to be fixed:
for (Class c in arr)
c variable is not a pointer - the asterisk should be removed. Your code works.
The Class type is not an NSObject type, and although it is a bit special it is object-like or object-equivalent, so you are able to send it messages and store it in collections like you're doing.
You don't use the asterisk as #MaxPevsner says, because Class isn't used as a normal pointer-to-object. Think of Class as a special type like id which also doesn't get the * when you use it to reference an object.

Objective C Convenience Method Use

I am tring to understand convenience methods.
IF I have a sqlite database containing store details and am returning these store details in a FMResultSet. I am thinking that to create an array of these store details as Store objects, that the best way would be create an object of type Store in one go in a convenience method and add to array.
The Class I have created is as below with convenience method
#interface StoreDetails : NSObject
#property (nonatomic, strong) NSString *storeName;
etc etc etc
+ (instancetype)storeWithStoreName:(NSString *)storeName
TelephoneNumber:(NSString *)
telephoneNumber: etc .......
My ResultSet loop would be as below?
NSMutableArray *Stores = [[NSMutableArray alloc] init];
while ([rs next]) {
Store *store =
[Store storeDetailsWithStoreName:[rs stringForColumn:#"storename"]
telephoneNumber:[rs stringForColumn:#"TelephoneNo"]];
[Stores addObject:store];
}
Is my thinking correct as above is is it better to go as below.
NSMutableArray *Stores = [[NSMutableArray alloc] init];
while ([rs next]) {
Store *store = [Store alloc] init];
store.storeName = [rs stringForColumn:#"storename"];
store.telephoneNumber = [rs stringForColumn:#"TelephoneNo"];
[Stores addObject:store];
}
All I am trying trying to understand is why you would use one over the other in noob speak, thankyou.
I think you have a good approach: initializing your Store object in a method of the Store class.
The storeDetailsWithStoreName:... method you have defined is a good example of what Apple calls a factory method (assuming you aren't doing anything weird in its implementation). It's a quite common pattern; Foundation has all sorts of examples: arrayWithCapacity:, numberWithInt:, etc.
With ARC, the simplest examples of these factory methods are nearly identical to a corresponding alloc/init expression, since the developer no longer has to think about autoreleasing objects. But there are still plenty of uses for factory methods, e.g. special instantiation patterns such as singleton or flyweight, including a small amount of common conversion or formatting code for convenience, implementing class clusters, etc. And there's the simple convenience of not having an extra set of brackets and less indentation.
The instancetype keyword is a good choice. This allows you to send the same message to a subclass of Store, with the expectation that the method will instantiate an object of the subclass using the same init method, like this:
+ (instancetype)storeWithStoreName:(NSString *)storeName
telephoneNumber:(NSString *)
...
{
return [[self alloc] initWithStoreName:...];
}
In the code above, as it's a class method, the self in [self alloc] is the Class object (either Store or a subclass of Store) rather than a specific instance of Store. This is what allows creating an instance of the correct class at runtime, depending on whether you call [Store storeWithStoreName:...] or [MoreSpecificStoreSubType storeWithStoreName:...].
The alternative to a factory method, or compliment to it really, is to declare a custom init method in your Store class:
- (id)initWithStoreName:(NSString *)storeName
telephoneNumber:(NSString *)telephoneNumber ...
…and use that directly inside your loop, instead of a factory method. Again, with ARC, not much of a difference between the two unless there's extra work you want to do in the factory method. You can have multiple variants of the init method; the standard practice is for all of them to call the most detailed init method, which is called the designated initializer.
I would recommend taking the time to read the Apple documentation pages on standards for class design (I linked to some of these pages above). Since there are a lot of this is based more on convention rather than language design restrictions, it's important to know all about the patterns and best practices for good design and proper behavior of special methods.

Macro that logs the actual types of method arguments

Let's say this is my init method
- (id)initWithClient:(id <Client>)client
andDataStorage:(DataStorage *)storage
{
if (self = [super init])
{
self.client = client;
self.storage = storage;
}
return self;
}
Then I want to write a macro that somehow logs the parameters passed to a method, by wrapping the parameter with a defined macro. Is this possible in any way?
The problem is at runtime it's not possible to find out the type of a parameter passed to a method. So I'm trying to find a hack around it, and do it at compile time.
// somehow achieve this, and log the value inside the marco
#define INJECT(x) NSLog(#"%#", x)
- (id)initWithClient:(INJECT(id <Client>))client
andDataStorage:(INJECT(DataStorage *))storage
{
}
expected log in console:
id <Client>
DataStorage *
At the risk of running into what appear to be crossed wires in the comments: you can get the parameter types passed to a method at runtime.
E.g.
NSMethodSignature *signature =
[class methodSignatureForSelector:#selector(someSelector:)];
for(int argument = 2; argument < signature.numberOfArguments; argument++)
{
const char *argumentType = [signature getArgumentTypeAtIndex:argument];
// this is where it gets a bit messy...
if(!strcmp(argumentType, #encode(int))) NSLog(#"an integer");
if(!strcmp(argumentType, #encode(float))) NSLog(#"a float");
// ... etc, etc, etc ...
}
For any passed objects, use [object class] since all objects look the same at the runtime level — think of e.g. NSArray -addObject:; the runtime knows an object type will be passed in but it could be any object type.
See Apple's documentation on Type Encodings for information on what's going on there with those #encodes.
Whilst not an answer to the question as such. I would not recommend doing what you are asking about. I've seen far to much code where people have logged every single method call and argument (horribly over-complicated Java Enterprise stuff). The result has always been obscenely large logs that tell you next to nothing because of the amount of work it takes to find what you are after.
My recommendation would be that logging is important, but you should do targeted logging that clearing shows the state of relevant data at specific points which are important to understanding the flow.
Like others, I'm not sure what you are really after, or whether it is a good idea/design etc. But I wonder whether you are approaching the problem the wrong way. So let's take a look and maybe it will help you. From what I see you:
Want to find some way of obtaining the declared types of method parameters, in the form of strings, at runtime.
You are trying to tackle this by adding macros to the source. This tells me that you are not trying to do this for methods in a binary library that you are dynamically loading, but to methods in source you are compiling and are prepared to modify to achieve your goal.
Looked at that way, what is the problem? If you are prepared to add macros to your source why not simply add data declarations that contain the information you want - a mapping from a selector to an order list of parameter types as strings.
Is the issue that you want to extract the information in some automated way and were intending adding your macros by some automated process?
You can arrange for an Xcode project to run a source file through some other program by changing the file extension. Apple provide examples of using this to pre-process strings files - the files are fed through a Ruby script which produces a strings file which Xcode then handles as usual. Will that address your needs? Could you write a script/application (doesn't need to be in Ruby) which could add the information you need "on the fly" - take source in, produce modified source out which Xcode then compiles as usual? Note that the Clang compiler itself is designed to be called as a library so you can even use it to help you parse your source to extract the information you are after.
If none of those approaches suit consider that the debugger knows the correct types at runtime, and it gets those from the symbol information generated for it. There are library functions provided to help reader debugger information, so you should be able to write code which uses the same information the debugger does.
Hope those ideas help you, though I'm still not clear what you are trying or whether it makes sense!
due to objC being dynamically typed, all classes have the type id. The information about the declared types is erased. They are merely hints for the developer and to enable the compiler to do some type checking (again purely for the dev's benefit)
So while #encode works for 'primates' and structs and stuff, for classes all is equal... as there are not really object types for runtime
'Solution': Store the class names of method argumentsin a map manually and then COMBINE that info with #encode;s info to log the stuff.
working sample:
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
NSDictionary *DDParamsMap(void);
NSDictionary *DDParamsMap() {
static NSDictionary *dict = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
//TODO
//add all methods that are have objc classes passed
//add the classes or NSNull
dict = #{#"Test_initWithArray:data:number:": #[NSArray.class, NSData.class, NSNull.null]};
});
return dict;
}
void DDLogParamsOf(Class class, SEL sel);
void DDLogParamsOf(Class class, SEL sel) {
//
//try internal lookup first (so we get class names
//
NSString *className = #(class_getName(class));
NSString *methodName = NSStringFromSelector(sel);
NSString *key = [NSString stringWithFormat:#"%#_%#", className, methodName];
NSArray *types = DDParamsMap()[key];
//
// loop
//
NSMethodSignature *signature = [class instanceMethodSignatureForSelector:sel];
if(!signature) {
signature = [class methodSignatureForSelector:sel];
}
//if the array doesnt have the right number of values, screw it!
if(types.count != signature.numberOfArguments - 2) {
types = nil;
}
for(int argument = 2; argument < signature.numberOfArguments; argument++) {
id type = types[argument - 2];
if(type && ![type isKindOfClass:[NSNull class]]) {
NSLog(#"class is %#", type);
}
else {
const char *argumentType = [signature getArgumentTypeAtIndex:argument];
// this is where it gets a bit messy...
if(!strcmp(argumentType, #encode(int))) NSLog(#"an integer");
if(!strcmp(argumentType, #encode(float))) NSLog(#"a float");
if(!strcmp(argumentType, #encode(id))) NSLog(#"it is a class");
// ... etc, etc, etc ...
}
}
}
#define LogParams() DDLogParamsOf(self.class, _cmd);
#interface Test : NSObject
+ (void)testMethofWithFloat:(float)f;
- (id)initWithArray:(NSArray*)a
data:(NSData*)d
number:(int)i;
#end
#implementation Test
+ (void)testMethofWithFloat:(float)f {
LogParams();
}
- (id)initWithArray:(NSArray*)a
data:(NSData*)d
number:(int)i
{
LogParams();
return nil;
}
#end
int main(int argc, char *argv[]) {
#autoreleasepool {
[Test testMethofWithFloat:3.0f];
Test *t = [[Test alloc] initWithArray:#[] data:[NSMutableData data] number:1];
t = nil;
}
}

What's the way to communicate a set of Core Data objects stored in the background to the main thread?

Part of my iOS project polls a server for sets of objects, then converts and saves them to Core Data, to then update the UI with the results. The server tasks happens in a collection of NSOperation classes I call 'services' that operate in the background. If NSManagedObject and its ~Context were thread safe, I would have had the services call delegate methods on the main thread like this one:
- (void)service:(NSOperation *)service retrievedObjects:(NSArray *)objects;
Of course you can't pass around NSManagedObjects like this, so this delegate method is doomed. As far as I can see there are two solutions to get to the objects from the main thread. But I like neither of them, so I was hoping the great StackOverflow community could help me come up with a third.
I could perform an NSFetchRequest on the main thread to pull in the newly added or modified objects. The problem is that the Core Data store contains many more of these objects, so I have to add quite some verbosity to communicate the right set of objects. One way would be to add a property to the object like batchID, which I could then pass back to the delegate so it would know what to fetch. But adding data to the store to fix my concurrency limitations feels wrong.
I could also collect the newly added objects' objectID properties, put them in a list and send that list to the delegate method. The unfortunate thing though is that I have to populate the list after I save the context, which means I have to loop over the objects twice in the background before I have the correct list (first time is when parsing the server response). Then I still only have a list of objectIDs, which I have to individually reel in with existingObjectWithID:error: from the NSManagedObjectContext on the main thread. This just seems so cumbersome.
What piece of information am I missing? What's the third solution to bring a set of NSManagedObjects from a background thread to the main thread, without losing thread confinement?
epologee,
While you obviously have a solution you are happy with, let me suggest that you lose some valuable information, whether items are updated, deleted or inserted, with your mechanism. In my code, I just migrate the userInfo dictionary to the new MOC. Here is a general purpose routine to do so:
// Migrate a userInfo dictionary as defined by NSManagedObjectContextDidSaveNotification
// to the receiver context.
- (NSDictionary *) migrateUserInfo: (NSDictionary *) userInfo {
NSMutableDictionary *ui = [NSMutableDictionary dictionaryWithCapacity: userInfo.count];
NSSet * sourceSet = nil;
NSMutableSet *migratedSet = nil;
for (NSString *key in [userInfo allKeys]) {
sourceSet = [userInfo valueForKey: key];
migratedSet = [NSMutableSet setWithCapacity: sourceSet.count];
for (NSManagedObject *mo in sourceSet) {
[migratedSet addObject: [self.moc objectWithID: mo.objectID]];
}
[ui setValue: migratedSet forKey: key];
}
return ui;
} // -migrateUserInfo:
The above routine assumes it is a method of a class which has an #property NSManagedObjectContext *moc.
I hope you find the above useful.
Andrew
There's a section of the Core Data Programming Guide that addresses Concurrency with Core Data. In a nutshell, each thread should have its own managed object context and then use notifications to synchronize the contexts.
After a little experimentation, I decided to go for a slight alteration to my proposed method number 2. While performing background changes on the context, keep a score of the objects you want to delegate back to the main thread, say in an NSMutableArray *objectsOfInterest. We eventually want to get to the objectID keys of all the objects in this array, but because the objectID value changes when you save a context, we first have to perform that [context save:&error]. Right after the save, use the arrayFromObjectsAtKey: method from the NSArray category below to generate a list of objectID instances, like so:
NSArray *objectIDs = [objectsOfInterest arrayFromObjectsAtKey:#"objectID"];
That array you can pass back safely to the main thread via the delegate (do make sure your main thread context is updated with mergeChangesFromContextDidSaveNotification by listening to the NSManagedObjectContextDidSaveNotification). When you're ready to reel in the objects of the background operation, use the existingObjectsWithIDs:error: method from the category below to turn the array of objectID's back into a list of working NSManagedObjects.
Any suggestions to improve the conciseness or performance of these methods is appreciated.
#implementation NSArray (Concurrency)
- (NSArray *)arrayFromObjectsAtKey:(NSString *)key {
NSMutableArray *objectsAtKey = [NSMutableArray array];
for (id value in self) {
[objectsAtKey addObject:[value valueForKey:key]];
}
return objectsAtKey;
}
#end
#implementation NSManagedObjectContext (Concurrency)
- (NSArray *)existingObjectsWithIDs:(NSArray *)objectIDs error:(NSError **)error {
NSMutableArray *entities = [NSMutableArray array];
#try {
for (NSManagedObjectID *objectID in objectIDs) {
// existingObjectWithID might return nil if it can't find the objectID, but if you're not prepared for this,
// don't use this method but write your own.
[entities addObject:[self existingObjectWithID:objectID error:error]];
}
}
#catch (NSException *exception) {
return nil;
}
return entities;
}
#end

Cocoa without Interface Builder, initialize an instance of app controller?

I don't plan to write applications without IB, I'm just in the process of trying to learn more about programming.
How can I get a single instance of my AppController class at startup? (It's normally loaded from the nib.) And can you clear up the use of +initialize and -init? If I understand, +initialize is called on all classes at startup. How can I use this to create an instance of my AppController with instance variables that make up my interface?
Hope that makes sense, and thanks for any help.
+initalize is sent to a class the first time it or one of its subclasses receives a message for the first time. So, when you do:
instance = [[[YourClass alloc] init] autorelease];
That alloc message triggers initialize.
If you do the same thing with a subclass:
instance = [[[SubclassOfYourClass alloc] init] autorelease];
That alloc message will trigger +[YourClass initialize] the same way the other one did (prior to also triggering +[SubclassOfYourClass initialize]. But only one of these will do it—each class's initialize never gets called more than once. (Unless you call it yourself with [super initialize] or [SomeClass initialize]—so don't do that, because the method won't be expecting it.)
-init, on the other hand, initializes a new instance. In the expression [[YourClass alloc] init], you are personally sending the message directly to the instance. You may also call it indirectly, through another initializer ([[YourClass alloc] initWithSomethingElse:bar]) or a convenience factory ([YourClass instance]).
Unlike initialize, you should always send init (or another initializer, if appropriate) to your superclass. Most init methods look roughly like this:
- (id) init {
if ((self = [super init])) {
framistan = [[Framistan alloc] init];
}
return self;
}
Details differ (this method or the superclass's or both may take arguments, and some people prefer self = [super init] on its own line, and Wil Shipley doesn't assign to self at all), but the basic idea is the same: call [super init[WithSomething:…]], make sure it didn't return nil, set up the instance if it didn't, and return whatever the superclass returned.
This implies that you can return nil from init, and indeed you can. If you do this, you should [self release], so that you don't leak the failed object. (For detecting invalid argument values, an alternative is NSParameterAssert, which throws an exception if the assertion fails. The relative merits of each are beyond the scope of this question.)
How can I use this to create an instance of my AppController with instance variables that make up my interface?
The best way is to do it all in main:
int main(int argc, char **argv) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
AppController *controller = [[[AppController alloc] init] autorelease];
[[NSApplication sharedApplication] setDelegate:controller]; //Assuming you want it as your app delegate, which is likely
int status = NSApplicationMain(argc, argv);
[pool drain];
return status;
}
You'll do any other set-up in your application delegate methods in AppController.
You already know this, but for anyone else who reads this: Nibs are your friend. Interface Builder is your friend. Don't fight the framework—work with it, and build your interface graphically, and your application will be better for it.
Another solution to the problem of launching an app without a nib.
Instead of allocing your own controller, just use the extra parameters in the NSApplicationMain() method:
int retVal = NSApplicationMain(argc, argv, #"UIApplication", #"MyAppDelegate");
This takes care of all the proper linking one would need.
Then, the only other thing you'd need to remember is to make your own window and set it to visible.
A set of NIBs seem to be an unsatisfactory answer, even when represented in XML (as a XIB), because there's no easy way to compare or merge them with any standard subversion or SCM-style tool. The encoded information is fragile and not intended to be edited by mere humans. How would changes be represented by a GUI? Would I step through each attribute of each control and visually check them?
If the app's behavior is written in code, however, there is a chance that I can figure out what's going in, even if I have to keep lots of details close at hand at the same time.
A proposed solution: use a top-level NIB that the main architect coded up, but then code the rest of the app explicitly.
Anybody got a better idea?