Implementing NSURLConnectionDataDelegate Protocol - iphone

I am new to iOS development. I am trying to implement NSURLConnectionDataDelegate Protocol but it seems that none of the delegate methods ever get called. I had to type the delegate methods in myself, is it supposed to be automatically generated?
I have an NSLog command in each delegate method but nothing prints. I am using NSURLConnection to Asynchronously download and keep track of the progress so I can update a progressView later.
SearchFeed.h file (Notice I have tried to implement the protocol when I typed NSURLConnectionDataDelegate
#import <Foundation/Foundation.h>
#import "Doc.h"
#interface SearchFeed : NSObject <NSXMLParserDelegate, NSURLConnectionDataDelegate>
{
NSMutableString * currentElementValue;
Doc *currentDoc;
}
#property(strong,nonatomic) NSURL * searchUrl;
#property(strong,nonatomic) NSArray * searchResults;
//#property(retain, nonatomic) Doc * currentDoc;
#property(retain, nonatomic) NSMutableArray *docs;
//#property(retain, nonatomic) NSURLConnection *urlConnection;
#property(retain, nonatomic) UIProgressView * progressBar;
-(void)retrieveFromInternet;
-(double) getProgress;
+(NSString *)pathToDocuments;
+(void)downloadPDFToMyDocumentsFrom:(NSString*) PDFUrl filename:(NSString *) title;
+(NSArray *)listFilesAtPath:(NSString *)path;
#end
SearchFeed.m file:
#import "SearchFeed.h"
#implementation SearchFeed
#synthesize searchUrl = _searchUrl; //where to search from
#synthesize searchResults = _searchResults; // Not being used -- I think
//#synthesize currentDoc = _currentDoc; //current Doc
#synthesize docs = _docs; //array of Docs
#synthesize progressBar = _progressBar;
NSURLConnection *urlConnection;
double fileLength =0;
double lastProgress =0;
double currentLength =0;
NSOutputStream *fileStream;
+(void)downloadPDFToMyDocumentsFrom:(NSString*) PDFUrl filename:(NSString *) title {
NSURL *url = [[NSURL alloc] initWithString:PDFUrl];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
urlConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
NSString *fileName = [title stringByAppendingPathExtension:#"pdf"];
NSString *filePath = [[self pathToDocuments] stringByAppendingPathComponent:fileName];
fileStream = [[NSOutputStream alloc] initToFileAtPath:filePath append:YES];
[fileStream open];
}
//handling incoming data
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
double length = [data length];
currentLength += length;
double progress = currentLength/fileLength;
NSLog(#"Receiving data");
if(lastProgress < progress)
{
//progressBar WRITE code to update the progress for the progress bar
lastProgress = progress;
self.progressBar.progress = lastProgress;
NSLog(#"%f -------------------------------------------------------", lastProgress);
}
NSUInteger left = [data length];
NSUInteger nwr = 0;
do {
nwr = [fileStream write:[data bytes] maxLength:left];
if(nwr == -1)
break;
left -= nwr;
}while(left>0);
if(left)
{
NSLog(#"Stream error: %#", [fileStream streamError]);
}
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
long length = [response expectedContentLength];
fileLength = length;
NSLog(#"%f ------------------------------------------------------- is the fileLength", fileLength);
}
//handling connection progress
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
//WRITE code to set the progress bar to 1.0
self.progressBar.progress = 1.0;
[fileStream close];
NSLog(#"%f -------------------------------------------------------", lastProgress);
}
I have set the delegate for NSURLConnection urlConnection to self which is SearchFeed.m class.
In SearchFeed.h, I tried to implement the NSURLConnectionDataDelegate protocol.
I had to create connectionDidFinishLoading, didReceiveResponse and didReceiveData methods but those methods don't get called.
I either have not implemented the protocol properly OR I have declared some methods as + and some as - (some methods are class methods while some are instance methods)
downloadPDFToMyDocumentsFrom is a class method which is invoked when the user clicks download.
This method sets the NSURLConnection, sets the URL etc and the delegate and opens the fileStream to receive data. However, none of the other methods get called.

Your downloadPDFToMyDocumentsFrom method is setup as a class method (+), and you setup your delegate to be self, meaning the Class in this case. You should make the downloadPDFToMyDocumentsFrom method a instance method (-) so that self is an instantiated object.

Related

Delegate Methods not called in Class Instance

I'm creating an instance of a class called S3ObjectController (S3OC) that has one method and four delegate methods. I create an instance of my S3OC, call an instance method from the S3OC Class (which I know fires from NSLog statements) but none of the associated delegate methods are called within the S3OC class. I have the delegate set to self in the method and the delegate declared properly in the .h header.
Thoughts? just to be clear, it's the (void)request methods in the .m file below I'm thinking should be called that aren't. I'm getting EXC BAD ACCESS errors. Is self getting released by ARC?
The entire .m file of the S3OC class is below:
#import "S3ObjectController.h"
#implementation S3ObjectController
#synthesize string;
#synthesize s3GOR, s3Client;
-(void)method
{
NSLog(#"Method Called");
s3Client = [[AmazonS3Client alloc] initWithAccessKey:ACCESS_KEY_ID withSecretKey:SECRET_KEY];
s3GOR = [[S3GetObjectRequest alloc]initWithKey:string withBucket:[Constants pictureBucket]];
[s3GOR setDelegate:self];
[s3Client getObject:s3GOR];
NSLog(#"Method Finished");
}
-(void)request:(AmazonServiceRequest *)request didFailWithError:(NSError *)error
{
NSLog(#"Error %#",error);
}
-(void)request:(AmazonServiceRequest *)request didReceiveResponse:(NSURLResponse *)response
{
NSLog(#"Response Key %#", response);
}
-(void)request:(AmazonServiceRequest *)request didReceiveData:(NSData *)data
{
NSLog(#"ObjectRequestKey = %#",request);
}
-(void)request:(AmazonServiceRequest *)request didCompleteWithResponse:(AmazonServiceResponse *)response
{
NSLog(#"Final Delegate Method");
}
Here's the header:"
#interface S3ObjectController : NSObject <AmazonServiceRequestDelegate>{
NSMutableData *responseData;
NSString *string;
AmazonS3Client *s3Client;
S3GetObjectRequest *s3GOR;
}
-(void)method;
#property (nonatomic, strong) NSString *string;
#property (nonatomic, strong) S3GetObjectRequest *s3GOR;
#property (nonatomic, strong) AmazonS3Client *s3Client;
#end
Finally, here's how I call the method in another class:
for (NSString *name in nameArray){
#try {
S3ObjectController *localS3 = [[S3ObjectController alloc]init];
localS3.string = name;
[localS3 method];
NSLog(#"called");
}
I think your suspicions about ARC are true. Because delegate properties are usually weak references, they aren't enough to keep the object from being released.
Make an NSArray that's an iVar and add the S3ObjectController to it. If the delegates still don't fire, you know it's something else...
Edit:
so declare an NSMutableArray in the header of the class that contains your for loop, initialize it somewhere like this:
myArray = [NSMutableArray arrayWithCapacity:0];
then use it like this:
for (NSString *name in nameArray){
#try {
S3ObjectController *localS3 = [[S3ObjectController alloc]init];
localS3.string = name;
[localS3 method];
[myArray addObject:localS3];
NSLog(#"called");
}
}

Instances of NSObject acting as NSUrlConnection delegate appear not to be isolated

First post here, so I hope it is detailed enough.
While developing an Iphone App I am confronted with some strange behavour. A member variable of a certain instance of my "WebserviceConnection" class seems to obtain the value I assign to another instances of the same class.
For illustration: This is en excerpt of my log. I assume the 0x000000 is an instance ID. The fourth response should be "<-: 1".
2011-11-03 16:25:13.227 Dashboard[540:707] ->: 1, <WebserviceConnection: 0x11f950>
2011-11-03 16:25:13.256 Dashboard[540:707] ->: 0, <WebserviceConnection: 0x323db0>
2011-11-03 16:25:15.318 Dashboard[540:707] <-: 0, <WebserviceConnection: 0x323db0>
2011-11-03 16:25:15.325 Dashboard[540:707] <-: 0, <WebserviceConnection: 0x11f950>
The class is a NSUrlConnection delegate which exhibits this behavour when two connections are open at the same time.
This class: WebserviceConnection.h
(The ConnectionType is an enum)
#import "WebserviceConnection.h"
#import "WebserviceUtility.h"
#implementation WebserviceConnection
BOOL isCanceled;
NSDictionary *result;
ConnectionType connectionType;
id <WebserviceConnectionDelegate> delegate;
- (id)initWithDelegate:(id)webServiceDelegate connectionType:(ConnectionType) type {
delegate = webServiceDelegate;
connectionType = type;
isCanceled = NO;
NSLog(#"->: %i, %#", connectionType, self);
return self;
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
switch (connectionType) {
case GetAllAlerts:
result = [WebserviceUtility getJsonFromData:data];
break;
case GetServerAlerts:
result = [WebserviceUtility getJsonFromData:data];
break;
case GetServers:
result = [WebserviceUtility getJsonFromData:data];
break;
default:
result = nil;
break;
}
}
- (void)displayErrorAlert {
UIAlertView *errorMessage = [[UIAlertView alloc] initWithTitle:#"Fout" message:#"Verbinding met webservice niet mogelijk" delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[errorMessage show];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
if(!isCanceled) {
#try {
[delegate connection:connection ofType:connectionType didFinishWithError: [NSDictionary dictionaryWithObject:#"error" forKey:#"WebserverConnectionFailed"]];
}
#catch (NSException *e) {}
#finally {}
[self displayErrorAlert];
}
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(#"<-: %i, %#", connectionType, self);
if(!isCanceled) {
[delegate connection:connection ofType:connectionType didFinishWithResult:result];
}
}
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
NSURLCredential *credential = [WebserviceUtility getCredentials];
if ([challenge previousFailureCount] == 0) {
[[challenge sender] useCredential:credential
forAuthenticationChallenge:challenge];
}
else {
[delegate connection:connection ofType:connectionType didFinishWithError: [NSDictionary dictionaryWithObject:#"error" forKey:#"WebserverConnectionFailed"]];
[self displayErrorAlert];
}
}
- (void)delegateDidDealloc {
NSLog(#"!!: %i, %#", connectionType, self);
isCanceled = YES;
}
#end
Used like this:
- (void) getAllAlerts {
NSURLRequest *request = [WebserviceUtility getRequestForPath:#"/dashboard/DashboardAppleConnector.asmx/GetActiveAlerts"];
webserviceConnection = [[WebserviceConnection alloc] initWithDelegate:self connectionType:GetAllAlerts];
connection = [[NSURLConnection alloc] initWithRequest:request delegate: webserviceConnection];
}
When another ViewController with its own webserviceConnection instance uses its instance (similar to getAllAlerts) all goed pearshaped!
Any thoughts anyone?
Regards,
Bert
It looks like the problem is happening because of the way you are declaring your variables like connectionType. If you want them to be declared as instance variables, you should be putting them in the interface declaration:
#interface WebServiceConnection {
BOOL isCanceled;
NSDictionary *result;
ConnectionType connectionType;
id <WebserviceConnectionDelegate> delegate;
}
#end
By declaring them in the #implementation block you are actually creating global variables, not instance variables.
See this SO post for more information
The definition block:
BOOL isCanceled;
NSDictionary *result;
ConnectionType connectionType;
id <WebserviceConnectionDelegate> delegate;
Declares those four things to be global variables, exactly as if they weren't in the #implementation block. Simply putting things inside #implementation doesn't make them local to the object — it just explains which object all the subsequent method implementations belong to.
If you don't mind putting implementation specifics into your header files, you could move them into the #interface declaration, e.g.
#interface WebserviceConnection
{
BOOL isCanceled;
NSDictionary *result;
ConnectionType connectionType;
id <WebserviceConnectionDelegate> delegate;
}
// etc
#end
You can keep them purely internal to the implementation at the cost of some repetitive syntax by adding them to your class through a category, e.g.
#import "WebserviceConnection.h"
#import "WebserviceUtility.h"
#interface WebserviceConnection() // a category to add additional properties
#property (nonatomic, assign) BOOL isCanceled;
#property (nonatomic, retain) NSDictionary *result;
#property (nonatomic, assign) ConnectionType connectionType;
#property (nonatomic, assign) id <WebserviceConnectionDelegate> delegate;
#end
#implementation WebserviceConnection
// synthesising the properties also adds the named properties as instance variables
#synthesize isCanceled;
#synthesize result;
#synthesize connectionType;
#synthesize delegate;
- (id)initWithDelegate:(id)webServiceDelegate ... etc...
Aside: a method called getJsonFromData: should return a non-owning reference according to Cocoa naming conventions since it doesn't contain 'new', 'alloc', 'retain' or 'create'. Which, if you were to obey, would leave you with a dangling pointer in result in the code as presented.

iOS - Opening a PDF via Quicklook without using UIScrollView

I am trying to open a PDF via the QuickLook framework without using UIScrollView...
I believe I'm missing something...
Where I believe I'm going wrong is that I need to use a QLPreviewController and on the QLPreviewController is a dataSource that has to conform to QLPreviewItem. The documentation states that NSURL does conform to QLPriewItem so I'm setting the preview.dataSource to an NSURL which is throwing an error:
[NSURL numberOfPreviewItemsInPreviewController:]: unrecognized selector sent to instance
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSURL numberOfPreviewItemsInPreviewController:]: unrecognized selector sent to instance 0x5b5f200'
Which makes me think that NSURL does not conform.
all the code I think is necessary...
- (BOOL)previewController:(QLPreviewController *)controller shouldOpenURL:(NSURL *)url forPreviewItem:(id <QLPreviewItem>)item {
return YES;
}
- (NSInteger) numberOfPreviewItemsInPreviewController: (QLPreviewController *) controller {
return [documents count];
}
- (id <QLPreviewItem>) previewController: (QLPreviewController *) controller previewItemAtIndex: (NSInteger) index {
return [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:[documents objectAtIndex:index] ofType:nil]];
}
- (void)pushPDF {
QLPreviewController *preview = [[QLPreviewController alloc] init];
preview.dataSource = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"MCIT_Quiz" ofType:#"pdf"]];
//preview.currentPreviewItemIndex = 0;
[self presentModalViewController:preview animated:YES];
[preview release];
}
I ended up just creating another class to hold my values and use as a datasource, a bit quick and dirty but it works.
//
// documentList.h
//
#import <Foundation/Foundation.h>
#import <QuickLook/QuickLook.h>
#interface DocumentList : NSObject <QLPreviewControllerDataSource, QLPreviewControllerDelegate> {
NSArray *documents;
}
#property (nonatomic, retain) NSArray *documents;
-(void)createList;
-(NSInteger) numberOfPreviewItemsInPreviewController: (QLPreviewController *) controller;
- (id <QLPreviewItem>) previewController: (QLPreviewController *) controller previewItemAtIndex: (NSInteger) index;
#end
inserting text to break up the files
//
// documentList.m
//
#import "DocumentList.h"
#implementation DocumentList
#synthesize documents;
-(void) createList {
documents = [[NSArray arrayWithObjects:#"Quiz.pdf", nil] retain];
}
-(NSInteger) numberOfPreviewItemsInPreviewController: (QLPreviewController *) controller {
return [documents count];
}
- (id <QLPreviewItem>) previewController: (QLPreviewController *) controller previewItemAtIndex: (NSInteger) index {
return [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:[documents objectAtIndex:index] ofType:nil]];
}
#end
Well, I don't see where an NSURL conforms to QLPreviewControllerDataSource. I think you want
preview.dataSource = self;
And then your already written routines (numberOfPreviewItemsInPreviewController and previewController) would return the appropriate NSURL (although it's not clear how "documents" gets filled.).

Send and receive NSData via GameKit

I'm trying to send some NSData over Bluetooth through GameKit.
While I've got GameKit set up and are able to send small messages across, I now would like to expand and send across whole files.
I've been reading that you have to split large files up into packets before sending them across individually.
So I decided to create a struct to make it easier to decode the packets when they're received at the other end:
typedef struct {
const char *fileName;
NSData *contents;
int fileType;
int packetnumber;
int totalpackets;
} file_packet;
However, for small files (8KB and less) I thought one packet will be enough.
So for one packet, I thought I would be able to create a file_packet, set its properties, and send it via -sendDataToAllPeers:withDataMode:error:
NSData *fileData;
file_packet *packet = (file_packet *)malloc(sizeof(file_packet));
packet->fileName = [filename cStringUsingEncoding:NSASCIIStringEncoding];
packet->contents = [NSData dataWithContentsOfFile:selectedFilePath];
packet->packetnumber = 1;
packet->totalpackets = 1;
packet->fileType = 56; //txt document
fileData = [NSData dataWithBytes:(const void *)packet length:sizeof(file_packet)];
free(packet);
NSError *error = nil;
[self.connectionSession sendDataToAllPeers:fileData withDataMode:GKSendDataReliable error:&error];
if (error) {
NSLog(#"An error occurred: %#", [error localizedDescription]);
}
However, I don't think something's right setting fileData - and error displays nothing.
When a file's received, I do the following:
file_packet *recievedPacket = (file_packet *)malloc(sizeof(file_packet));
recievedPacket = (file_packet *)[data bytes];
NSLog(#"packetNumber = %d", recievedPacket->packetnumber);
...
However, the output on the console is packetNumber = 0, even when I set packetNumber to 1.
Am I missing the obvious?
I don't know much about NSData or GameKit.
So my question is - Can I add a file_packet in NSData, and if so, How do I do it successfully - and How do you split files up into multiple packets?
To add on:
What you ought to do here is make an NSObject subclass to represent your packet, and then adopt NSCoding to serialize it to an NSData in the way that you want. Doing this with a struct isn't buying you anything, and makes things even harder. It's also fragile, since packing a struct into an NSData doesn't account for things like endian-ness, etc.
The tricky part of the packetizing process using NSCoding is that you don't really know what the overhead of the coding process is, so being as big as possible, but still under the max packet size is tricky...
I present this without testing, or warranty, but if you want a decent start on that approach, this may be it. Be warned, I didn't check to see if my arbitrary 100 bytes for overhead was realistic. You'll have to play with the numbers a little bit.
Packet.h:
#interface Packet : NSObject <NSCoding>
{
NSString* fileName;
NSInteger fileType;
NSUInteger totalPackets;
NSUInteger packetIndex;
NSData* packetContents;
}
#property (readonly, copy) NSString* fileName;
#property (readonly, assign) NSInteger fileType;
#property (readonly, assign) NSUInteger totalPackets;
#property (readonly, assign) NSUInteger packetIndex;
#property (readonly, retain) NSData* packetContents;
+ (NSArray*)packetsForFile: (NSString*)name ofType: (NSInteger)type withData: (NSData*)fileContents;
#end
Packet.m:
#import "Packet.h"
#interface Packet ()
#property (readwrite, assign) NSUInteger totalPackets;
#property (readwrite, retain) NSData* packetContents;
#end
#implementation Packet
- (id)initWithFileName: (NSString*)pFileName ofType: (NSInteger)pFileType index: (NSUInteger)pPacketIndex
{
if (self = [super init])
{
fileName = [pFileName copy];
fileType = pFileType;
packetIndex = pPacketIndex;
totalPackets = NSUIntegerMax;
packetContents = [[NSData alloc] init];
}
return self;
}
- (void)dealloc
{
[fileName release];
[packetContents release];
[super dealloc];
}
#synthesize fileName;
#synthesize fileType;
#synthesize totalPackets;
#synthesize packetIndex;
#synthesize packetContents;
- (void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject: self.fileName forKey: #"fileName"];
[aCoder encodeInt64: self.fileType forKey:#"fileType"];
[aCoder encodeInt64: self.totalPackets forKey:#"totalPackets"];
[aCoder encodeInt64: self.packetIndex forKey:#"packetIndex"];
[aCoder encodeObject: self.packetContents forKey:#"totalPackets"];
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super init])
{
fileName = [[aDecoder decodeObjectForKey: #"fileName"] copy];
fileType = [aDecoder decodeInt64ForKey:#"fileType"];
totalPackets = [aDecoder decodeInt64ForKey:#"totalPackets"];
packetIndex = [aDecoder decodeInt64ForKey:#"packetIndex"];
packetContents = [[aDecoder decodeObjectForKey:#"totalPackets"] retain];
}
return self;
}
+ (NSArray*)packetsForFile: (NSString*)name ofType: (NSInteger)type withData: (NSData*)fileContents
{
const NSUInteger quanta = 8192;
Packet* first = [[[Packet alloc] initWithFileName:name ofType:type index: 0] autorelease];
// Find out how big the NON-packet payload is...
NSMutableData* data = [NSMutableData data];
NSKeyedArchiver* coder = [[[NSKeyedArchiver alloc] initForWritingWithMutableData:data] autorelease];
[first encodeWithCoder: coder];
[coder finishEncoding];
const NSUInteger nonPayloadSize = [data length];
NSMutableArray* packets = [NSMutableArray array];
NSUInteger bytesArchived = 0;
while (bytesArchived < [fileContents length])
{
Packet* nextPacket = [[[Packet alloc] initWithFileName: name ofType: type index: packets.count] autorelease];
NSRange subRange = NSMakeRange(bytesArchived, MIN(quanta - nonPayloadSize - 100, fileContents.length - bytesArchived));
NSData* payload = [fileContents subdataWithRange: subRange];
nextPacket.packetContents = payload;
bytesArchived += [payload length];
[packets addObject: nextPacket];
}
for (Packet* packet in packets)
{
packet.totalPackets = packets.count;
}
return packets;
}
- (NSData*)dataForSending
{
NSMutableData* data = [NSMutableData data];
NSKeyedArchiver* coder = [[[NSKeyedArchiver alloc] initForWritingWithMutableData:data] autorelease];
[self encodeWithCoder: coder];
[coder finishEncoding];
return [NSData dataWithData:data];
}
+ (Packet*)packetObjectFromRxdData:(NSData*)data
{
NSKeyedUnarchiver* decoder = [[[NSKeyedUnarchiver alloc] initForReadingWithData:data] autorelease];
return [[[Packet alloc] initWithCoder:decoder] autorelease];
}
#end
The reassemblage of the original file from these packets can be done using much the same approach as splitting it up... Iterate over the packets, copying from the individual packet payload NSDatas into a big NSMutableData.
In closing, I feel compelled to say that when you find yourself doing something like this, that boils down to implementing a primitive TCP stack, it's usually time to stop yourself and ask if there aren't better ways to do this. Put differently, if GameKit were the best way to transfer files between devices over bluetooth, one would expect that the API would have a method for doing just that, but instead it has this 8K limit.
I'm not being intentionally cryptic -- I don't know what the right API would be for your situation, but the exercise of cooking up this Packet class left me thinking, "there's gotta be a better way."
Hope this helps.
You create the NSData with size sizeof(packet), which is only the pointer's size. Change it to sizeof(file_packet).
BTW, you're not really sending the filename and the contents. Only the pointers to them.

iPhone read image from socket

I am working in a little app for iphone base on ideas used to make an Android app.
To test, obviously i use the simulator, but the simulator don't have support for built-in camera. The Android idea to test this consist in use a WebCamBroadcaster Java app in the desktop to capture frames from built-in webcam and pass it through socket. Then in the app you just read the bytes and convert to image.
Well i was trying to do the same thing with iPhone Simulator. Searching in the web a found a class to work with asynchronous sockets (cocoaasyncsocket). But i can't make it work.
The Java App send the frames like this:
socket = ss.accept();
BufferedImage image = videoCapture.getNextImage();
if (image != null) {
OutputStream out = socket.getOutputStream();
if (RAW) {
image.getWritableTile(0, 0).getDataElements(0, 0, w$
image.releaseWritableTile(0, 0);
DataOutputStream dout = new DataOutputStream(new Bu$
out));
for (int i = 0; i < data.length; i++) {
dout.writeInt(data[i]);
}
dout.close();
} else {
ImageIO.write(image, "JPEG", out);
}
}
The Android version of this use C code to implement de socket reading proccess like this:
long read_count, total_read = 0;
while (total_read < readBufSize)
{
read_count = read(sockd, &readBuf[total_read], readBufSize);
if (read_count <= 0 || errno != 0)
{
char buffer[100];
sprintf(buffer, "socket read errorno = %d", errno);
LOGV(buffer);
break;
}
total_read += read_count;
}
// If we read all of the data we expected, we will load the frame from the p$
if (total_read == readBufSize){
frame = loadPixels(readBuf, width, height);}
Where readBufsize = width*height*sizeof(int);
readBuf = (char*)malloc(readBufSize);
So i try to implement the same for iPhone but i have an error in the connection (errno = 2).. Then i find cocoaasyncsocket and i try to use but i have an unknown error and nothing is read:
#import <Foundation/Foundation.h>
#import "AsyncSocket.h"
#interface Captura : NSObject {
NSString *ipserver;
UInt16 port;
NSError *errPtr;
AsyncSocket *socket;
NSMutableData *socketData;
}
#property (nonatomic,retain) NSString *ipserver;
#property (retain) AsyncSocket *socket;
#property (retain) NSError *errPtr;
//will contain de data read from socket
#property (retain) NSMutableData *socketData;
-(id)initWithIp:(NSString*)ip puerto:(UInt16)p;
-(BOOL)open;
-(void)close;
-(void)beginRead;
- (UIImage*)getImage;
#end
and the implementation
#import "Captura.h"
#implementation Captura
#synthesize ipserver;
#synthesize socket;
#synthesize errPtr;
#synthesize socketData;
-(id)initWithIp:(NSString*)ip puerto:(UInt16)p{
if (self = [super init]) {
ipserver = ip;
port = p;
socket = [[AsyncSocket alloc] initWithDelegate:self];
socketData = [[NSMutableData alloc] init];
}
return self;
}
//Connect
-(BOOL)open{
return [socket connectToHost:ipserver onPort:port error:&errPtr];
}
-(void)beginRead{
NSLog(#"Begin Read");
NSUInteger offset = [socketData length];
[socket readDataWithTimeout:1
tag:0];
}
- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port{
NSLog(#"Conectado al servidor");
}
- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
NSLog(#"Data leida %u",[data length]);
[socketData appendData:data];
[self beginRead];
}
- (void)onSocketDidDisconnect:(AsyncSocket *)sock{
[socketData release];
[ipserver release];
[socket release];
NSLog(#"MutableData length %u", [socketData length]);
NSLog(#"Socket Desconectado");
}
- (void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err{
NSLog(#"Ocurrió un error desconectando.... %#",err);
}
- (UIImage*)getImage{
NSData *data;
[socketData getBytes:data length:320*480*sizeof(int)];
NSLog(#"Data obtenida %#",[data length]);
if ([socketData length]>320*480*sizeof(int)) {
[socketData replaceBytesInRange:NSMakeRange(0,320*480*sizeof(int)) withBytes:NULL length:0];
}
if (data!=nil && [data length]) {
UIImage *img = [[UIImage alloc] initWithData:data];
[data release];
return img;
}
[data release];
return nil;
}
#end
Well this code connect to the server and initialize the reading process and then close up.. socket is disconnect and the app is close.
i can't test de getImage method yet...
Some idea?
Thanks in advance...
I think you need a call to -beginRead in -onSocket:didConnectToHost:port: