Implementing NSCoding protocol to send object over to the Java based server - objective-c

I have asked a similar question a couple of days ago...
While I have made some progress, I still cant seem to make it work.
Here is what I got up till now:
customWriteableObj.h:
#interface customWriteableObj : NSObject <NSCoding>
#property int integer;
#property NSString * string;
#property BOOL boo;
#end
customWriteableObj.m:
#import "customWriteableObj.h"
#implementation customWriteableObj
-(id)init
{
_integer = 117;
_string = #"aString";
_boo = YES;
return self;
}
-(id)initWithCoder:(NSCoder *)aDecoder
{
_integer = [aDecoder decodeIntForKey:#"integer"];
_boo = [aDecoder decodeBoolForKey:#"boo"];
_string = [aDecoder decodeObjectForKey:#"string"];
return self;
}
-(void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:self.string forKey:#"string"];
[aCoder encodeBool:self.boo forKey:#"boo"];
[aCoder encodeInteger:self.integer forKey:#"integer"];
}
#end
main:
customWriteableObj * x = [[customWriteableObj alloc]init];
NSMutableData *dat = [[NSMutableData alloc] init];
NSKeyedArchiver* arch1 = [[NSKeyedArchiver alloc]initForWritingWithMutableData:dat];
arch1.outputFormat = NSPropertyListXMLFormat_v1_0;
[arch1 encodeObject:x forKey:#"tester1"];
[arch1 finishEncoding];
[dat writeToFile:#"text.xml";
customWriteableObj * y = [[customWriteableObj alloc]init];
y = [NSKeyedUnarchiver unarchiveObjectWithFile:#"text.xml";
Output in XML:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>$archiver</key>
<string>NSKeyedArchiver</string>
<key>$objects</key>
<array>
<string>$null</string>
<dict>
<key>$class</key>
<dict>
<key>CF$UID</key>
<integer>3</integer>
</dict>
<key>boo</key>
<true/>
<key>integer</key>
<integer>117</integer>
<key>string</key>
<dict>
<key>CF$UID</key>
<integer>2</integer>
</dict>
</dict>
<string>aString</string>
<dict>
<key>$classes</key>
<array>
<string>customWriteableObj</string>
<string>NSObject</string>
</array>
<key>$classname</key>
<string>customWriteableObj</string>
</dict>
</array>
<key>$top</key>
<dict>
<key>tester1</key>
<dict>
<key>CF$UID</key>
<integer>1</integer>
</dict>
</dict>
<key>$version</key>
<integer>100000</integer>
</dict>
</plist>
which doesnt seem to be correct, since I cant see any data here, plus, when I try to read it back I get a nil!
I also need to persist this object to a database on a java based server...

At a glance it looks like you are missing the super calls in your init methods. This means you overrode these initialization methods and never actually initialize an object. So when you deserialize you would just end up with nil. This should fix it:
-(id)init
{
if(self = [super init])
{
_integer = 117;
_string = #"aString";
_boo = YES;
}
return self;
}
-(id)initWithCoder:(NSCoder *)aDecoder
{
if(self = [self init])
{
_integer = [aDecoder decodeIntForKey:#"integer"];
_boo = [aDecoder decodeBoolForKey:#"boo"];
_string = [aDecoder decodeObjectForKey:#"string"];
}
return self;
}
EDIT with JSON serialization example
Create a method on your custom object class that converts the object into a serializable dictionary. It might look something like:
- (NSDictionary *) jsonDictionary
{
return #{#"integer": #(_integer), #"boo": #(_boo), #"string" : _string};
}
Then just call that iteratively on all the objects in your array whenever you are ready to send them over. That might look something like:
// Assuming you have an NSArray called customObjects
NSMutableArray *customObjectsJSON = [[NSMutableArray alloc] initWithCapacity:customObjects.count];
for(customWriteableObj *object in customObjects)
{
[customObjectsJSON addObject:[object jsonDictionary]];
}
At this point, customObjectsJSON is ready to be set as a parameter for a network request. Depending on what other tools you are using you may need to convert it to JSON yourself using NSJSONSerialization

It looks correct. In the XML you can see your 117 and aString values. The XML is a custom format so you generally shouldn't be trying to use it for anything other than storing and reloading.
Your result object when you try to load the archive back in is nil because you are reloading differently than you are archiving (in terms of structure). If you are archiving with [arch1 encodeObject:x forKey:#"tester1"]; then you need to unarchive with initForReadingWithData: and decodeObjectForKey:.

Related

Obj-C: application:openFiles: (multiple files dropped) not receiving all files. Bug?

Closest one I found is: https://stackoverflow.com/questions/4778932/cocoa-app-not-receiving-all-dropped-files-in-applicationopenfiles
But it hasn't been answered.
My Problem is this,
So let's say I am dropping 4 files on my dock application:
test.xls
test.rtf
test.jpg
test.pdf
If I go debug my program it shows this:
Debug log
As you can see the .jpg file is not in there.
This also happens for: .py, other image types, .txt files
I have found out that if I drop files only from that group (.py .jpg .txt) then it recognizes all of them.
My Info.plist looks like this:
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPEplistPUBLIC"-//Apple//DTDPLIST1.0//EN""http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plistversion="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeName</key>
<string>AllFiles</string>
<key>CFBundleTypeIconFile</key>
<string>application.icns</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSHandlerRank</key>
<string>Alternate</string>
<key>LSItemContentTypes</key>
<array>
<string>public.item</string>
</array>
</dict>
</array>
I don't know where the error is in here, maybe it's a bug? Or did I configure my info.plist wrong?
I hope someone can help me and thank you all in advance!
I encountered the same problem and here is how I solved it:
#property (strong) NSMutableArray *openFilesList;
#property (strong) NSTimer *openFilesTimer;
...
#synthesize openFilesList;
#synthesize openFilesTimer;
...
-(void)init {
openFilesList = [[NSMutableArray alloc] init];
openFilesTimer = nil;
}
-(void)application:(NSApplication *)sender openFiles:(NSArray *)filenames {
if (openFilesTimer) {
[openFilesTimer invalidate];
}
[openFilesList addObjectsFromArray:filenames];
openFilesTimer = [NSTimer scheduledTimerWithTimeInterval:0.2f
target:self
selector:#selector(processOpenFiles)
userInfo:nil
repeats:NO];
}
-(void)processOpenFiles {
NSArray *filenames = [openFilesList copy];
openFilesTimer = nil;
[openFilesList removeAllObjects];
// Do your processing with filenames
}
set in info.plist like this
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>*</string>
</array>
<key>CFBundleTypeName</key>
<string>Files</string>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>LSItemContentTypes</key>
<array>
<string>public.data</string>
</array>
</dict>
</array>
and use this method in AppDelegate.m
-(void)application:(NSApplication *)sender openFiles:(NSArray *)fileList{
// use fileList array
}
-(BOOL)application:(NSApplication *)sender openFile:(NSString *)filename{
return YES;
}

SMS Interception in Jailbreak iOS 7

I have followed this answer Blocking incomming sms in ios 7. The problem is it blocks every message and its notification. Secondly it continuously call _processReceivedMessage_hooked method when I send message other then this number +923139303006.
I'm using OpenDev with Xcode 5, iOS 7.x.
#include <logos/logos.h>
#import <substrate.h>
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import <libkern/OSAtomic.h>
#import "CoreTelephony.h"
id(*_processReceivedMessage_orig)(id, SEL, CTMessage*) = NULL;
id _processReceivedMessage_hooked(id self, SEL _cmd, CTMessage* msg);
#class IMDService;
static void (*_logos_orig$_ungrouped$IMDService$loadServiceBundle)(IMDService*, SEL); static void _logos_method$_ungrouped$IMDService$loadServiceBundle(IMDService*, SEL);
static void _logos_method$_ungrouped$IMDService$loadServiceBundle(IMDService* self, SEL _cmd) {
_logos_orig$_ungrouped$IMDService$loadServiceBundle(self, _cmd);
NSBundle *bundle =[NSBundle mainBundle];
NSLog(#"bundle identifier %# ***** ",[bundle bundleIdentifier]);
// if ([[bundle bundleIdentifier] isEqualToString:#"com.apple.imservice.sms"] && [bundle isLoaded])
// {
NSLog(#"Hoooking ***** ");
MSHookMessageEx(objc_getClass("SMSServiceSession"),
#selector(_processReceivedMessage:),
(IMP)_processReceivedMessage_hooked,
(IMP*)&_processReceivedMessage_orig);
// }
}
id _processReceivedMessage_hooked(id self, SEL _cmd, CTMessage* msg)
{
NSObject<CTMessageAddress>* phonenumber = [msg sender];
NSString *senderNumber = (NSString*) [phonenumber canonicalFormat];
CTMessagePart *itmes = [[msg items] objectAtIndex:0];
NSString* msgtxt = [[NSString alloc] initWithData:itmes.data encoding:NSASCIIStringEncoding];
NSLog(#"message %# ****",msgtxt);
if ([senderNumber isEqualToString:#"+923139303006"])
[[CTMessageCenter sharedMessageCenter] acknowledgeIncomingMessageWithId:[msg messageId]];
else
return _processReceivedMessage_orig(self, _cmd, msg);
}
static __attribute__((constructor)) void _logosLocalInit() {
{
Class _logos_class$_ungrouped$IMDService = objc_getClass("IMDService");
MSHookMessageEx(_logos_class$_ungrouped$IMDService, #selector(loadServiceBundle), (IMP)&_logos_method$_ungrouped$IMDService$loadServiceBundle, (IMP*)&_logos_orig$_ungrouped$IMDService$loadServiceBundle);
}
}
here is plist file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Filter</key>
<dict>
<key>Bundles</key>
<array>
<string>com.apple.imagent</string>
</array>
</dict>
</dict>
</plist>
Try uncommenting if ([[bundle bundleIdentifier] isEqualToString:#"com.apple.imservice.sms"] && [bundle isLoaded]) check.
The reason is loadServiceBundle is called multiple times - there're several imagent plugins. Every time it's called you hook _processReceivedMessage: again and again rewriting your previous hooks. Because it all happens inside a single imagent process original _processReceivedMessage: implementation will be lost. As a result you recursively call your hooked function.
Also you using wrong NSBundle instance. [NSBundle mainBundle] returns you bundle of yourself i.e. com.apple.imagent daemon. You need NSBundle of the plugin being loaded. I covered that in my answer - you need to use IMDService -(NSBundle*)bundle. In your case, it will be [self bundle].

NSTableView with source, leads to EXC_BAD_ACCESS

Although I find myself familiar with a bunch of programming languages, I fail for some time now to get used to Cocoa/Objective-C.
I wanted to fill a NSTableView with some content, with the following code:
- (int) numberOfRowsInTableView:(NSTableView *)aTableView {
return (int)[settingsPlist count];}
- (id) tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex {
NSString *title = [[NSString stringWithString:[[aTableColumn headerCell] stringValue]] autorelease];
NSLog(title); // debug
NSLog(#"%i",rowIndex); // debug
if([title isEqual: #"Plugin Name"]) {
return [[settingsPlist objectForKey:[NSString stringWithFormat:#"%i",rowIndex]] objectForKey:#"name"];
} else {
return #"(n/a)";
}
}
settingsPlist is filled with the contents of a plist, looks like this:
<plist version="1.0">
<dict>
<key>0</key>
<dict>
<key>name</key>
<string>Test-Plugin</string>
<key>version</key>
<string>0.1</string>
<key>type</key>
<string>Car</string>
<key>creator</key>
<string>Icke</string>
<key>checksum</key>
<string>0x32</string>
<key>link</key>
<string>http://</string>
</dict>
</dict>
The problem: It works fine for one row (you can tell by looking at the console output, thrown up by NSLog(title); and NSLog(rowIndex);), however, after that, the debugger halts the execution, throwing up EXC_BAD_ACCESS. I know what that means, but I don't know why I'm getting this and how to fix this.
Thanks for any help. :)
you did over release here,
NSString *title = [[NSString stringWithString:[[aTableColumn headerCell] stringValue]] autorelease];
-[NSString stringWithString:] already autorelease the returned value, so you didn't need to call it again.

how to write plist that contains array of dictionary

I'm a new developer for the iPhone. I have a plist file (named "Favorites") in main bundle.
I need to write the data with the following structure, for 20 dictionary items.
how would I write?
<array>
<dict>
<key>PubDate</key>
<date>2011-08-12T23:15:12Z</date>
<key>ImageName</key>
<string>abc.png</string>
<key>Title</key>
<string>ABCDEF</string>
<key>Description</key>
<string>Suggestions?</string>
</dict>
<dict>
<key>PubDate</key>
<date>2011-08-12T23:15:12Z</date>
<key>ImageName</key>
<string>abc.png</string>
<key>Title</key>
<string>ABCDEF</string>
<key>Description</key>
<string>Suggestions?</string>
</dict>
<dict>
<key>PubDate</key>
<date>2011-08-12T23:15:12Z</date>
<key>ImageName</key>
<string>abc.png</string>
<key>Title</key>
<string>ABCDEF</string>
<key>Description</key>
<string>Suggestions?</string>
</dict>
Well don't expect people to write out all the code for you, but this is probably close to what you're looking for.
//Put this where you want to write the data. add is the filename you want to save under
[info writeToFile:[self saveFilePath:add] atomically:YES];
//Put this somewhere in your class
- (NSString*) saveFilePath: (NSString *) add
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
NSString *path = [paths objectAtIndex:0];
NSString *filename = [path stringByAppendingPathComponent:add];
return filename;
}
I will Suggest you to make a Java type dictionary bcoz a dictionary is immutable so you create it once and you can't add or remove objects. For a Java like dictionary you need to use NSMutableDictionary....

arrayWithFile returns count of 0

I am writing an app that copies a plist into the docsdir and then reads it into a mutable array. The code below, however, returns a count of 0 for the array. The line with the dictionary log, however, returns the correct items. I have also verified that the file is being copied to the docsdir.
-(NSString *)docsDir {
return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *listPath = [[self docsDir]stringByAppendingPathComponent:#"list.plist"];
if (![[NSFileManager defaultManager]fileExistsAtPath:listPath]) {
[[NSFileManager defaultManager]copyItemAtPath:[[NSBundle mainBundle]pathForResource:#"list" ofType:#"plist"] toPath:listPath error:nil];
NSLog(#"Chicken");
}
NSLog(#"%#", [NSDictionary dictionaryWithContentsOfFile:listPath]);
_array = [NSArray arrayWithContentsOfFile:listPath];
NSLog(#"Count: %i", [_array count]);
}
- (void)viewDidUnload
{
[super viewDidUnload];
/ / Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
Usually this is because by default root element in plist files is a Dictionary.
Right click and select Open as Source Code, your file may look like this:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>foo</key>
<array>
<string>foo1</string>
<string>foo2</string>
<string>foo3</string>
</array>
</dict>
</plist>
where the root element is a dict, change it to:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
<string>foo1</string>
<string>foo2</string>
<string>foo3</string>
</array>
</plist>
where the root element is an array. You can now edit as usual.
Open the plist file with Xcode.
Just find the 'key' at the top left corner and Type of the plist.
Make sure the Type is Array.
I think your plist is a dictionary that contains an array.
Try this
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:listPath]
NSArray *array = [dict objectForKey:#"key"];
Plists are usually saved a dictionaries:
Here's an example :
<dict>
<key>tiltingAnim</key>
<dict>
<key>filenamePrefix</key>
<string>radar_</string>
<key>delay</key>
<real>0.25</real>
<key>animationFrames</key>
<string>1,2,3,4,5,5,4,3,2,1,2,3,4,5</string>
</dict>
<key>takingAHitAnim</key>
<dict>
<key>filenamePrefix</key>
<string>radar_</string>
<key>delay</key>
<real>0.1</real>
<key>animationFrames</key>
<string>5,5,7,8,8</string>
</dict>
<key>blowingUpAnim</key>
<dict>
<key>filenamePrefix</key>
<string>radar_</string>
<key>delay</key>
<real>0.2</real>
<key>animationFrames</key>
<string>5,6,7,8,9,10,11,12,13,14,15,16,17</string>
</dict>
<key>transmittingAnim</key>
<dict>
<key>filenamePrefix</key>
<string>radar_</string>
<key>delay</key>
<real>0.3</real>
<key>animationFrames</key>
<string>5,6,5,6,5,6,5</string>
</dict>
</dict>
Now, there are 2 solutions to your question.
Either get the contents into a dictionary then take out the array for a specific key.
Open up the plist with a text editor and change the root key into then change root into . If your plist is static and in the bundle resources then you could do this but if it's a plist generated by your code then i wouldn't recommend this.