I have been banging my head against this problem for the last couple weeks. I was updating a project originally coded in Xcode 4.01 for iOS 4. I was doing the update in Xcode 4.2 and mostly running the app on iOS 5 devices and simulators. Then I noticed that if I ran the app on an iOS 4.x device or simulator that a lot of the UILabel objects in my app were not showing up in the UI. Super strange. Super frustrating.
For some reason the UILabel font property of some of the labels I was using had to be set to System in IB. Once I did that my labels showed up again and all was good.
I’ve been scratching my head most of the day trying to figure out why I was able to authorize with Twitter perfectly fine in my app running on pre-iOS 5 software but not in iOS 5. There are quite a few complaints about this on the Twitter dev site and someone has even filed a bug against the Twitter API but I think I just found a solution.
First of all, what this issue looks like to the user is that when they try to login to Twitter from the web view in your app they get the following message:
“Woah there!
This page is no longer valid. It looks like someone already used the token information you provided. Please return to the site that sent you to this page and try again … it was probably an honest mistake.”
I discovered that in SA_OAuthTwitterEnging the method fetchDataWithRequest:delegate:didFinishSelector:didFailSelector: was failing and calling outhTicketFailed: and got this info in the console:
Error Domain=NSURLErrorDomain Code=-1012 "The operation couldn\u2019t be completed.
(NSURLErrorDomain error -1012.)" UserInfo=0x93cf030
{NSErrorFailingURLKey=http://twitter.com/oauth/access_token,
NSErrorFailingURLStringKey=http://twitter.com/oauth/access_token,
NSUnderlyingError=0x93cef20 "The operation couldn\u2019t be completed.
(kCFErrorDomainCFNetwork error -1012.)"}
Which led me to those URLs which are defined in SA_OAuthTwtterEngine.m. The URLs for request_token, access_token and authorize need to be updated to use https instead of plain old http. You will find these in the initOAuthWithDelegate method. These work fine as is with iOS versions prior to 5 but for iOS 5 they need to use https.
If you are getting the following Xcode build error then this post is for you:
warning: iPhone apps should include an armv6 architecture (current ARCHS = “armv7″)
iOS apps prior to 4.3 use the armv6 architecture and will run on 3G and later iOS devices including iPhone 3G, 3GS, 4, iPad 3.2, and iPad 4.2 whereas iOS 4.3 and later apps use the armv6 or armv7 architectures. If your app has a deployment target less than iOS 4.3 and you have not included the armv6 architecture then you will get this build error.
To remedy this do the following:
1. Click on your project in the Groups and Files pane on the left and select your project on the right (above your target).
2. Click on the Build Settings tab and then look at the Architectures group in the list of settings.
3. Next, you need to edit this setting so that it includes both armv6 and armv7. Start by clicking on the setting and choosing Other…
4. Now click the “+” button and enter “armv6″ in the new text field and then select Done.
3. Also make sure that your Base SDK is set to Latest iOS (iOS 5), your Build Active Architecture Only is set to NO and that Valid Architectures is set to “armv6 armv7″.
Here is what it should like when you are done:
Now you should be good to build your project or at least not including armv6 won’t be holding you up anymore.
Some of you may have been scratching your heads as I was today when some of the table views in an app I was working on started showing up with section headers showing that weren’t there previously. It turns out that in iOS 5 your UITableViewDelegate is now required to return zero for tableView:heightForHeaderInSection:
Prior to iOS 5 it didn’t matter what value you returned for this method. As long as you returned nil for tableView:viewForHeaderInSection: you wouldn’t get a section header. Now you need to explicitly set the height to zero if you don’t want a section header. This may require some logic similar to what you might have done if you have ever had to make a table view with different row heights.
It isn’t a big change but it could be a small gotcha for people as they start coding iOS 5 apps. Hope this is a useful tip.
The Wub Machine takes any piece of audio as input and spits out either a dubstep or an electro version. The project is available on GitHub or as a web app though it seems the web app has fallen due to too much traffic. Here is an example of what The Wub Machine did to Ob-La-Di, Ob-La-Da by the Beatles:
Here is how Peter Sobot describes his project and the tech he used to build it:
–
“The Wub Machine was a great little auto-remixer project – some audio hackery in Python to make a neat script. Unfortunately, I can probably count on one hand the number of people who *actually* downloaded the script and tried it on their own songs. So, I decided to make it into a web app.
I opened up my trusty Photoshop, cranked out some multicoloured waves and set “The Wub Machine” in beautiful Proxima Nova. Then I set about the immense task of actually implementing the remixer on the web.
I’d go into the technical impressiveness of the system, and how it’s brilliant and took me months to come up with… but it’s really not. It’s one big hack.
I ended up using:
PHP to serve the front-end, as well as serve the AJAX progress updates and interface with SoundCloud
Python to power and tie together all of the processing on the back-end
The Echo Nest Remix API to do the heavy lifting, audio analysis and beat detection
FFMPEG to decode & encode the MP3s
Mutagen and PIL to rewrite the MP3′s metadata, extract artwork, overlay a graphic and put it back in to the final MP3
Beanstalkd to queue processing jobs and connect PHP to Python
SQLite3 for logging and some queue intelligence
HTML5 Audio, used for a beautiful HTML5 player (taken from the extremely impressive Neutron Creations blog)
Flash for the fallback player on older browsers
Javascript and jQuery to hold together the very rickety frontend
CSS3 animations, for the moving waves at the top of the page
The SoundCloud API for sharing tracks (without putting me at risk of nasty legal issues or pushing storage constraints)
I did have to make a couple changes to the original algorithm, though:
I realized that audio volume is a nonlinear curve, so I had to account for that and create a new mixing algorithm. The volume of the original track vs. the wubwubs is now almost always about 50%.
I went back into my dubstep template in Logic Pro and added different types of TransitionFX samples to the intro and the wubs – booms, splashes and such. Although I’m still not happy with certain parts of the template, it’ll have to do for now. I’m not a dubstep producer – I’m a rock/metal/electronica/jazz guy. (for now!)
I made the algorithm as deterministic as possible. The remixer is essentially a function (depending on the analysis I get back from the Echo Nest) so if you put in the same song, you should get the exact same remix.
I improved the loudness calculation algorithms, fixed some stupidly-inefficient bugs, killed off a statistically-improbable-but-still-possible infinite loop, added logging, error handling, and progress indicators.
Since my blog post about the initial hack, it’s taken me 3 weeks to assemble this web front end. That said, there’s probably still tons of bugs – it only accepts MP3s at the moment, and it’s probably somewhat unstable. If I push it too hard, or post it to Reddit or Hacker News, my shiny new Linode will probably spontaneously combust. Be gentle!”
–
I had mixed results using the web app, probably because it is getting pounded (the site is actually down as I write this) so I went ahead and downloaded wub-machine from GitHub and installed it on my Mac. There were a fair number of dependencies that I had to install (more than were listed on the GitHub page):
Once I got all the dependencies installed using wub-machine was as easy as:
?> python dubstep.py mysong.mp3
This is an awesome project and I think it is great that Peter has shared the list of tech he used to build it. He also let me know today that he will be doing a full open-source release of the entire site and web front-end in the next week or so.
This week I needed to have a script run on a linux box whenever an email was received by a certain user. The user in my case is just a bot that is taking some action whenever a certain git repo on GitHub receives a push but this solution would work for any user on a *.nix system that needed a script to run when their account receives mail.
So first of all, if you don’t already have a user then create one: (my user will be named “robot”)
?> useradd robot
Then give the user a password with:
?> passwd robot
and enter and confirm your user’s password.
You will need to make sure that your firewall allows Port 25 inbound for incoming mail. To check this use the netstat tool:
If all you see for port 25 is the loopback ip address (127.0.0.1) then you need to append a line to your /etc/sysconfig/iptables file. Yours may look a little different than mine but just look at the other entries in your iptables for guidance. Here is the line I had to add which I basically copied from a different port in my iptables file, just changing the port number to 25.
-A RH-Firewall-1-INPUT -p tcp -m tcp --dport 25 -j ACCEPT
Once that is added you need to save the file and then restart the iptables with:
We now have the loopback and the one from the outside so we are good to go.
With that all squared away, create a .forward file in your home directory and add a line to it that pipes the email to your script:
|/path/to/your/script/yourscript.sh
You also need to set the permissions on the .forward file:
?> chmod 644 .forward
Because Sendmail is restrictive about what it can run you need to add a simlink to your script in /etc/smrsh/ to enable Sendmail to access the script:
?> cd /etc/smrsh
?> ln -s /path/to/your/script/yourscript.sh yourscript.sh
Note that I am using a shell script in this example but you could use a Perl, Python, Ruby, PHP or whatever kind of script you like.
You may also need to edit your /etc/mail/sendmail.cf by finding the line that begins with Mprog and replacing P=/bin/sh with P=/usr/sbin/smrsh
You then need to restart sendmail with:
?> /etc/rc.d/init.d/sendmail restart
You should now be able to test your script by sending an email to your user’s email account. Depending on what you are trying to achieve you will probably want to parse the email with your script and then take some action, but just to test you should do something simple like have your script create a file in your home directory. This will give you a quick indication that everything is working.
Though I still don’t have walls up, I do have the studio insulated and have been coding and making music in it for the last two weeks. The other night I recorded my first jam in the space, appropriately titled ‘Insulated’.
Ableton is being used to sequence and provide some reverb (AudioDamage EOS) and then I’m mixing, tweaking and playing the instruments and effects live. Enjoy.
They claim, “It’s simply the best app on the iPad for controlling all your MIDI gear.”
From the looks of things I would have to agree. White Noise Audio have done an amazing job with this piece of software. It has everything I would expect from a basic MIDI sequencer. I will definitely be testing this out as an alternate centre piece for my hardware setup to use when I have spent too much time on the computer and just want to jam. This should also make a great tool for performing with when you just don’t want a laptop on stage.
Using Genome MIDI Sequencer (GMS), “You can sequence single patterns or an entire 16 track song.” Here is their promotional video:
Here are the features:
CoreMIDI, Line6 Mobilizer Mk I & II compatible
Supports Network MIDI
Sends and Receives MIDI Clock Sync, Start and Stop events
Also sends Note On, Note Off, Pitch Bend, Aftertouch, Channel Pressure and CC’s
Pattern Based, pattern changes occur on bar boundaries so song stays in sync
On screen keyboard interface
Up to 16 simultaneous tracks, unlimited number of patterns
Song / live modes
Record incoming CC’s and Notes
Undo / redo for most actions
GMS is compatible with the Line6 MIDI Mobilizer and any interfaces that support CoreMIDI using the Camera Connection Kit or Network MIDI. Network MIDI allows you to send events to your Mac Desktop or to other iOS devices and apps.
I recently needed to create a vertically scrolling UIScrollView with a child sub view on which I needed to capture touches. Working with this kind of layering of views and the responder chain can be tricky but it is not as difficult as it first appears. If you are unfamiliar with the responder chain in iOS I recommend the Apple documentation on the subject available here.
For this example lets say we have a UIScrollView that is the size of the screen, and inside of the scroll view we add a sub view; say a UIView that is 300 pixels wide by 200 pixels high. We want the scroll view to scroll vertically up and down when the user drags their finger anywhere outside of the sub view, but if the user touches inside of the sub view we want it to process the touches, not the scroll view.
The way to do this is to have the scroll view be a custom subclass of UIScrollView so that we can add some code to intercept the touches on it and thus control the behaviour as we see fit. To create the sub class in Xcode, Control-click in the Navigator and choose New File… then choose Objective-C Class and make it a sub class of UIScrollView. I named mine CustomScrollView.
In the header of the new CustomScrollView class add a CGRect property. This is what will define the area of the sub view in the scroll view. We will use this later to turn off scrolling when the touches are in our sub view. Your header should look like this:
After your basic initWithFrame: method we add the three touch responder methods: touchesBegan:withEvent:, touchesMoved:withEvent: and touchesEnded:withEvent. Any time a touch happens on the scroll view, then these methods will be called on the CustomScrollView object as part of the responder chain. Because UIScrollView uses gesture recognizers under the hood, and UIGestureRecognizer objects are not in the responder chain, we are safe to just pass these methods on to the next responder.
That is what the method call in each of these is doing. We are telling the touches received on the scroll view to pass themselves along to the next responder which will be the controller of our sub view. In that controller that owns the sub view, wether a custom NSObject based controller or a UIViewController, you will want to implement each of these three methods which will now be called on it. This is where you do whatever it is you want to do with the touches.
When you are implementing those you will want to make sure that the touches you are processing are actually in your sub view. You can do that by including the following check in each of the touch methods:
if (CGRectContainsPoint([[self yourSubView] frame], [[touches anyObject] locationInView:[[self yourScrollView] view]])) {
/* your touch handling code goes here */
}
There is one more thing we need to deal with if you don’t want the scroll view to be able to scroll while you touch your sub view. That is what the subViewRect property is for. In your controller you need to set the subViewRect to the frame of your sub view:
Now every time the scroll view receives a touch we check if the touch is in the sub view that we want to capture the touches. If it is then we disable the scroll view’s ability to scroll. If the touch is not in the sub view then we enable the scroll view’s ability to scroll.
And that should be that. Working with views inside of scroll views can sometimes be frustrating but hopefully this gives you a bit of a leg up the next time you need do it.