The Mobile Galaxy The New Mobile Era Has Come | Mobile – A Time To Remember

25Nov/110

Memory Management Advice – iphone

I am a little unclear about some of the conventions in memory management. I have tried to follow Slick and Duncan's advice and follow this style:

in .h

Class *_var

@property (nonatomic, retain) Class *var

in .m@synthesize var = _var;When assigning the variable

either (for example with UITextView):

self.var = [[[UITextView alloc] initWithFrame:(such and such frame)] autorelease];

(autorelease to avoid two retains)

or

UITextView *tempTextView = [[UITextView alloc] initWithFrame:(so on and so so)];
self.var = tempTextView;
[tempTextView release];

In dealloc

self.var = nil; (does the release automatically due to synthesize)

So, assuming I am doing this right, the question comes up in what I do when I am working with these variables. Do I use the instance variable or property when working with the variable in non "self.var = " purposes.

for instance:

If var is a UITextView, Do I use:

self.var.userInteractionEnabled = NO;
self.var.text = @"Some Text";

OR

_var.userInteractionEnabled = NO;
_var.text = @"Some Text";

Basically,

When is the property accessed when changing the "sub properties" vs. the instance variable. It seems like both work but I assume that one would have a preferred way above another.

I was under the impression that I should only call the property when directly assigning. e.g.

self.var = something;

Additionally, when adding a subView to a view (assuming a UITextView var), would I say:

[self.view addSubView: self.var];

or

[self.view addSubview:_var];

btw, I've color coded Instance Variables as Slick suggested in red but I am confused as it seems like everything shows up as an instance variable (including self.var) in red. The only time something shows up not red is like:

[something setSomething:self.var];

Where "var" is not red.

Otherwise:

self.var =

or

_var =

var is red.

I feel like this is a huge fundamental thing I am missing and although I have created a great number of successful apps, I keep having minor bugs haunt me that are associated with memory problems. All the tutorials you follow assign instance variables and properties with the same exact name so it isn't clear what is going on and why it works.

Thanks!
James

Share
21Nov/110

What is MailCore?

MailCore is a Cocoa framework designed to ease the pain of dealing with e-mail protocols by adding a nice Objective-C/Cocoa interface to the C library Libetpan!. MailCore makes the process of sending e-mail easy by hiding the nasty details like MIME composition from you. Instead, there is a nice interface for composing messages and then there is a single method required to send the message. Checking e-mail on an IMAP server is a more complex beast, but MailCore makes the job much simpler but presenting everything as a set of abstract objects like Messages, Folders and Accounts. Note, however, that MailCore is not multithreaded so any calls made will potentially block and not every IMAP detail is abstracted away. Also, MailCore stores everything in memory so if you want to save state to disk it has to be done by hand.

 

Sending E-mail

Sending e-mail with MailCore is very easy, it takes care of all the details like MIME encoding, and the SMTP protocol. First, start by creating a CTCoreMessage instance. Then set the subject, body, from, and atleast one to, bcc, or cc recipient. One detail to note is that the to, cc, bcc attributes take an NSSet of CTCoreAddress recipients.

CTCoreMessage *testMsg = [[CTCoreMessage alloc] init];
[testMsg setTo:[NSSet setWithObject:[CTCoreAddress addressWithName:@"Monkey" email:@"monkey@monkey.com"]]];
[testMsg setFrom:[NSSet setWithObject:[CTCoreAddress addressWithName:@"Someone" email:@"test@someone.com"]]];
[testMsg setBody:@"This is a test message!"];
[testMsg setSubject:@"This is a subject"];

Once the message attributes have been set, all that is left is sending the message usingCTSMTPConnection:

[CTSMTPConnection sendMessage:testMsg server:@"mail.test.com" username:@"test" password:@"test" port:25 useTLS:YES shouldAuth:YES];
[testMsg release];

That's all

 

Working with IMAP

Working with IMAP through MailCore is quite easy. First you need to instantiate aCTCoreAccount object and establish a connection like so:

CTCoreAccount *account = [[CTCoreAccount alloc] init];
[account connectToServer:@"mail.theronge.com" port:143 connectionType:CONNECTION_TYPE_PLAIN authType:IMAP_AUTH_TYPE_PLAIN login:@"test" password:@"none"];

If by any chance it fails to make a connection an exception will be thrown. Now that we have a connection to the server we can go ahead and get a list of folders. Note: I use the term folder in place of mailbox; the IMAP spec uses the term mailbox but I get that confused with account.

NSSet *subFolders = [account subscribedFolders];

If we take a look at the resulting NSSet, we see that what is returned is a set of NSStrings with folder path's.

<NSCFSet: 0x309d60> (INBOX.Test.Test22, INBOX, INBOX.TheArchive, INBOX.Test, INBOX.Trash)

We can use one of those strings to create a CTCoreFolder object or we can just pass in a path, for example this sets up a connection to the INBOX on the server.

CTCoreFolder *inbox = [account folderWithPath:@"INBOX"];

Now that we have a connection to a folder we can start to do more interesting things, like we can get a set of the messages in the particular folder, or we can delete the folder, or remove the folder from the subscribed list, check the CTCoreFolder for more information. For this particular example I am going to get a list of the messages in the INBOX (0 as the end index indicates that the entire inbox should be loaded).

NSSet *messageList = [inbox messageListFromIndex:1 toIndex:0];

Like the with folders, what is returned is a set of NSString's containing unique message identifiers (UID).

<NSCFSet: 0x309d60> (1142229815-5, 1142229815-6, 1142229815-7, 1142229815-8, 1142229815-10, 1142229815-1, 1142229815-9, 1142229815-2, 1142229815-11, 1142229815-3, 1142229815-4)

You might be wondering about the parameter to messageListFromIndex: now, it's exists because of a limitation of IMAP. IMAP was designed to be a protocol where you would always be connected to the server, it wasn't until later that people got the idea using IMAP as an offline protocol. Therefore, IMAP generally returns the entire list of message UID's, but this can be very time consuming for very large folders, and by a large folder I'm talking over 5000 messages. To download only new messages and not every message each time, you can save the last message UID you received. Since you have the last message UID you know the next UID has to be one after it. For example, if you receive the UID 1142229815-4 then you know the next UID has to be 1142229815-5. So if you pass 1142229815-4 into messageListFromIndex: it will only retrieve message with a higher UID.

While UID's are not supposed to change, a folder can change the message UID's on rare occasions. It's important to make sure that the cached UID"s are still valid by using the isUIDValid method. If a bad UID was used there is potential for data loss, since the former UID might not reference the message you intend on deleting. If you save a UID, you should make sure that the server is still using the same UID, otherwise start over by passing nil into messageListFromIndex.

Now back to working with messages, to retrieve with a particular message you need to use the method messageWithUID inside of CTCoreFolder. The resulting object will be of typeCTCoreMessage, from there you can retrieve the subject, body and other things by using the message object.

Share
21Nov/110

Capture IOS Screen code

1.
UIGraphicsBeginImageContextWithOptions(pageView.page.bounds.size, YES, zoomScale);
        [pageView.page.layer renderInContext:UIGraphicsGetCurrentContext()];
        UIImage *uiImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
2.
- (UIImage *) glToUIImage {
    
    DWScrollView *pageView = [self getActivePageView];
       pageView.page.backgroundColor = [UIColor clearColor];
  //  self.backgroundColor=[UIColor clearColor];
    NSInteger myDataLength = 320 * 308 * 4;
    
    // allocate array and read pixels into it.
    GLubyte *buffer = (GLubyte *) malloc(myDataLength);
    glReadPixels(0, 0, 320, 308, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
    
    // gl renders "upside down" so swap top to bottom into new array.
    // there's gotta be a better way, but this works.
    GLubyte *buffer2 = (GLubyte *) malloc(myDataLength);
    
    for(int y = 0; y <308; y++)
    {
        for(int x = 0; x <320 * 4; x++)
        {
            if(buffer[y* 4 * 320 + x]==0)
                buffer2[(307 - y) * 320 * 4 + x]=1;
            else
                buffer2[(307 - y) * 320 * 4 + x] = buffer[y* 4 * 320 + x];
        }
    }
    
    // make data provider with data.
    CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, buffer2, myDataLength, NULL);
    
    // prep the ingredients
    int bitsPerComponent = 8;
    int bitsPerPixel = 32;
    int bytesPerRow = 4 * 320;
    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
    CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
    CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
    
    // make the cgimage
    CGImageRef imageRef = CGImageCreate(320, 308, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent);
    
    // then make the uiimage from that
    UIImage *myImage = [UIImage imageWithCGImage:imageRef];
    UIImageWriteToSavedPhotosAlbum(myImage, nil, nil, nil);
    return myImage;
}

3.
// get screen
- (void)grabScreen {
    unsigned char buffer[320*480*4];
    glReadPixels(0,0,320,480,GL_RGBA,GL_UNSIGNED_BYTE,&buffer);
    
    CGDataProviderRef ref = CGDataProviderCreateWithData(NULL, &buffer, 320*480*4, NULL);
    CGImageRef iref = CGImageCreate(320,480,8,32,320*4,CGColorSpaceCreateDeviceRGB(),kCGBitmapByteOrderDefault,ref,NULL,true,kCGRenderingIntentDefault);
    CGFloat width = CGImageGetWidth(iref);
    CGFloat height = CGImageGetHeight(iref);
    size_t length = width*height*4;
    uint32_t *pixels = (uint32_t *)malloc(length);
    CGContextRef context = CGBitmapContextCreate(pixels, width, height, 8, 320*4, CGImageGetColorSpace(iref), kCGImageAlphaLast | kCGBitmapByteOrder32Big);
    CGContextTranslateCTM(context, 0.0, height);
    CGContextScaleCTM(context, 1.0, -1.0);
    CGContextDrawImage(context, CGRectMake(0.0, 0.0, width, height), iref);
    CGImageRef outputRef = CGBitmapContextCreateImage(context);
    UIImage *outputImage = [UIImage imageWithCGImage:outputRef];
    
    UIImageWriteToSavedPhotosAlbum(outputImage, nil, nil, nil); 
    
    CGContextRelease(context);
    CGImageRelease(iref);
    CGDataProviderRelease(ref);
} 
4.
CGImageRef UIGetScreenImage();
void SaveScreenImage(NSString *path)
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    CGImageRef cgImage = UIGetScreenImage();
        void *imageBytes = NULL;
        if (cgImage == NULL) {
                CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
                imageBytes = malloc(320 * 480 * 4);
                CGContextRef context = CGBitmapContextCreate(imageBytes, 320, 480, 8, 320 * 4, colorspace, kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Big);
                CGColorSpaceRelease(colorspace);
                for (UIWindow *window in [[UIApplication sharedApplication] windows]) {
                        CGRect bounds = [window bounds];
                        CALayer *layer = [window layer];
                        CGContextSaveGState(context);
                        if ([layer contentsAreFlipped]) {
                                CGContextTranslateCTM(context, 0.0f, bounds.size.height);
                                CGContextScaleCTM(context, 1.0f, -1.0f);
                        }
                        [layer renderInContext:(CGContextRef)context];
                        CGContextRestoreGState(context);
                }
                cgImage = CGBitmapContextCreateImage(context);
                CGContextRelease(context);
        }
    NSData *pngData = UIImagePNGRepresentation([UIImage imageWithCGImage:cgImage]);
    CGImageRelease(cgImage);
        if (imageBytes)
                free(imageBytes);
    [pngData writeToFile:path atomically:YES];
    [pool release];
}

5.
  + (UIImage *)imageWithScreenContents
{
     CGImageRef cgScreen = UIGetScreenImage();
     if (cgScreen) {
         UIImage *result = [UIImage imageWithCGImage:cgScreen];
         CGImageRelease(cgScreen);
         return result;
     }
     return nil;
}
Share
20Nov/110

FoneMonkey – Automation Testing Tool for iOS Apps

 

 

Credit to:

Rishabh Software

 

From:http://www.rishabhsoft.com/blog/fonemonkey-automation-testing-tool-for-ios-apps

The growing popularity of mobile applications requires that companies adopt strategies and have automated testing solutions designed specifically for the needs of their mobile applications. Due to its nature, it is always a challenge to have automation testing for mobile applications.

I have been getting many customer inquiries about automation testing tools for mobile apps. So far, there have not been many companies offering free tools, but now there’s hope for all mobile apps developers and testers. Gorilla Logic, an IT-consultancy company has launched an open-source automation testing tool for iOS apps, by the name of FoneMonkey.

FoneMonkey is an easy to learn tool that can be used effectively by both groups, to develop and test. FoneMonkey offers the possibilities to save a script, load, read and conveniently modify it. The user can create test suites that automate the execution of the operation sequences of the users and check the results. FoneMonkey is designed to support developers and quality control tests. Tests of FoneMonkey can be easily incorporated into continuous integration environments. FoneMonkey fills a huge void in the area of ​​agile development and showed pragmatism through automated testing for iOS apps.

FoneMonkey Features

  • Robust script recording and playback — more comprehensive recording and playback for user interactions, including taps, keyboard input, dragging, and scrolling for all Cocoa Touch components.
  • Code generation options –  generation of ready-to-run test scripts in Objective-C under OCUnit, or JavaScript under Apple’s UI Automation tools
  • Optimized for both iPhone and iPad platforms and user interfaces
  • Works on both simulators and real devices
  • Completely automated test playbacks

A few disadvantages of FoneMonkey

  • It does not support Flex andAndroid application
  • It does not support testing of HTML-based apps delivered through UIWebView

 

FoneMonkey gives you the ability to easily record, edit and add verification steps to scripts by simply interacting with your apps on the iOS device. So, are you looking to get your iOS Apps tested?

Share