Tag Archives: development

Overriding HTTP user agent for calls to -initWithContentsOfURL:

Perhaps you need to override the HTTP user agent whenever you call -initWithContentsOfURL: from classes such as NSString, NSDictionary or NSArray, or one of this method’s convenience wrappers such as +stringWithContentsOfURL:, +dictionaryWithContentsOfURL: or +arrayWithContentsOfURL:. So let’s consider how this can be accomplished under iOS.

From what I can see, there is no easy and “clean” way apart from adding a category on the classes where you need to support this and writing your own implementation of -initWithContentsOfURL: and convenience functions (with a slightly different name, of course). These implementations would use NSURLConnection‘s +sendSynchronousRequest:returningResponse:error:. Of course, as with -initWithContentsOfURL: you’d use this replacement method in a background thread to maintain UI responsiveness.

You’d have to write a reimplementation of -initWithContentsOfURL: because the first place you can change this is NSURLRequest, or more specifically, its mutable variant NSMutableURLRequest, using the -setValue:forHTTPHeaderField:. But, if you have tons of code, you probably can’t easily change it to use the new method.

So I dug in and, with a few smart tricks (such as feeding a broken non-NSURL as a NSURL to figure out which methods get called, then implementing them as necessary), I figured out which of several ways for fetching web content is actually used in NSString‘s implementation of -initWithContentsOfURL:. These could have been NSURLConnection or some low level messing with CFNetwork.

It turned out not to matter since NSURLRequest is generated out of the NSURL passed to the method. Customizing the user agent turned out to be just a matter of taking all NSURLRequests, forcing them to become mutable copies in form of instances of NSMutableURLRequest during the initializer and setting the user agent at that time. Specific initializer appearing in iOS implementation used in iOS 5 Simulator that ships with Xcode 4.2.1 appears to be -initWithURL:cachePolicy:timeoutInterval:.

It’s an enormous hack, but I decided to simply swizzle this method out. Swizzling NSURLConnection‘s class method +sendSynchronousRequest:returningResponse:error: did not appear to work – the original method still got called despite my best efforts to figure out what went wrong with swizzling, so I gave up on it. If you can see a mistake in my class swizzling code, please tell me about it in the comments section below.

I definitely have no idea whether or not your app will be rejected for this, but from what I know, method swizzling is not illegal.

//  NSURLRequest+UserAgentFix.m

#define YOUR_USER_AGENT @"Your User Agent"
#import "NSURLRequest+UserAgentFix.h"
#import "NSObject+ISSwizzling.h"
@implementation NSURLRequest (UserAgentFix)
+(void)load
{
    [self swizzleMethod:@selector(initWithURL:cachePolicy:timeoutInterval:)
             withMethod:@selector(initWithURL2:cachePolicy:timeoutInterval:)];
}
-(id)initWithURL2:(NSURL *)URL cachePolicy:(NSURLRequestCachePolicy)cachePolicy timeoutInterval:(NSTimeInterval)timeoutInterval
{
    self = [self initWithURL2:URL cachePolicy:cachePolicy timeoutInterval:timeoutInterval];
    
    if(!self)
        return nil;
    
    if([self class] == [NSURLRequest class])
        self = [self mutableCopy];
    
    if([self class] == [NSMutableURLRequest class])
    {
        NSMutableURLRequest * req = self;
        [req setValue:YOUR_USER_AGENT forHTTPHeaderField:@"User-Agent"];
    }
    
    return self;
}
@end

// NSURLRequest+UserAgentFix.h

#import 

@interface NSURLRequest (UserAgentFix)

@end
// NSObject+ISSwizzling.h

#import 

@interface NSObject (ISSwizzling)
+ (BOOL)swizzleMethod:(SEL)origSelector withMethod:(SEL)newSelector;
+ (BOOL)swizzleClassMethod:(SEL)origSelector withMethod:(SEL)newSelector;

@end
// NSObject+ISSwizzling.m

#import 
#import "NSObject+ISSwizzling.h"

@implementation NSObject (ISSwizzling)
+ (BOOL)swizzleMethod:(SEL)origSelector withMethod:(SEL)newSelector
{
    Method origMethod = class_getInstanceMethod(self, origSelector);
    Method newMethod = class_getInstanceMethod(self, newSelector);
    
    if (origMethod && newMethod) {
        if (class_addMethod(self, origSelector, method_getImplementation(newMethod), method_getTypeEncoding(newMethod))) {
            class_replaceMethod(self, newSelector, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
        } else {
            method_exchangeImplementations(origMethod, newMethod);
        }
        return YES;
    }
    return NO;
}
+ (BOOL)swizzleClassMethod:(SEL)origSelector withMethod:(SEL)newSelector
{
    Method origMethod = class_getClassMethod(self, origSelector);
    Method newMethod = class_getClassMethod(self, newSelector);
    
    Class class = object_getClass((id)self);

    if (origMethod && newMethod) {
        if (class_addMethod(class, origSelector, method_getImplementation(newMethod), method_getTypeEncoding(newMethod))) {
            class_replaceMethod(class, newSelector, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
        } else {
            method_exchangeImplementations(origMethod, newMethod);
        }
        return YES;
    }
    return NO;
}

@end

Tested on iOS 5 Simulator with NSString‘s +stringWithContentsOfURL:.

Why GNU/Linux is not successful on desktops

I used Debian for a long time. I used it as a desktop OS. I did a lot of development and tinkering. I don’t have time for tinkering anymore, and I was lucky enough to get a Mac.

I was inspired to write this short outline of my views why GNU/Linux is, sadly, not right for an average user on the desktop, by a tweet from @ivan_gustin (retweeted by @ambivalentcase) that mentioned Linus Torvalds’ thoughts on the same subject from LinuxCon Europe 2011.

Let me point out: I WANT STRONG LINUX. I want freedom, I want power. What I don’t want is ground slipping below my feet.

Technical issues

Torvalds is spot on here. You can’t give the end-user a machine that might or might not work. Things are extremely improved here, and were already good back in 2006.

Greatest issue, however, are regressions and constant feeling of land moving under user’s feet. I can’t in good faith press that “update” button and be nearly certain that the machine will work after the update is performed. Ubuntu is doing very well here if you update within the same release. Next release may or may not work. However, I have had almost no upgrade of a graphics card driver that didn’t require some sort of tinkering in console afterwards and messing with Xorg.conf.

Linux is awesome because it recognizes almost every piece of software that you throw at it.

User interface keeps changing

Look at OS X Tiger. Then look at OS X Leopard. Then look at OS X Snow Leopard. Then look at OS X Lion.

If you go from one version to the next one, you get the user experience that is different, but not very different. Apart from performance issues, what was a major adoption blocker for Windows Vista? A radical reworking of the UI.

People don’t like changes to UI that are forced on them. If I just want, for example, a better mail client that let’s-say comes with Ubuntu 11.04, why am I expected to get used to Ubuntu Unity? If I just want the terminal to keep working and be improved, why do the GNOME team force me to upgrade not just the terminal, but the entire desktop, if I want a complete and integrated user experience? Oh, and that new desktop environment in GNOME 3 is, of course, completely different from GNOME 2.

And GNOME 3 and Ubuntu Unity are just reruns of the KDE 4 saga.

KDE 4 decided to make everything modular. GNOME 3 and Ubuntu Unity decided to develop a UI that is usable on both tablets and desktops. What happens next? Someone bright decides that desktop users must use a media center-like interface?

Features that disappear

I really don’t like it when a package suddenly gets removed from Debian. Remember XMMS? A beautiful clone of Winamp whose only flaw was that it was written with GTK1. Someone thought it was a good idea to rewrite it as a server that plays the music, and a client that controls the playing and called this XMMS2. End-user’s client was, of course, seriously flawed and buggy, and its only boon was that it was written with GTK2. (That didn’t help it, because it was unskinnable and it was ugly.) Debian removed original XMMS because it was “unmaintained”. Great move!

Same thing happened to BitchX. Users who realized this were directed to use other command line IRC clients, such as irssi, which is far less usable and far uglier. At least to me.

Things changing, changing, changing, moving around, breaking down

I’m not exactly a kid anymore. I don’t have time or will to continuously tinker with stuff I already tinkered with. I just want things to work.

I don’t want to worry about packages conflicting.
I don’t want to worry that after an upgrade, a package will be removed due to a conflict.
I don’t want to worry that after an upgrade, my graphics card and my wireless card suddenly stop working because, hey, the kernel was upgraded and previously installed modules no longer work with the new kernel.
I don’t want to worry that after an upgrade, I will have to relearn basically everything because some dimwit decided to “fix” what was not broken: the previously extremely usable UI.
I don’t want to worry that after an upgrade, no icons appear on my desktop.

Applications and features

Hello. Meet my friend, Anna. She’s a graphics artist. She heavily uses Photoshop on a Mac. She needs, at the very least, effects applied on layers. She also needs to work with other designers’ PSD files.

What option does she have on Linux? GIMP? Seriously?

I can use GIMP. I like GIMP. Unfortunately, Anna cannot.

Hello. Meet aunt Silvia. She’s a 60 year old woman taught to work with Microsoft’s Word 2007 for Windows.

Can she use either Word for Mac, or OpenOffice? Let me tell you, she cannot.

You cannot force her to use it. She does not want to learn, even if she will pirate the software. (She does not understand that your refusal to install pirated Windows and Office is a moral choice. She will think you are a jerk.)

Hello. Meet Tom. Tom writes a lot of documentation. Tom got used to one thing that Macs do really well: drag and drop. He grabs almost anything, drags it, presses F3 to show Exposé, points to a window, presses space so he doesn’t have to wait for the window to be zoomed into, and drops it.

It works great with, for example, word processing.

Screenshotting is also nice. Keyboard shortcut is extremely nasty and unergonomic, but being able to get any portion of a screen, or a nice image of a window (complete with a shadow) is just a few keytaps away, and it’s integrated into what would be a “window manager” under GNU/Linux or other X11 environments. You can easily get the screenshot in a file on the desktop, or you can get it into the clipboard for quick pasting into the mail client.

And under GNU/Linux, you have to worry if dragging-and-dropping, copying-and-pasting will even work between programs under same desktop environment — situation is way worse when you have to do content exchange between different environments. Can I be sure that an image put into clipboard under Konqueror will be pasteable into GIMP or Thunderbird?

Exposé doesn’t seem useful until you realize how useful it is with drag-drop, especially when you press space. I can’t remember any use for desktop cube effect except that it made me feel warm deep inside. (Yep, I still love desktop cube. Sometimes I perform ‘switch user’ on OS X just to watch the default desktop cube animation.)

Hello. Meet me. I’m a developer, and what I’m about to say is unfair. I love Objective-C. I love the concept of building the UI in an Interface Builder. I don’t need Objective-C per se, as long as I can use similar software building practices.

Java seems awfully close.

Except it isn’t. It’s static and restrictive where it shouldn’t be.

GNUstep folks are great, and they’re doing great job. But they don’t really have the resources to build a good IDE, nor prepare good introduction for new Objective-C developers. C++ developers have the very nice Code::Blocks/, which is wonderful, until you need to develop a GUI app.

I also want to sell my software. I love doing free software/open source work, but sometimes a person has to live off something. My end users expect good quality packaging, an easy to install app, and support that will last even if I don’t update the app manually. Developer portal for Ubuntu is an excellent step forward for distribution, but building a quality .deb package is still difficult. Intel’s AppUp is confusing and little-known. I’m also from Croatia — can you folks send me cash to my country? (AppUp had issues with that — or so I’m told.)

Hello. Meet Harry. He’s a 14-year old gamer who wants to play StarCraft II, Call of Duty: Modern Warfare 2 and Portal 2.

I’ve had mostly bad experiences with Wine. Sure, you can play singleplayer original StarCraft. You can even play it in multiplayer! However, what if something goes wrong? Also, have you tried playing using Battle.net?

Have you tried playing Rise of Nations? Have you tried any other old title that uses DirectPlay? Did you see how many titles work, but their installers don’t work?

What happens when Harry’s graphics card drivers don’t start? Does he want to worry whether or not he may update nVidia’s drivers? Does he want to worry where the installer will put the launch icons? What happens when the .desktop file (the shortcut for launching apps) doesn’t work? I can probably get the title to work with Wine, but will Harry be able to?

And let me tell you, Harry won’t be happy when the 60 EUR game he just bought doesn’t work and he has to tinker with the computer to get it to run.

Conclusion

Who is GNU/Linux for?

Enthusiasts and people who use computers only for Skype, surfing, mail.

That’s not the massive user base that pushes the desktops and desktop usage forward. User base that pushes desktops and desktop usage forward are home power users, gamers, business users, artists, developers. Even a person who can do word processing with one package cannot use it with another these days.

And you know what “people who use computers only for Skype, surfing, mail” can use?

A tablet or (shudder) a netbook.

Either an Android tablet, an iPad or a Chromebook will do for them.

Solution

* Stabilize the UI. (Apple faced backlash for its reworking of scrollbars.)
* Be careful before making drastic incompatibility moves. (Apple faced backlash for removing Rosetta, breaking TurboTax 2007.)
* Stabilize the ABI. (Apple often ships very old versions of libraries. Removing Rosetta allowed removal of old PowerPC-only code.)
* Help the developers. (You are a free software enthusiast and that’s fine. But don’t think everyone is. If I want to ship paid software, and I have a market, don’t lock me out.)

Don’t break stuff, don’t change stuff. Help the dev.

I admire Linux Game Publishing‘s struggle in face of licensing issues (for example, SDL’s LGPL), in face of incompatibility, in face of historic disregard for ABI. It’s difficult to package executables that are easily relocatable to different places in the filesystem – because, since the software is open source, you can simply recompile the program for the new location. (Dependency on dynamic libraries put in fixed locations is the biggest issue.)

Avoiding memory leak in OpenAL and crash in OpenAL for Mac

UPDATE: We’re still seeing the crash on Mac. Procedure described does fix the memory leak, though.

UPDATE 2: Crash on Mac is caused by what appears to be a bug in Apple’s code relating to queueing commands for execution on dedicated audio thread, and mutex lock breaking down. Since mutex lock seems to stop working, it’s only natural that a threading-related crash occurs.


When calling alSourceStop(), you might forget to unbind a buffer from the source. Did you unbind it?

alSourcei(this->sourceId, AL_BUFFER, AL_NONE);

If you get a crash on Mac with call stack containing OALSource::Play() and/or ending with OALSource::PrepBufferQueueForPlayback(), this is most probably a good fix. Looks like OpenAL on Mac might have a race condition somewhere unless you do this.

See difference between revision 293 and 294 in libxal, in file audiosystems/OpenAL/OpenAL_Player.cpp.

Why software isn’t free

TUAW has a nice post talking about why software is not free, and in fact linking to this simple list of why it is so. TUAW is also worried about iOS lowering software prices.

As a user, I like that. As a developer, I don’t. By buying software, you’re not losing money, you’re helping honest people keep doing what they do. Don’t look at software (especially games!) and think: “Why the hell does this app cost $0.99? It sucks!” $0.99 is cheap. $4.99 is cheap! You’re paying more for stuff you consume daily and which take very little time to produce. How about paying $0.99 for that game that probably took a few months to create?

Getting Objective-C 2.0 to work on Debian’s GNUstep with clang

If you are a Cocoa or Cocoa Touch developer, you may have attempted to use features such as properties in GNUstep, only to be surprised that these don’t seem to be supported. This is because these are Objective-C 2.0 features.

To get the new features, the only way is to use a different compiler called clang. You may have seen this compiler used in newer releases of Xcode. This is a compiler that targets a virtual machine called LLVM before producing native code.

UPDATE May 4th 2011: GCC 4.6 has got the Objective-C 2.0 treatment, and since Debian includes GCC 4.6, I’d recommend you to try compiling your software that way. Not because it’s a better compiler — I have no idea which one works better — but because it’s there. Also, consider compiling GNUstep from trunk using GCC 4.6; it’s rather easy to do. (CC=gcc-4.6 ./configure, whenever compiling a component of GNUstep).

Let’s presume you managed to run an Objective-C program with GNUstep; that is, let’s presume you are aware of Project Center, or GNUmakefiles. If you are didn’t use GNUmakefiles, you should know that Project Center generates these in order to build your app.

Now you want to switch to clang, and you want to do so on your favorite operating system, Debian GNU/Linux.
Continue reading

Getting started with Objective-C?

If you want to get started with Objective-C, and you have some background in C/C++, read this neat post I randomly stumbled upon: “Why Objective-C is cool“. It’s a pretty nice description and hopefully removes a lot of WTFs from a newbie.

Then, read CocoaLab‘s free e-book “Become an Xcoder“.

Finally, this is the longest route, but the one I went with: watch all 18 hours + extras of CS193P iPhone Application Development 2009 (and then go watch some of the 2010 lessons, too). It takes a long time to watch, but it’s worth it.