[{"data":1,"prerenderedAt":5292},["ShallowReactive",2],{"article_list_ios_":3},[4,408,684,2979,3157,5094,5152],{"_path":5,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":9,"description":10,"publishDate":11,"image":12,"tags":13,"excerpt":10,"body":18,"_type":399,"_id":400,"_source":401,"_file":402,"_stem":403,"_extension":404,"author":405},"/jbagley/2025-08/a_developers_primer_on_apple_tracking_transparency","2025-08",false,"","A Primer on Apple's App Tracking Transparency","If an app tracks user activity, Apple requires them to declare all information they collect as well as whether that data is linked or tracked. This includes collection by the app itself and any third parties the app uses. The app owner is responsible for knowing and correctly reporting privacy information for all components in the app.","2026-05-22","/jbagley/2025-08/img/apple_app_transparency.png",[14,15,16,17],"app tracking transparency","att","ios","macos",{"type":19,"children":20,"toc":386},"root",[21,30,48,53,58,65,75,85,95,104,120,126,138,143,149,171,176,181,187,193,198,203,209,217,234,249,262,268,273,284,297,302,317,323,328,342,348,361,366,372],{"type":22,"tag":23,"props":24,"children":26},"element","h1",{"id":25},"overview",[27],{"type":28,"value":29},"text","Overview",{"type":22,"tag":31,"props":32,"children":33},"p",{},[34,36,46],{"type":28,"value":35},"If an app tracks user activity, Apple requires them to declare ",{"type":22,"tag":37,"props":38,"children":39},"em",{},[40],{"type":22,"tag":41,"props":42,"children":43},"strong",{},[44],{"type":28,"value":45},"all",{"type":28,"value":47}," information they collect as well as whether that data is linked or tracked. This includes collection by the app itself and any third parties the app uses. The app owner is responsible for knowing and correctly reporting privacy information for all components in the app.",{"type":22,"tag":31,"props":49,"children":50},{},[51],{"type":28,"value":52},"The information is declared in two places, the Privacy Nutrition Label shown with the app in the App Store, and a privacy manifest the app carries. If an app will be tracking users, it must request permission to do so from the user.",{"type":22,"tag":31,"props":54,"children":55},{},[56],{"type":28,"value":57},"Collectively these requirements and practices are known as App Tracking Transparency (ATT).",{"type":22,"tag":59,"props":60,"children":62},"h2",{"id":61},"terms",[63],{"type":28,"value":64},"Terms",{"type":22,"tag":31,"props":66,"children":67},{},[68,73],{"type":22,"tag":41,"props":69,"children":70},{},[71],{"type":28,"value":72},"Collecting",{"type":28,"value":74}," information is storing information for longer than it is needed to perform whatever function generated or required the information. For example, even server logs might be considered collecting.",{"type":22,"tag":31,"props":76,"children":77},{},[78,83],{"type":22,"tag":41,"props":79,"children":80},{},[81],{"type":28,"value":82},"Linking",{"type":28,"value":84}," is connecting the collected data to a specific user in some way.",{"type":22,"tag":31,"props":86,"children":87},{},[88,93],{"type":22,"tag":41,"props":89,"children":90},{},[91],{"type":28,"value":92},"Tracking",{"type":28,"value":94}," is",{"type":22,"tag":96,"props":97,"children":98},"blockquote",{},[99],{"type":22,"tag":31,"props":100,"children":101},{},[102],{"type":28,"value":103},"\"aggregating linked data from one or more sources to build up some profile of a specific user that potentially can be combined with information form other sources to target a user for advertising or tracking advertising performance.\"",{"type":22,"tag":31,"props":105,"children":106},{},[107,109,118],{"type":28,"value":108},"(From ",{"type":22,"tag":110,"props":111,"children":115},"a",{"href":112,"rel":113},"https://developer.apple.com/app-store/user-privacy-and-data-use/",[114],"nofollow",[116],{"type":28,"value":117},"Apple's privacy and data use documentation",{"type":28,"value":119},".)",{"type":22,"tag":59,"props":121,"children":123},{"id":122},"concerns",[124],{"type":28,"value":125},"Concerns",{"type":22,"tag":31,"props":127,"children":128},{},[129,131,136],{"type":28,"value":130},"Determining what to include in these privacy declarations takes all parties. The organization that owns the app ",{"type":22,"tag":37,"props":132,"children":133},{},[134],{"type":28,"value":135},"and their legal counsel",{"type":28,"value":137}," should review the information. What the app declares should match the organization's posted privacy policy, of course.",{"type":22,"tag":31,"props":139,"children":140},{},[141],{"type":28,"value":142},"Code reviews should be done to determine how information is being used and the privacy implications. This might involve reviewing logging and database schemas as well as reviewing where data is transmitted. If a third party performs any data collecting, their privacy statements and manifests should be reviewed.",{"type":22,"tag":23,"props":144,"children":146},{"id":145},"privacy-nutrition-label",[147],{"type":28,"value":148},"Privacy Nutrition Label",{"type":22,"tag":31,"props":150,"children":151},{},[152,154,161,163,169],{"type":28,"value":153},"In 2020 Apple introduced the Privacy Nutrition Label. They are created using App Store Connect. In the ",{"type":22,"tag":155,"props":156,"children":158},"code",{"className":157},[],[159],{"type":28,"value":160},"App Store > TRUST & SAFETY > App Privacy",{"type":28,"value":162}," section under the ",{"type":22,"tag":155,"props":164,"children":166},{"className":165},[],[167],{"type":28,"value":168},"Distribution",{"type":28,"value":170}," tab, Apple provides a UI for creating the label.",{"type":22,"tag":31,"props":172,"children":173},{},[174],{"type":28,"value":175},"I don't recommend starting with this. Instead, create the privacy manifest because it is seen as the ground truth by Apple. After the privacy manifest exists, Xcode can provide a privacy report for your app that makes this easier.",{"type":22,"tag":31,"props":177,"children":178},{},[179],{"type":28,"value":180},"One quirk to mention is that changes to the Privacy Nutrition Label go live on the App Store immediately, so there could be discrepancies when submitting a new version.",{"type":22,"tag":182,"props":183,"children":184},"aside",{},[185],{"type":28,"value":186},"\n*I don't understand why Apple does not automatically populate this from the submitted app's privacy manifest files.*\n",{"type":22,"tag":23,"props":188,"children":190},{"id":189},"tracking-permission",[191],{"type":28,"value":192},"Tracking Permission",{"type":22,"tag":31,"props":194,"children":195},{},[196],{"type":28,"value":197},"In 2021, Apple added the requirement for requesting permission from the user to allow tracking. If the user does not agree, then it is up to the app to make sure no tracking occurs by it or any third party libraries it uses.",{"type":22,"tag":31,"props":199,"children":200},{},[201],{"type":28,"value":202},"Keep in mind that users disable allowing tracking in their OS settings; meaning they will never see a request for permission, and any queries for the permission will return a value meaning not permitted.",{"type":22,"tag":23,"props":204,"children":206},{"id":205},"privacy-manifests",[207],{"type":28,"value":208},"Privacy Manifests",{"type":22,"tag":96,"props":210,"children":211},{},[212],{"type":22,"tag":31,"props":213,"children":214},{},[215],{"type":28,"value":216},"\"A privacy manifest is a property list file (PrivacyInfo.xcprivacy) that you add to your target’s resources. The privacy manifest describes the privacy practices of an app or third-party SDK.\"",{"type":22,"tag":218,"props":219,"children":220},"ul",{},[221],{"type":22,"tag":222,"props":223,"children":224},"li",{},[225,227],{"type":28,"value":226},"From ",{"type":22,"tag":110,"props":228,"children":231},{"href":229,"rel":230},"https://developer.apple.com/documentation/bundleresources/adding-a-privacy-manifest-to-your-app-or-third-party-sdk",[114],[232],{"type":28,"value":233},"Apple's documentation for adding a privacy manifest",{"type":22,"tag":31,"props":235,"children":236},{},[237,239,247],{"type":28,"value":238},"In 2023 Apple introduced privacy manifests, and in 2024 it ",{"type":22,"tag":110,"props":240,"children":244},{"href":241,"rel":242,"title":243},"https://developer.apple.com/news/?id=pvszzano",[114],"Apple's reminder for privacy changes",[245],{"type":28,"value":246},"started to require them",{"type":28,"value":248}," in apps submitted to the App Store.",{"type":22,"tag":31,"props":250,"children":251},{},[252,254,260],{"type":28,"value":253},"Xcode also provides an editor that has the relevant keys and values like it does for the ",{"type":22,"tag":155,"props":255,"children":257},{"className":256},[],[258],{"type":28,"value":259},"info.plist",{"type":28,"value":261}," format.",{"type":22,"tag":59,"props":263,"children":265},{"id":264},"generating-the-manifest",[266],{"type":28,"value":267},"Generating the manifest",{"type":22,"tag":31,"props":269,"children":270},{},[271],{"type":28,"value":272},"Create a privacy manifest using",{"type":22,"tag":274,"props":275,"children":279},"pre",{"className":276,"code":278,"language":28},[277],"language-text","New > File from template...\n",[280],{"type":22,"tag":155,"props":281,"children":282},{"__ignoreMap":8},[283],{"type":28,"value":278},{"type":22,"tag":31,"props":285,"children":286},{},[287,289,295],{"type":28,"value":288},"and choose the template ",{"type":22,"tag":155,"props":290,"children":292},{"className":291},[],[293],{"type":28,"value":294},"App Privacy",{"type":28,"value":296},".",{"type":22,"tag":31,"props":298,"children":299},{},[300],{"type":28,"value":301},"It's then a painstaking, manual process to input what data is collected and how it is used. Referring to the app's privacy policy statement if it already exists is the best way to populate this file. Ideally, the organizational review and code reviews will have been done by the time you create this.",{"type":22,"tag":182,"props":303,"children":304},{},[305,312],{"type":22,"tag":306,"props":307,"children":309},"h3",{"id":308},"third-party-software",[310],{"type":28,"value":311},"Third Party Software",{"type":22,"tag":31,"props":313,"children":314},{},[315],{"type":28,"value":316},"Apple encourages library providers to include privacy manifest files. Some that Apple considers critical to privacy–like Firebase, Meta or Branch–are required to as well as being signed. I found every library my app uses to be compliant, but you should be aware of it.",{"type":22,"tag":59,"props":318,"children":320},{"id":319},"tracking-domains",[321],{"type":28,"value":322},"Tracking Domains",{"type":22,"tag":31,"props":324,"children":325},{},[326],{"type":28,"value":327},"The manifest's tracking domain section lets you black list some domains used for tracking. This is a fail-safe to prevent tracking if the user has not agreed to it. These domains will be blocked automatically when the user does not want to be tracked.",{"type":22,"tag":182,"props":329,"children":330},{},[331,337],{"type":22,"tag":306,"props":332,"children":334},{"id":333},"verifying",[335],{"type":28,"value":336},"Verifying",{"type":22,"tag":31,"props":338,"children":339},{},[340],{"type":28,"value":341},"Xcode's Instruments can build a profile of network connections during an app run, allowing you to verify which domains your app contacts.",{"type":22,"tag":59,"props":343,"children":345},{"id":344},"checking-your-work",[346],{"type":28,"value":347},"Checking your work",{"type":22,"tag":31,"props":349,"children":350},{},[351,353,359],{"type":28,"value":352},"To see your app's privacy manifest in a user friendly way, use Xcode Organizer. Generate an archive build, then right click on the arvie in the Organizer and select ",{"type":22,"tag":155,"props":354,"children":356},{"className":355},[],[357],{"type":28,"value":358},"Generate Privacy Report",{"type":28,"value":360},". This creates a PDF with the information about data types collected and how they are used. It will include the third party privacy manifests information.",{"type":22,"tag":31,"props":362,"children":363},{},[364],{"type":28,"value":365},"Now use this report to create the Privacy Nutrition Label in App Store Connect.",{"type":22,"tag":23,"props":367,"children":369},{"id":368},"conclusion",[370],{"type":28,"value":371},"Conclusion",{"type":22,"tag":31,"props":373,"children":374},{},[375,377,384],{"type":28,"value":376},"Hopefully this primer will keep your head from spinning too much when you get more into ",{"type":22,"tag":110,"props":378,"children":381},{"href":379,"rel":380},"https://developer.apple.com/app-store/app-privacy-details/",[114],[382],{"type":28,"value":383},"Apple's comprehensive overview",{"type":28,"value":385},". Good luck!",{"title":8,"searchDepth":387,"depth":387,"links":388},3,[389,391,392,395,398],{"id":61,"depth":390,"text":64},2,{"id":122,"depth":390,"text":125},{"id":264,"depth":390,"text":267,"children":393},[394],{"id":308,"depth":387,"text":311},{"id":319,"depth":390,"text":322,"children":396},[397],{"id":333,"depth":387,"text":336},{"id":344,"depth":390,"text":347},"markdown","content:jbagley:2025-08:a_developers_primer_on_apple_tracking_transparency.md","content","jbagley/2025-08/a_developers_primer_on_apple_tracking_transparency.md","jbagley/2025-08/a_developers_primer_on_apple_tracking_transparency","md",{"user":406,"name":407},"jbagley","Jason Bagley",{"_path":409,"_dir":410,"_draft":7,"_partial":7,"_locale":8,"title":411,"description":412,"excerpt":412,"image":413,"publishDate":414,"tags":415,"body":419,"_type":399,"_id":678,"_source":401,"_file":679,"_stem":680,"_extension":404,"author":681},"/asherbrooke/2020-4/watchwah","2020-4","Bringing an Idea to Life: WatchWah Proof of Concept","\"Wouldn't it be cool if...\"","/asherbrooke/2020-4/img/Guitar_and_Watch.jpeg","2020-04-01",[16,416,417,418],"apple","watch","juce",{"type":19,"children":420,"toc":669},[421,428,433,439,444,449,476,481,487,492,497,502,508,522,534,539,545,550,556,561,575,580,585,590,595,600,606,620,625,639,661],{"type":22,"tag":31,"props":422,"children":423},{},[424],{"type":22,"tag":37,"props":425,"children":426},{},[427],{"type":28,"value":412},{"type":22,"tag":31,"props":429,"children":430},{},[431],{"type":28,"value":432},"We've all had that thought about something. How do you get from there to a product you can use and share with others? When I found myself playing with an idea that seemed exciting and new, I decided to capture some notes on the process, from the perspective of an Engineering Manager at a company that's all about implementing people's creative visions.",{"type":22,"tag":59,"props":434,"children":436},{"id":435},"the-idea",[437],{"type":28,"value":438},"The Idea",{"type":22,"tag":31,"props":440,"children":441},{},[442],{"type":28,"value":443},"In addition to working as Art+Logic's Director of Engineering I've been a performing musician for much of my life. A year ago I bought an Apple Watch and it occurred to me that this small computer, packed with sensors monitoring all sorts of interesting things, could be used to enhance some element of musical expression.",{"type":22,"tag":31,"props":445,"children":446},{},[447],{"type":28,"value":448},"As a professional software developer I've learned that a good idea includes these qualities:",{"type":22,"tag":218,"props":450,"children":451},{},[452,457,462],{"type":22,"tag":222,"props":453,"children":454},{},[455],{"type":28,"value":456},"It needs to spark your passion, or at least get you curious. If it's something you're personally neutral about, but think might make you money, it's much harder to stay with it over the long haul. My idea was fairly simple, and I felt curious enough to spend some time on it.",{"type":22,"tag":222,"props":458,"children":459},{},[460],{"type":28,"value":461},"It's framed generally enough to be resilient as challenges arise. I've seen clients cling to specific details of their projects, at the expense of the product, when a looser conception of their goals might have allowed them to pivot more gracefully. In my case, \"Can I use my watch to enhance my musical performance\" seemed sufficiently general.",{"type":22,"tag":222,"props":463,"children":464},{},[465,467,474],{"type":28,"value":466},"It's been researched enough to know what possible challenges or competitors exist. I found ",{"type":22,"tag":110,"props":468,"children":471},{"href":469,"rel":470},"https://www.synthanatomy.com/2019/02/midiwrist-apple-watch-midi-controller.html",[114],[472],{"type":28,"value":473},"an existing system",{"type":28,"value":475}," that allowed the user to send messages from the Apple Watch to audio applications, but it didn't use the sensors. I was pleased that there wasn't anything quite like my idea that was already available, but also wondered if it might be unexpectedly difficult to implement, since nobody seemed to have done this before.",{"type":22,"tag":31,"props":477,"children":478},{},[479],{"type":28,"value":480},"Interestingly, I'd say \"the idea is possible\" is not always an important question to ask. If it's not possible now it may be in the future, and indeed it's hard to say whether or not something can be done until you try to do it.",{"type":22,"tag":59,"props":482,"children":484},{"id":483},"development",[485],{"type":28,"value":486},"Development",{"type":22,"tag":31,"props":488,"children":489},{},[490],{"type":28,"value":491},"I love the idea of iterative development, and it's something we do a lot of at Art+Logic. With a new and unproven idea it's extremely valuable; how quickly (and cheaply) can you learn if your idea will work, and how can it be refined, step-wise, through experimentation?",{"type":22,"tag":31,"props":493,"children":494},{},[495],{"type":28,"value":496},"My idea seemed to have a few parts: getting sensor data from the watch, bringing that data to a guitar effect to control it's behavior, and then the effect itself. I had a vision of using my watch to control a physical \"stomp-box\" style guitar effects pedal, so I wouldn't need to be tethered to a computer, but to test and refine the basic, big-picture idea that seemed excessive, so I opted for something simpler.",{"type":22,"tag":31,"props":498,"children":499},{},[500],{"type":28,"value":501},"Not only is a fast proof-of-concept a more reasonable business proposition, but it can be hard to sustain the passion for an untested idea over the months it takes to build out a complete solution. Iterative development allows for a whole bunch of successes along the way, which keeps excitement and engagement high. Failures happen too, admittedly, but they're usually cheaper and less disappointing than seeing a lengthy project abandoned. Spoiler alert - there are no major failures in this article!",{"type":22,"tag":306,"props":503,"children":505},{"id":504},"the-watch",[506],{"type":28,"value":507},"The Watch",{"type":22,"tag":31,"props":509,"children":510},{},[511,513,520],{"type":28,"value":512},"A quick search turned up ",{"type":22,"tag":110,"props":514,"children":517},{"href":515,"rel":516},"http://sensorlog.berndthomas.net",[114],[518],{"type":28,"value":519},"SensorLog",{"type":28,"value":521}," for the iPhone and Apple Watch. It's an app that can write sensor data to file, or stream it via a network socket. I even approached testing out this app iteratively - I first logged my data to file to see what the sensor data looked like, so I could make a guess about which sensors might meed my needs, before investing time in reading a live stream of data.",{"type":22,"tag":31,"props":523,"children":524},{},[525,527,532],{"type":28,"value":526},"I had an initial misstep as I learned how to use the app. I was using my iPhone to log what I believed to be watch sensor data. I wiggled my wrist around to generate interesting watch information for the log, but the app was actually monitoring the sensors on the ",{"type":22,"tag":37,"props":528,"children":529},{},[530],{"type":28,"value":531},"phone",{"type":28,"value":533},"! I spent an hour trying to convince myself that I saw meaningful patterns in the accelerometer and other sensor data, when it was all being created by a device sitting motionless upon my table. After discovering my mistake and switching the system over to monitoring the watch I was delighted to find dramatically varying data that clearly correlated with my previous movements. I graphed data in a spreadsheet program from a bunch of different possible sensors, and saw lots of possibilities.",{"type":22,"tag":31,"props":535,"children":536},{},[537],{"type":28,"value":538},"Documenting the process is really valuable. When you're not completely sure what you're going for, having notes about the journey can provide additional options later on. I decided to start with accelerometer data, but added notes to a \"Future\" document, indicating that it might be worth trying the gyro sensor, or other CoreMotion data.",{"type":22,"tag":306,"props":540,"children":542},{"id":541},"the-effect",[543],{"type":28,"value":544},"The Effect",{"type":22,"tag":31,"props":546,"children":547},{},[548],{"type":28,"value":549},"It appeared that the natural movements of my wrist and body were indeed enough for the sensors to output interesting information. That had been my hope, since it meant that a player could add some nuance without having to learn a whole new approach to playing (as with a foot pedal). I decided that the first thing I would try would be controlling a wah effect. This is a movable band pass filter that adds a lot of character and expressiveness to a sound, but can also be relatively subtle and flexible as to when it's applied. In other words even a somewhat random movement of the filter might be kind of interesting. I decided to use my existing recording software (Logic Pro) to process the guitar sound. I set up a Logic project that featured Apple's Fuzz-Wah effect on my guitar channel. While my ultimate goal was to have a standalone effects processor, possibly based on an effect I would write myself, staying focused on testing the basic idea was the priority, and using Logic made this part of the test trivially easy.",{"type":22,"tag":306,"props":551,"children":553},{"id":552},"the-app",[554],{"type":28,"value":555},"The App",{"type":22,"tag":31,"props":557,"children":558},{},[559],{"type":28,"value":560},"The missing link between the watch and the wah effect was some piece of software that could listen for the incoming sensor data and convert it to a form that the wah could understand. MIDI seemed the obvious answer, since Logic has extensive capacity for remote control by MIDI, and standardized formats often provide the greatest flexibility. There was no obvious way to convert socket-based, comma-separated numbers to MIDI (aside from possibly using a fairly expensive 3rd-party product like Max/MSP), so I decided it was time to write some code.",{"type":22,"tag":31,"props":562,"children":563},{},[564,566,573],{"type":28,"value":565},"I've come to really appreciate the ",{"type":22,"tag":110,"props":567,"children":570},{"href":568,"rel":569},"https://juce.com/",[114],[571],{"type":28,"value":572},"JUCE C++ cross-platform development framework",{"type":28,"value":574},", particularly for audio and MIDI work. I consulted a colleague to learn what I might encounter as I set out to write my JUCE MIDI app. I was grateful for the support; it turns out that it's trivially easy to write a \"virtual MIDI port\" app with JUCE on macOS X, and extremely difficult on Windows. Knowing that in advance was great, as it confirmed my initial decision to work on macOS X. And again, as this was a proof-of-concept rather than a commercial product, one platform would be enough for now.",{"type":22,"tag":31,"props":576,"children":577},{},[578],{"type":28,"value":579},"I started with a skeleton MIDI / audio app, adding a slider to send MIDI Continuous Controller messages through a virtual MIDI port, so I could test the app without needing the watch. Within about an hour I was able to open my Logic project, launch my new app, and control the wah effect's \"pedal position\" parameter with the slider in my app.",{"type":22,"tag":31,"props":581,"children":582},{},[583],{"type":28,"value":584},"Adding JUCE's StreamingSocket class allowed me to monitor the port to which the watch would be sending data, wait for a connection, and start reading in values. This happens in a separate thread, and getting the thread performance to acceptable levels took a little fiddling.",{"type":22,"tag":31,"props":586,"children":587},{},[588],{"type":28,"value":589},"The most labor intensive portion came next; parsing the incoming sensor data and converting it to MIDI messages. SensorLog streams CSV values - comma-separated and then further delimited by line feed characters. I broke up the lines of data, and was able to convert the accelerometer readings to float values. Here too the learning was iterative: I was pleased to discover JUCE's NormalisableRange class, which appeared to let me map my accelerometer values to the 0-127 range MIDI requires, then startled when vigorous arm movements caused my program to crash!",{"type":22,"tag":31,"props":591,"children":592},{},[593],{"type":28,"value":594},"The problem was that I hadn't fully understood how the accelerometer values worked. I'd thought they might be ranging from -1.0 to 1.0, based on my cursory observations, but they're actually unbounded; 1.0 simply means acceleration equal to gravity, so quick movements can easily generate three or four times that value. I considered those movements to be outliers, and simply filtered them out. It was hard to imagine I'd be wildly swinging my fretting hand. If Pete Townsend wants this for his right arm, I can expand my range a bit! Accelerometer values also seem to depend upon the orientation within the gravitational field, so the watch at rest reports a non-zero value, and when upside down, a different value; roughly the inverse of the first.",{"type":22,"tag":31,"props":596,"children":597},{},[598],{"type":28,"value":599},"At this point I was ready to test - my iterative process had allowed me to check various components of the project along the way so I had some confidence that it would work pretty well.",{"type":22,"tag":59,"props":601,"children":603},{"id":602},"results",[604],{"type":28,"value":605},"Results",{"type":22,"tag":31,"props":607,"children":608},{},[609],{"type":22,"tag":110,"props":610,"children":613},{"href":611,"rel":612},"https://youtu.be/g5aaT5ytM3Q?si=mJVD1hVN3RHSJTWD",[114],[614],{"type":22,"tag":615,"props":616,"children":619},"img",{"alt":617,"src":618},"Performance","/asherbrooke/2020-4/img/Performance.jpg",[],{"type":22,"tag":31,"props":621,"children":622},{},[623],{"type":28,"value":624},"The results can be seen in the linked videos, and are really exciting to me. After just a few evenings of effort I have a surprisingly musical tool. I see many possible next steps; trying different sensors (possibly simultaneously), using other effects, scaling the controller data in different ways, and simply jamming with it for a while to see how my relationship with the tool evolves. The next steps will also be iterative, and perhaps documented here. I can already see that one challenge will be balancing my urge to keep tweaking against the goal of actually building something that others can use.",{"type":22,"tag":31,"props":626,"children":627},{},[628,630,637],{"type":28,"value":629},"Here's a ",{"type":22,"tag":110,"props":631,"children":634},{"href":632,"rel":633},"https://youtu.be/jTOcGLFNTmo",[114],[635],{"type":28,"value":636},"quick video",{"type":28,"value":638}," of the sensor data changing the sound of a solo guitar.",{"type":22,"tag":31,"props":640,"children":641},{},[642,643,650,652,659],{"type":28,"value":629},{"type":22,"tag":110,"props":644,"children":647},{"href":645,"rel":646},"https://youtu.be/g5aaT5ytM3Q",[114],[648],{"type":28,"value":649},"longer performance demonstration",{"type":28,"value":651},", featuring a song I wrote and recorded ",{"type":22,"tag":110,"props":653,"children":656},{"href":654,"rel":655},"https://youtu.be/Jc-J-T5gQBQ",[114],[657],{"type":28,"value":658},"once before",{"type":28,"value":660}," without the wah effect.",{"type":22,"tag":31,"props":662,"children":663},{},[664],{"type":22,"tag":37,"props":665,"children":666},{},[667],{"type":28,"value":668},"Photos courtesy of the author.",{"title":8,"searchDepth":387,"depth":387,"links":670},[671,672,677],{"id":435,"depth":390,"text":438},{"id":483,"depth":390,"text":486,"children":673},[674,675,676],{"id":504,"depth":387,"text":507},{"id":541,"depth":387,"text":544},{"id":552,"depth":387,"text":555},{"id":602,"depth":390,"text":605},"content:asherbrooke:2020-4:watchwah.md","asherbrooke/2020-4/watchwah.md","asherbrooke/2020-4/watchwah",{"user":682,"name":683},"asherbrooke","Andrew Sherbrooke",{"_path":685,"_dir":686,"_draft":7,"_partial":7,"_locale":8,"title":687,"description":688,"publishDate":689,"tags":690,"image":695,"excerpt":688,"body":696,"_type":399,"_id":2973,"_source":401,"_file":2974,"_stem":2975,"_extension":404,"author":2976},"/nharrison/2012-07/core-data","2012-07","Securing Your Core Data with Transformable Attributes","In order to store private data in an iOS Core Data database, there are several methods available for encryption, including:","2012-07-30",[691,692,16,693,694],"core-data","encryption","security","objective-c","/nharrison/2012-07/img/superman.jpg",{"type":19,"children":697,"toc":2961},[698,702,731,736,742,765,783,802,808,942,948,1688,1699,1704,1709,1744,1750,2203,2235,2245,2258,2263,2269,2301,2339,2365,2396,2401,2410,2415,2421,2945,2950,2955],{"type":22,"tag":31,"props":699,"children":700},{},[701],{"type":28,"value":688},{"type":22,"tag":218,"props":703,"children":704},{},[705,717],{"type":22,"tag":222,"props":706,"children":707},{},[708,715],{"type":22,"tag":110,"props":709,"children":712},{"href":710,"rel":711},"http://support.apple.com/kb/HT4175",[114],[713],{"type":28,"value":714},"iOS-level data protection",{"type":28,"value":716}," based on the device passcode",{"type":22,"tag":222,"props":718,"children":719},{},[720,722,729],{"type":28,"value":721},"open source projects like ",{"type":22,"tag":110,"props":723,"children":726},{"href":724,"rel":725},"http://sqlcipher.net/ios-tutorial/",[114],[727],{"type":28,"value":728},"SQLCipher for iOS",{"type":28,"value":730}," that encrypt the database file",{"type":22,"tag":31,"props":732,"children":733},{},[734],{"type":28,"value":735},"However, neither of these options is sufficient for if you need to use multiple encryption keys, encrypt only certain attributes, or preserve decrypted data while the device is locked.",{"type":22,"tag":59,"props":737,"children":739},{"id":738},"encryption-transformer-class",[740],{"type":28,"value":741},"Encryption Transformer Class",{"type":22,"tag":31,"props":743,"children":744},{},[745,747,754,756,763],{"type":28,"value":746},"Instead, it's fairly simple and straight-forward to perform lazy decryption on only certain database fields using the special ",{"type":22,"tag":110,"props":748,"children":751},{"href":749,"rel":750},"https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreData/Articles/cdNSAttributes.html",[114],[752],{"type":28,"value":753},"Transformable Core Data attribute type",{"type":28,"value":755},". Transformable attributes are configured with an ",{"type":22,"tag":110,"props":757,"children":760},{"href":758,"rel":759},"http://developer.apple.com/library/ios/#DOCUMENTATION/Cocoa/Reference/Foundation/Classes/NSValueTransformer_Class/Reference/Reference.html",[114],[761],{"type":28,"value":762},"NSValueTransformer",{"type":28,"value":764}," subclass that you write that specifies:",{"type":22,"tag":218,"props":766,"children":767},{},[768,773,778],{"type":22,"tag":222,"props":769,"children":770},{},[771],{"type":28,"value":772},"a method for converting one object into another",{"type":22,"tag":222,"props":774,"children":775},{},[776],{"type":28,"value":777},"an optional method for reversing that process (and whether reversing is supported)",{"type":22,"tag":222,"props":779,"children":780},{},[781],{"type":28,"value":782},"the class of an object after transformation",{"type":22,"tag":31,"props":784,"children":785},{},[786,788,793,795,800],{"type":28,"value":787},"Here's an example class that converts from a decrypted NSData object to an encrypted one. It relies on a ",{"type":22,"tag":41,"props":789,"children":790},{},[791],{"type":28,"value":792},"key",{"type":28,"value":794}," method to get the encryption key, and a couple ",{"type":22,"tag":41,"props":796,"children":797},{},[798],{"type":28,"value":799},"NSData",{"type":28,"value":801}," category methods that perform AES-256 encryption and decryption.",{"type":22,"tag":306,"props":803,"children":805},{"id":804},"encryptiontransformerh",[806],{"type":28,"value":807},"EncryptionTransformer.h",{"type":22,"tag":274,"props":809,"children":813},{"className":810,"code":811,"language":812,"meta":8,"style":8},"language-objc shiki shiki-themes github-light github-dark","@interface EncryptionTransformer : NSValueTransformer\n{}\n\n/**\n * Returns the key used for encrypting / decrypting values during transformation.\n */\n- (NSString*)key;\n\n@end\n","objc",[814],{"type":22,"tag":155,"props":815,"children":816},{"__ignoreMap":8},[817,846,854,863,873,882,891,925,933],{"type":22,"tag":818,"props":819,"children":822},"span",{"class":820,"line":821},"line",1,[823,829,835,841],{"type":22,"tag":818,"props":824,"children":826},{"style":825},"--shiki-default:#D73A49;--shiki-dark:#F97583",[827],{"type":28,"value":828},"@interface",{"type":22,"tag":818,"props":830,"children":832},{"style":831},"--shiki-default:#6F42C1;--shiki-dark:#B392F0",[833],{"type":28,"value":834}," EncryptionTransformer",{"type":22,"tag":818,"props":836,"children":838},{"style":837},"--shiki-default:#24292E;--shiki-dark:#E1E4E8",[839],{"type":28,"value":840}," : ",{"type":22,"tag":818,"props":842,"children":843},{"style":831},[844],{"type":28,"value":845},"NSValueTransformer\n",{"type":22,"tag":818,"props":847,"children":848},{"class":820,"line":390},[849],{"type":22,"tag":818,"props":850,"children":851},{"style":837},[852],{"type":28,"value":853},"{}\n",{"type":22,"tag":818,"props":855,"children":856},{"class":820,"line":387},[857],{"type":22,"tag":818,"props":858,"children":860},{"emptyLinePlaceholder":859},true,[861],{"type":28,"value":862},"\n",{"type":22,"tag":818,"props":864,"children":866},{"class":820,"line":865},4,[867],{"type":22,"tag":818,"props":868,"children":870},{"style":869},"--shiki-default:#6A737D;--shiki-dark:#6A737D",[871],{"type":28,"value":872},"/**\n",{"type":22,"tag":818,"props":874,"children":876},{"class":820,"line":875},5,[877],{"type":22,"tag":818,"props":878,"children":879},{"style":869},[880],{"type":28,"value":881}," * Returns the key used for encrypting / decrypting values during transformation.\n",{"type":22,"tag":818,"props":883,"children":885},{"class":820,"line":884},6,[886],{"type":22,"tag":818,"props":887,"children":888},{"style":869},[889],{"type":28,"value":890}," */\n",{"type":22,"tag":818,"props":892,"children":894},{"class":820,"line":893},7,[895,900,906,911,916,920],{"type":22,"tag":818,"props":896,"children":897},{"style":837},[898],{"type":28,"value":899},"- (",{"type":22,"tag":818,"props":901,"children":903},{"style":902},"--shiki-default:#005CC5;--shiki-dark:#79B8FF",[904],{"type":28,"value":905},"NSString",{"type":22,"tag":818,"props":907,"children":908},{"style":825},[909],{"type":28,"value":910},"*",{"type":22,"tag":818,"props":912,"children":913},{"style":837},[914],{"type":28,"value":915},")",{"type":22,"tag":818,"props":917,"children":918},{"style":831},[919],{"type":28,"value":792},{"type":22,"tag":818,"props":921,"children":922},{"style":837},[923],{"type":28,"value":924},";\n",{"type":22,"tag":818,"props":926,"children":928},{"class":820,"line":927},8,[929],{"type":22,"tag":818,"props":930,"children":931},{"emptyLinePlaceholder":859},[932],{"type":28,"value":862},{"type":22,"tag":818,"props":934,"children":936},{"class":820,"line":935},9,[937],{"type":22,"tag":818,"props":938,"children":939},{"style":825},[940],{"type":28,"value":941},"@end\n",{"type":22,"tag":306,"props":943,"children":945},{"id":944},"encryptiontransformerm",[946],{"type":28,"value":947},"EncryptionTransformer.m",{"type":22,"tag":274,"props":949,"children":951},{"className":810,"code":950,"language":812,"meta":8,"style":8},"@implementation EncryptionTransformer\n\n+ (Class)transformedValueClass\n{\n   return [NSData class];\n}\n\n+ (BOOL)allowsReverseTransformation\n{\n   return YES;\n}\n\n- (NSString*)key\n{\n   // Your version of this class might get this key from the app delegate or elsewhere.\n   return @\"secret key\";\n}\n\n- (id)transformedValue:(NSData*)data\n{\n   // If there's no key (e.g. during a data migration), don't try to transform the data\n   if (nil == [self key])\n   {\n      return data;\n   }\n\n   if (nil == data)\n   {\n      return nil;\n   }\n\n   return [data dataAES256EncryptedWithKey:[self key]];\n}\n\n- (id)reverseTransformedValue:(NSData*)data\n{\n   // If there's no key (e.g. during a data migration), don't try to transform the data\n   if (nil == [self key])\n   {\n      return data;\n   }\n\n   if (nil == data)\n   {\n      return nil;\n   }\n\n   return [data dataAES256DecryptedWithKey:[self key]];\n}\n\n@end\n",[952],{"type":22,"tag":155,"props":953,"children":954},{"__ignoreMap":8},[955,968,975,997,1005,1032,1040,1047,1068,1075,1092,1100,1108,1133,1141,1150,1168,1176,1184,1224,1232,1241,1284,1293,1307,1316,1324,1349,1357,1374,1382,1390,1426,1434,1442,1479,1487,1495,1531,1539,1551,1559,1567,1591,1599,1615,1623,1631,1664,1672,1680],{"type":22,"tag":818,"props":956,"children":957},{"class":820,"line":821},[958,963],{"type":22,"tag":818,"props":959,"children":960},{"style":825},[961],{"type":28,"value":962},"@implementation",{"type":22,"tag":818,"props":964,"children":965},{"style":831},[966],{"type":28,"value":967}," EncryptionTransformer\n",{"type":22,"tag":818,"props":969,"children":970},{"class":820,"line":390},[971],{"type":22,"tag":818,"props":972,"children":973},{"emptyLinePlaceholder":859},[974],{"type":28,"value":862},{"type":22,"tag":818,"props":976,"children":977},{"class":820,"line":387},[978,983,988,992],{"type":22,"tag":818,"props":979,"children":980},{"style":837},[981],{"type":28,"value":982},"+ (",{"type":22,"tag":818,"props":984,"children":985},{"style":825},[986],{"type":28,"value":987},"Class",{"type":22,"tag":818,"props":989,"children":990},{"style":837},[991],{"type":28,"value":915},{"type":22,"tag":818,"props":993,"children":994},{"style":831},[995],{"type":28,"value":996},"transformedValueClass\n",{"type":22,"tag":818,"props":998,"children":999},{"class":820,"line":865},[1000],{"type":22,"tag":818,"props":1001,"children":1002},{"style":837},[1003],{"type":28,"value":1004},"{\n",{"type":22,"tag":818,"props":1006,"children":1007},{"class":820,"line":875},[1008,1013,1018,1022,1027],{"type":22,"tag":818,"props":1009,"children":1010},{"style":825},[1011],{"type":28,"value":1012},"   return",{"type":22,"tag":818,"props":1014,"children":1015},{"style":837},[1016],{"type":28,"value":1017}," [",{"type":22,"tag":818,"props":1019,"children":1020},{"style":902},[1021],{"type":28,"value":799},{"type":22,"tag":818,"props":1023,"children":1024},{"style":902},[1025],{"type":28,"value":1026}," class",{"type":22,"tag":818,"props":1028,"children":1029},{"style":837},[1030],{"type":28,"value":1031},"];\n",{"type":22,"tag":818,"props":1033,"children":1034},{"class":820,"line":884},[1035],{"type":22,"tag":818,"props":1036,"children":1037},{"style":837},[1038],{"type":28,"value":1039},"}\n",{"type":22,"tag":818,"props":1041,"children":1042},{"class":820,"line":893},[1043],{"type":22,"tag":818,"props":1044,"children":1045},{"emptyLinePlaceholder":859},[1046],{"type":28,"value":862},{"type":22,"tag":818,"props":1048,"children":1049},{"class":820,"line":927},[1050,1054,1059,1063],{"type":22,"tag":818,"props":1051,"children":1052},{"style":837},[1053],{"type":28,"value":982},{"type":22,"tag":818,"props":1055,"children":1056},{"style":825},[1057],{"type":28,"value":1058},"BOOL",{"type":22,"tag":818,"props":1060,"children":1061},{"style":837},[1062],{"type":28,"value":915},{"type":22,"tag":818,"props":1064,"children":1065},{"style":831},[1066],{"type":28,"value":1067},"allowsReverseTransformation\n",{"type":22,"tag":818,"props":1069,"children":1070},{"class":820,"line":935},[1071],{"type":22,"tag":818,"props":1072,"children":1073},{"style":837},[1074],{"type":28,"value":1004},{"type":22,"tag":818,"props":1076,"children":1078},{"class":820,"line":1077},10,[1079,1083,1088],{"type":22,"tag":818,"props":1080,"children":1081},{"style":825},[1082],{"type":28,"value":1012},{"type":22,"tag":818,"props":1084,"children":1085},{"style":902},[1086],{"type":28,"value":1087}," YES",{"type":22,"tag":818,"props":1089,"children":1090},{"style":837},[1091],{"type":28,"value":924},{"type":22,"tag":818,"props":1093,"children":1095},{"class":820,"line":1094},11,[1096],{"type":22,"tag":818,"props":1097,"children":1098},{"style":837},[1099],{"type":28,"value":1039},{"type":22,"tag":818,"props":1101,"children":1103},{"class":820,"line":1102},12,[1104],{"type":22,"tag":818,"props":1105,"children":1106},{"emptyLinePlaceholder":859},[1107],{"type":28,"value":862},{"type":22,"tag":818,"props":1109,"children":1111},{"class":820,"line":1110},13,[1112,1116,1120,1124,1128],{"type":22,"tag":818,"props":1113,"children":1114},{"style":837},[1115],{"type":28,"value":899},{"type":22,"tag":818,"props":1117,"children":1118},{"style":902},[1119],{"type":28,"value":905},{"type":22,"tag":818,"props":1121,"children":1122},{"style":825},[1123],{"type":28,"value":910},{"type":22,"tag":818,"props":1125,"children":1126},{"style":837},[1127],{"type":28,"value":915},{"type":22,"tag":818,"props":1129,"children":1130},{"style":831},[1131],{"type":28,"value":1132},"key\n",{"type":22,"tag":818,"props":1134,"children":1136},{"class":820,"line":1135},14,[1137],{"type":22,"tag":818,"props":1138,"children":1139},{"style":837},[1140],{"type":28,"value":1004},{"type":22,"tag":818,"props":1142,"children":1144},{"class":820,"line":1143},15,[1145],{"type":22,"tag":818,"props":1146,"children":1147},{"style":869},[1148],{"type":28,"value":1149},"   // Your version of this class might get this key from the app delegate or elsewhere.\n",{"type":22,"tag":818,"props":1151,"children":1153},{"class":820,"line":1152},16,[1154,1158,1164],{"type":22,"tag":818,"props":1155,"children":1156},{"style":825},[1157],{"type":28,"value":1012},{"type":22,"tag":818,"props":1159,"children":1161},{"style":1160},"--shiki-default:#032F62;--shiki-dark:#9ECBFF",[1162],{"type":28,"value":1163}," @\"secret key\"",{"type":22,"tag":818,"props":1165,"children":1166},{"style":837},[1167],{"type":28,"value":924},{"type":22,"tag":818,"props":1169,"children":1171},{"class":820,"line":1170},17,[1172],{"type":22,"tag":818,"props":1173,"children":1174},{"style":837},[1175],{"type":28,"value":1039},{"type":22,"tag":818,"props":1177,"children":1179},{"class":820,"line":1178},18,[1180],{"type":22,"tag":818,"props":1181,"children":1182},{"emptyLinePlaceholder":859},[1183],{"type":28,"value":862},{"type":22,"tag":818,"props":1185,"children":1187},{"class":820,"line":1186},19,[1188,1192,1197,1201,1206,1211,1215,1219],{"type":22,"tag":818,"props":1189,"children":1190},{"style":837},[1191],{"type":28,"value":899},{"type":22,"tag":818,"props":1193,"children":1194},{"style":825},[1195],{"type":28,"value":1196},"id",{"type":22,"tag":818,"props":1198,"children":1199},{"style":837},[1200],{"type":28,"value":915},{"type":22,"tag":818,"props":1202,"children":1203},{"style":831},[1204],{"type":28,"value":1205},"transformedValue:",{"type":22,"tag":818,"props":1207,"children":1208},{"style":837},[1209],{"type":28,"value":1210},"(",{"type":22,"tag":818,"props":1212,"children":1213},{"style":902},[1214],{"type":28,"value":799},{"type":22,"tag":818,"props":1216,"children":1217},{"style":825},[1218],{"type":28,"value":910},{"type":22,"tag":818,"props":1220,"children":1221},{"style":837},[1222],{"type":28,"value":1223},")data\n",{"type":22,"tag":818,"props":1225,"children":1227},{"class":820,"line":1226},20,[1228],{"type":22,"tag":818,"props":1229,"children":1230},{"style":837},[1231],{"type":28,"value":1004},{"type":22,"tag":818,"props":1233,"children":1235},{"class":820,"line":1234},21,[1236],{"type":22,"tag":818,"props":1237,"children":1238},{"style":869},[1239],{"type":28,"value":1240},"   // If there's no key (e.g. during a data migration), don't try to transform the data\n",{"type":22,"tag":818,"props":1242,"children":1244},{"class":820,"line":1243},22,[1245,1250,1255,1260,1265,1269,1274,1279],{"type":22,"tag":818,"props":1246,"children":1247},{"style":825},[1248],{"type":28,"value":1249},"   if",{"type":22,"tag":818,"props":1251,"children":1252},{"style":837},[1253],{"type":28,"value":1254}," (",{"type":22,"tag":818,"props":1256,"children":1257},{"style":902},[1258],{"type":28,"value":1259},"nil",{"type":22,"tag":818,"props":1261,"children":1262},{"style":825},[1263],{"type":28,"value":1264}," ==",{"type":22,"tag":818,"props":1266,"children":1267},{"style":837},[1268],{"type":28,"value":1017},{"type":22,"tag":818,"props":1270,"children":1271},{"style":902},[1272],{"type":28,"value":1273},"self",{"type":22,"tag":818,"props":1275,"children":1276},{"style":902},[1277],{"type":28,"value":1278}," key",{"type":22,"tag":818,"props":1280,"children":1281},{"style":837},[1282],{"type":28,"value":1283},"])\n",{"type":22,"tag":818,"props":1285,"children":1287},{"class":820,"line":1286},23,[1288],{"type":22,"tag":818,"props":1289,"children":1290},{"style":837},[1291],{"type":28,"value":1292},"   {\n",{"type":22,"tag":818,"props":1294,"children":1296},{"class":820,"line":1295},24,[1297,1302],{"type":22,"tag":818,"props":1298,"children":1299},{"style":825},[1300],{"type":28,"value":1301},"      return",{"type":22,"tag":818,"props":1303,"children":1304},{"style":837},[1305],{"type":28,"value":1306}," data;\n",{"type":22,"tag":818,"props":1308,"children":1310},{"class":820,"line":1309},25,[1311],{"type":22,"tag":818,"props":1312,"children":1313},{"style":837},[1314],{"type":28,"value":1315},"   }\n",{"type":22,"tag":818,"props":1317,"children":1319},{"class":820,"line":1318},26,[1320],{"type":22,"tag":818,"props":1321,"children":1322},{"emptyLinePlaceholder":859},[1323],{"type":28,"value":862},{"type":22,"tag":818,"props":1325,"children":1327},{"class":820,"line":1326},27,[1328,1332,1336,1340,1344],{"type":22,"tag":818,"props":1329,"children":1330},{"style":825},[1331],{"type":28,"value":1249},{"type":22,"tag":818,"props":1333,"children":1334},{"style":837},[1335],{"type":28,"value":1254},{"type":22,"tag":818,"props":1337,"children":1338},{"style":902},[1339],{"type":28,"value":1259},{"type":22,"tag":818,"props":1341,"children":1342},{"style":825},[1343],{"type":28,"value":1264},{"type":22,"tag":818,"props":1345,"children":1346},{"style":837},[1347],{"type":28,"value":1348}," data)\n",{"type":22,"tag":818,"props":1350,"children":1352},{"class":820,"line":1351},28,[1353],{"type":22,"tag":818,"props":1354,"children":1355},{"style":837},[1356],{"type":28,"value":1292},{"type":22,"tag":818,"props":1358,"children":1360},{"class":820,"line":1359},29,[1361,1365,1370],{"type":22,"tag":818,"props":1362,"children":1363},{"style":825},[1364],{"type":28,"value":1301},{"type":22,"tag":818,"props":1366,"children":1367},{"style":902},[1368],{"type":28,"value":1369}," nil",{"type":22,"tag":818,"props":1371,"children":1372},{"style":837},[1373],{"type":28,"value":924},{"type":22,"tag":818,"props":1375,"children":1377},{"class":820,"line":1376},30,[1378],{"type":22,"tag":818,"props":1379,"children":1380},{"style":837},[1381],{"type":28,"value":1315},{"type":22,"tag":818,"props":1383,"children":1385},{"class":820,"line":1384},31,[1386],{"type":22,"tag":818,"props":1387,"children":1388},{"emptyLinePlaceholder":859},[1389],{"type":28,"value":862},{"type":22,"tag":818,"props":1391,"children":1393},{"class":820,"line":1392},32,[1394,1398,1403,1408,1413,1417,1421],{"type":22,"tag":818,"props":1395,"children":1396},{"style":825},[1397],{"type":28,"value":1012},{"type":22,"tag":818,"props":1399,"children":1400},{"style":837},[1401],{"type":28,"value":1402}," [data ",{"type":22,"tag":818,"props":1404,"children":1405},{"style":902},[1406],{"type":28,"value":1407},"dataAES256EncryptedWithKey:",{"type":22,"tag":818,"props":1409,"children":1410},{"style":837},[1411],{"type":28,"value":1412},"[",{"type":22,"tag":818,"props":1414,"children":1415},{"style":902},[1416],{"type":28,"value":1273},{"type":22,"tag":818,"props":1418,"children":1419},{"style":902},[1420],{"type":28,"value":1278},{"type":22,"tag":818,"props":1422,"children":1423},{"style":837},[1424],{"type":28,"value":1425},"]];\n",{"type":22,"tag":818,"props":1427,"children":1429},{"class":820,"line":1428},33,[1430],{"type":22,"tag":818,"props":1431,"children":1432},{"style":837},[1433],{"type":28,"value":1039},{"type":22,"tag":818,"props":1435,"children":1437},{"class":820,"line":1436},34,[1438],{"type":22,"tag":818,"props":1439,"children":1440},{"emptyLinePlaceholder":859},[1441],{"type":28,"value":862},{"type":22,"tag":818,"props":1443,"children":1445},{"class":820,"line":1444},35,[1446,1450,1454,1458,1463,1467,1471,1475],{"type":22,"tag":818,"props":1447,"children":1448},{"style":837},[1449],{"type":28,"value":899},{"type":22,"tag":818,"props":1451,"children":1452},{"style":825},[1453],{"type":28,"value":1196},{"type":22,"tag":818,"props":1455,"children":1456},{"style":837},[1457],{"type":28,"value":915},{"type":22,"tag":818,"props":1459,"children":1460},{"style":831},[1461],{"type":28,"value":1462},"reverseTransformedValue:",{"type":22,"tag":818,"props":1464,"children":1465},{"style":837},[1466],{"type":28,"value":1210},{"type":22,"tag":818,"props":1468,"children":1469},{"style":902},[1470],{"type":28,"value":799},{"type":22,"tag":818,"props":1472,"children":1473},{"style":825},[1474],{"type":28,"value":910},{"type":22,"tag":818,"props":1476,"children":1477},{"style":837},[1478],{"type":28,"value":1223},{"type":22,"tag":818,"props":1480,"children":1482},{"class":820,"line":1481},36,[1483],{"type":22,"tag":818,"props":1484,"children":1485},{"style":837},[1486],{"type":28,"value":1004},{"type":22,"tag":818,"props":1488,"children":1490},{"class":820,"line":1489},37,[1491],{"type":22,"tag":818,"props":1492,"children":1493},{"style":869},[1494],{"type":28,"value":1240},{"type":22,"tag":818,"props":1496,"children":1498},{"class":820,"line":1497},38,[1499,1503,1507,1511,1515,1519,1523,1527],{"type":22,"tag":818,"props":1500,"children":1501},{"style":825},[1502],{"type":28,"value":1249},{"type":22,"tag":818,"props":1504,"children":1505},{"style":837},[1506],{"type":28,"value":1254},{"type":22,"tag":818,"props":1508,"children":1509},{"style":902},[1510],{"type":28,"value":1259},{"type":22,"tag":818,"props":1512,"children":1513},{"style":825},[1514],{"type":28,"value":1264},{"type":22,"tag":818,"props":1516,"children":1517},{"style":837},[1518],{"type":28,"value":1017},{"type":22,"tag":818,"props":1520,"children":1521},{"style":902},[1522],{"type":28,"value":1273},{"type":22,"tag":818,"props":1524,"children":1525},{"style":902},[1526],{"type":28,"value":1278},{"type":22,"tag":818,"props":1528,"children":1529},{"style":837},[1530],{"type":28,"value":1283},{"type":22,"tag":818,"props":1532,"children":1534},{"class":820,"line":1533},39,[1535],{"type":22,"tag":818,"props":1536,"children":1537},{"style":837},[1538],{"type":28,"value":1292},{"type":22,"tag":818,"props":1540,"children":1542},{"class":820,"line":1541},40,[1543,1547],{"type":22,"tag":818,"props":1544,"children":1545},{"style":825},[1546],{"type":28,"value":1301},{"type":22,"tag":818,"props":1548,"children":1549},{"style":837},[1550],{"type":28,"value":1306},{"type":22,"tag":818,"props":1552,"children":1554},{"class":820,"line":1553},41,[1555],{"type":22,"tag":818,"props":1556,"children":1557},{"style":837},[1558],{"type":28,"value":1315},{"type":22,"tag":818,"props":1560,"children":1562},{"class":820,"line":1561},42,[1563],{"type":22,"tag":818,"props":1564,"children":1565},{"emptyLinePlaceholder":859},[1566],{"type":28,"value":862},{"type":22,"tag":818,"props":1568,"children":1570},{"class":820,"line":1569},43,[1571,1575,1579,1583,1587],{"type":22,"tag":818,"props":1572,"children":1573},{"style":825},[1574],{"type":28,"value":1249},{"type":22,"tag":818,"props":1576,"children":1577},{"style":837},[1578],{"type":28,"value":1254},{"type":22,"tag":818,"props":1580,"children":1581},{"style":902},[1582],{"type":28,"value":1259},{"type":22,"tag":818,"props":1584,"children":1585},{"style":825},[1586],{"type":28,"value":1264},{"type":22,"tag":818,"props":1588,"children":1589},{"style":837},[1590],{"type":28,"value":1348},{"type":22,"tag":818,"props":1592,"children":1594},{"class":820,"line":1593},44,[1595],{"type":22,"tag":818,"props":1596,"children":1597},{"style":837},[1598],{"type":28,"value":1292},{"type":22,"tag":818,"props":1600,"children":1602},{"class":820,"line":1601},45,[1603,1607,1611],{"type":22,"tag":818,"props":1604,"children":1605},{"style":825},[1606],{"type":28,"value":1301},{"type":22,"tag":818,"props":1608,"children":1609},{"style":902},[1610],{"type":28,"value":1369},{"type":22,"tag":818,"props":1612,"children":1613},{"style":837},[1614],{"type":28,"value":924},{"type":22,"tag":818,"props":1616,"children":1618},{"class":820,"line":1617},46,[1619],{"type":22,"tag":818,"props":1620,"children":1621},{"style":837},[1622],{"type":28,"value":1315},{"type":22,"tag":818,"props":1624,"children":1626},{"class":820,"line":1625},47,[1627],{"type":22,"tag":818,"props":1628,"children":1629},{"emptyLinePlaceholder":859},[1630],{"type":28,"value":862},{"type":22,"tag":818,"props":1632,"children":1634},{"class":820,"line":1633},48,[1635,1639,1643,1648,1652,1656,1660],{"type":22,"tag":818,"props":1636,"children":1637},{"style":825},[1638],{"type":28,"value":1012},{"type":22,"tag":818,"props":1640,"children":1641},{"style":837},[1642],{"type":28,"value":1402},{"type":22,"tag":818,"props":1644,"children":1645},{"style":902},[1646],{"type":28,"value":1647},"dataAES256DecryptedWithKey:",{"type":22,"tag":818,"props":1649,"children":1650},{"style":837},[1651],{"type":28,"value":1412},{"type":22,"tag":818,"props":1653,"children":1654},{"style":902},[1655],{"type":28,"value":1273},{"type":22,"tag":818,"props":1657,"children":1658},{"style":902},[1659],{"type":28,"value":1278},{"type":22,"tag":818,"props":1661,"children":1662},{"style":837},[1663],{"type":28,"value":1425},{"type":22,"tag":818,"props":1665,"children":1667},{"class":820,"line":1666},49,[1668],{"type":22,"tag":818,"props":1669,"children":1670},{"style":837},[1671],{"type":28,"value":1039},{"type":22,"tag":818,"props":1673,"children":1675},{"class":820,"line":1674},50,[1676],{"type":22,"tag":818,"props":1677,"children":1678},{"emptyLinePlaceholder":859},[1679],{"type":28,"value":862},{"type":22,"tag":818,"props":1681,"children":1683},{"class":820,"line":1682},51,[1684],{"type":22,"tag":818,"props":1685,"children":1686},{"style":825},[1687],{"type":28,"value":941},{"type":22,"tag":31,"props":1689,"children":1690},{},[1691,1693,1697],{"type":28,"value":1692},"The ",{"type":22,"tag":41,"props":1694,"children":1695},{},[1696],{"type":28,"value":792},{"type":28,"value":1698}," method might get the secret key from any number of places, such as a password requested at login and stored in the app delegate. I'll touch on the NSData category methods that actually perform the encryption in a little bit.",{"type":22,"tag":31,"props":1700,"children":1701},{},[1702],{"type":28,"value":1703},"This encryption class can then easily be subclassed to handle different data types, like strings, dates, numbers, etc. Here's an example string encryption class that converts between NSString and NSData in order to use its parent class transformation methods.",{"type":22,"tag":306,"props":1705,"children":1707},{"id":1706},"encryptiontransformerh-1",[1708],{"type":28,"value":807},{"type":22,"tag":274,"props":1710,"children":1712},{"className":810,"code":1711,"language":812,"meta":8,"style":8},"@interface StringEncryptionTransformer : EncryptionTransformer\n{}\n",[1713],{"type":22,"tag":155,"props":1714,"children":1715},{"__ignoreMap":8},[1716,1737],{"type":22,"tag":818,"props":1717,"children":1718},{"class":820,"line":821},[1719,1723,1728,1732],{"type":22,"tag":818,"props":1720,"children":1721},{"style":825},[1722],{"type":28,"value":828},{"type":22,"tag":818,"props":1724,"children":1725},{"style":831},[1726],{"type":28,"value":1727}," StringEncryptionTransformer",{"type":22,"tag":818,"props":1729,"children":1730},{"style":837},[1731],{"type":28,"value":840},{"type":22,"tag":818,"props":1733,"children":1734},{"style":831},[1735],{"type":28,"value":1736},"EncryptionTransformer\n",{"type":22,"tag":818,"props":1738,"children":1739},{"class":820,"line":390},[1740],{"type":22,"tag":818,"props":1741,"children":1742},{"style":837},[1743],{"type":28,"value":853},{"type":22,"tag":1745,"props":1746,"children":1748},"h4",{"id":1747},"encryptiontransformerm-1",[1749],{"type":28,"value":947},{"type":22,"tag":274,"props":1751,"children":1753},{"className":810,"code":1752,"language":812,"meta":8,"style":8},"@implementation StringEncryptionTransformer\n\n+ (Class)transformedValueClass\n{\n   return [NSString class];\n}\n\n- (id)transformedValue:(NSString*)string\n{\n   NSData* data = [string dataUsingEncoding:NSUTF8StringEncoding];\n   return [super transformedValue:data];\n}\n\n- (id)reverseTransformedValue:(NSData*)data\n{\n   if (nil == data)\n   {\n      return nil;\n   }\n\n   data = [super reverseTransformedValue:data];\n\n   return [[[NSString alloc] initWithBytes:[data bytes]\n                                    length:[data length]\n                                  encoding:NSUTF8StringEncoding]\n           autorelease];\n}\n\n@end\n",[1754],{"type":22,"tag":155,"props":1755,"children":1756},{"__ignoreMap":8},[1757,1769,1776,1795,1802,1825,1832,1839,1875,1882,1918,1944,1951,1958,1993,2000,2023,2030,2045,2052,2059,2088,2095,2141,2162,2174,2182,2189,2196],{"type":22,"tag":818,"props":1758,"children":1759},{"class":820,"line":821},[1760,1764],{"type":22,"tag":818,"props":1761,"children":1762},{"style":825},[1763],{"type":28,"value":962},{"type":22,"tag":818,"props":1765,"children":1766},{"style":831},[1767],{"type":28,"value":1768}," StringEncryptionTransformer\n",{"type":22,"tag":818,"props":1770,"children":1771},{"class":820,"line":390},[1772],{"type":22,"tag":818,"props":1773,"children":1774},{"emptyLinePlaceholder":859},[1775],{"type":28,"value":862},{"type":22,"tag":818,"props":1777,"children":1778},{"class":820,"line":387},[1779,1783,1787,1791],{"type":22,"tag":818,"props":1780,"children":1781},{"style":837},[1782],{"type":28,"value":982},{"type":22,"tag":818,"props":1784,"children":1785},{"style":825},[1786],{"type":28,"value":987},{"type":22,"tag":818,"props":1788,"children":1789},{"style":837},[1790],{"type":28,"value":915},{"type":22,"tag":818,"props":1792,"children":1793},{"style":831},[1794],{"type":28,"value":996},{"type":22,"tag":818,"props":1796,"children":1797},{"class":820,"line":865},[1798],{"type":22,"tag":818,"props":1799,"children":1800},{"style":837},[1801],{"type":28,"value":1004},{"type":22,"tag":818,"props":1803,"children":1804},{"class":820,"line":875},[1805,1809,1813,1817,1821],{"type":22,"tag":818,"props":1806,"children":1807},{"style":825},[1808],{"type":28,"value":1012},{"type":22,"tag":818,"props":1810,"children":1811},{"style":837},[1812],{"type":28,"value":1017},{"type":22,"tag":818,"props":1814,"children":1815},{"style":902},[1816],{"type":28,"value":905},{"type":22,"tag":818,"props":1818,"children":1819},{"style":902},[1820],{"type":28,"value":1026},{"type":22,"tag":818,"props":1822,"children":1823},{"style":837},[1824],{"type":28,"value":1031},{"type":22,"tag":818,"props":1826,"children":1827},{"class":820,"line":884},[1828],{"type":22,"tag":818,"props":1829,"children":1830},{"style":837},[1831],{"type":28,"value":1039},{"type":22,"tag":818,"props":1833,"children":1834},{"class":820,"line":893},[1835],{"type":22,"tag":818,"props":1836,"children":1837},{"emptyLinePlaceholder":859},[1838],{"type":28,"value":862},{"type":22,"tag":818,"props":1840,"children":1841},{"class":820,"line":927},[1842,1846,1850,1854,1858,1862,1866,1870],{"type":22,"tag":818,"props":1843,"children":1844},{"style":837},[1845],{"type":28,"value":899},{"type":22,"tag":818,"props":1847,"children":1848},{"style":825},[1849],{"type":28,"value":1196},{"type":22,"tag":818,"props":1851,"children":1852},{"style":837},[1853],{"type":28,"value":915},{"type":22,"tag":818,"props":1855,"children":1856},{"style":831},[1857],{"type":28,"value":1205},{"type":22,"tag":818,"props":1859,"children":1860},{"style":837},[1861],{"type":28,"value":1210},{"type":22,"tag":818,"props":1863,"children":1864},{"style":902},[1865],{"type":28,"value":905},{"type":22,"tag":818,"props":1867,"children":1868},{"style":825},[1869],{"type":28,"value":910},{"type":22,"tag":818,"props":1871,"children":1872},{"style":837},[1873],{"type":28,"value":1874},")string\n",{"type":22,"tag":818,"props":1876,"children":1877},{"class":820,"line":935},[1878],{"type":22,"tag":818,"props":1879,"children":1880},{"style":837},[1881],{"type":28,"value":1004},{"type":22,"tag":818,"props":1883,"children":1884},{"class":820,"line":1077},[1885,1890,1894,1899,1904,1909,1914],{"type":22,"tag":818,"props":1886,"children":1887},{"style":902},[1888],{"type":28,"value":1889},"   NSData",{"type":22,"tag":818,"props":1891,"children":1892},{"style":825},[1893],{"type":28,"value":910},{"type":22,"tag":818,"props":1895,"children":1896},{"style":837},[1897],{"type":28,"value":1898}," data ",{"type":22,"tag":818,"props":1900,"children":1901},{"style":825},[1902],{"type":28,"value":1903},"=",{"type":22,"tag":818,"props":1905,"children":1906},{"style":837},[1907],{"type":28,"value":1908}," [string ",{"type":22,"tag":818,"props":1910,"children":1911},{"style":902},[1912],{"type":28,"value":1913},"dataUsingEncoding:NSUTF8StringEncoding",{"type":22,"tag":818,"props":1915,"children":1916},{"style":837},[1917],{"type":28,"value":1031},{"type":22,"tag":818,"props":1919,"children":1920},{"class":820,"line":1094},[1921,1925,1929,1934,1939],{"type":22,"tag":818,"props":1922,"children":1923},{"style":825},[1924],{"type":28,"value":1012},{"type":22,"tag":818,"props":1926,"children":1927},{"style":837},[1928],{"type":28,"value":1017},{"type":22,"tag":818,"props":1930,"children":1931},{"style":902},[1932],{"type":28,"value":1933},"super",{"type":22,"tag":818,"props":1935,"children":1936},{"style":902},[1937],{"type":28,"value":1938}," transformedValue:",{"type":22,"tag":818,"props":1940,"children":1941},{"style":837},[1942],{"type":28,"value":1943},"data];\n",{"type":22,"tag":818,"props":1945,"children":1946},{"class":820,"line":1102},[1947],{"type":22,"tag":818,"props":1948,"children":1949},{"style":837},[1950],{"type":28,"value":1039},{"type":22,"tag":818,"props":1952,"children":1953},{"class":820,"line":1110},[1954],{"type":22,"tag":818,"props":1955,"children":1956},{"emptyLinePlaceholder":859},[1957],{"type":28,"value":862},{"type":22,"tag":818,"props":1959,"children":1960},{"class":820,"line":1135},[1961,1965,1969,1973,1977,1981,1985,1989],{"type":22,"tag":818,"props":1962,"children":1963},{"style":837},[1964],{"type":28,"value":899},{"type":22,"tag":818,"props":1966,"children":1967},{"style":825},[1968],{"type":28,"value":1196},{"type":22,"tag":818,"props":1970,"children":1971},{"style":837},[1972],{"type":28,"value":915},{"type":22,"tag":818,"props":1974,"children":1975},{"style":831},[1976],{"type":28,"value":1462},{"type":22,"tag":818,"props":1978,"children":1979},{"style":837},[1980],{"type":28,"value":1210},{"type":22,"tag":818,"props":1982,"children":1983},{"style":902},[1984],{"type":28,"value":799},{"type":22,"tag":818,"props":1986,"children":1987},{"style":825},[1988],{"type":28,"value":910},{"type":22,"tag":818,"props":1990,"children":1991},{"style":837},[1992],{"type":28,"value":1223},{"type":22,"tag":818,"props":1994,"children":1995},{"class":820,"line":1143},[1996],{"type":22,"tag":818,"props":1997,"children":1998},{"style":837},[1999],{"type":28,"value":1004},{"type":22,"tag":818,"props":2001,"children":2002},{"class":820,"line":1152},[2003,2007,2011,2015,2019],{"type":22,"tag":818,"props":2004,"children":2005},{"style":825},[2006],{"type":28,"value":1249},{"type":22,"tag":818,"props":2008,"children":2009},{"style":837},[2010],{"type":28,"value":1254},{"type":22,"tag":818,"props":2012,"children":2013},{"style":902},[2014],{"type":28,"value":1259},{"type":22,"tag":818,"props":2016,"children":2017},{"style":825},[2018],{"type":28,"value":1264},{"type":22,"tag":818,"props":2020,"children":2021},{"style":837},[2022],{"type":28,"value":1348},{"type":22,"tag":818,"props":2024,"children":2025},{"class":820,"line":1170},[2026],{"type":22,"tag":818,"props":2027,"children":2028},{"style":837},[2029],{"type":28,"value":1292},{"type":22,"tag":818,"props":2031,"children":2032},{"class":820,"line":1178},[2033,2037,2041],{"type":22,"tag":818,"props":2034,"children":2035},{"style":825},[2036],{"type":28,"value":1301},{"type":22,"tag":818,"props":2038,"children":2039},{"style":902},[2040],{"type":28,"value":1369},{"type":22,"tag":818,"props":2042,"children":2043},{"style":837},[2044],{"type":28,"value":924},{"type":22,"tag":818,"props":2046,"children":2047},{"class":820,"line":1186},[2048],{"type":22,"tag":818,"props":2049,"children":2050},{"style":837},[2051],{"type":28,"value":1315},{"type":22,"tag":818,"props":2053,"children":2054},{"class":820,"line":1226},[2055],{"type":22,"tag":818,"props":2056,"children":2057},{"emptyLinePlaceholder":859},[2058],{"type":28,"value":862},{"type":22,"tag":818,"props":2060,"children":2061},{"class":820,"line":1234},[2062,2067,2071,2075,2079,2084],{"type":22,"tag":818,"props":2063,"children":2064},{"style":837},[2065],{"type":28,"value":2066},"   data ",{"type":22,"tag":818,"props":2068,"children":2069},{"style":825},[2070],{"type":28,"value":1903},{"type":22,"tag":818,"props":2072,"children":2073},{"style":837},[2074],{"type":28,"value":1017},{"type":22,"tag":818,"props":2076,"children":2077},{"style":902},[2078],{"type":28,"value":1933},{"type":22,"tag":818,"props":2080,"children":2081},{"style":902},[2082],{"type":28,"value":2083}," reverseTransformedValue:",{"type":22,"tag":818,"props":2085,"children":2086},{"style":837},[2087],{"type":28,"value":1943},{"type":22,"tag":818,"props":2089,"children":2090},{"class":820,"line":1243},[2091],{"type":22,"tag":818,"props":2092,"children":2093},{"emptyLinePlaceholder":859},[2094],{"type":28,"value":862},{"type":22,"tag":818,"props":2096,"children":2097},{"class":820,"line":1286},[2098,2102,2107,2111,2116,2121,2126,2131,2136],{"type":22,"tag":818,"props":2099,"children":2100},{"style":825},[2101],{"type":28,"value":1012},{"type":22,"tag":818,"props":2103,"children":2104},{"style":837},[2105],{"type":28,"value":2106}," [[[",{"type":22,"tag":818,"props":2108,"children":2109},{"style":902},[2110],{"type":28,"value":905},{"type":22,"tag":818,"props":2112,"children":2113},{"style":902},[2114],{"type":28,"value":2115}," alloc",{"type":22,"tag":818,"props":2117,"children":2118},{"style":837},[2119],{"type":28,"value":2120},"] ",{"type":22,"tag":818,"props":2122,"children":2123},{"style":902},[2124],{"type":28,"value":2125},"initWithBytes:",{"type":22,"tag":818,"props":2127,"children":2128},{"style":837},[2129],{"type":28,"value":2130},"[data ",{"type":22,"tag":818,"props":2132,"children":2133},{"style":902},[2134],{"type":28,"value":2135},"bytes",{"type":22,"tag":818,"props":2137,"children":2138},{"style":837},[2139],{"type":28,"value":2140},"]\n",{"type":22,"tag":818,"props":2142,"children":2143},{"class":820,"line":1295},[2144,2149,2153,2158],{"type":22,"tag":818,"props":2145,"children":2146},{"style":902},[2147],{"type":28,"value":2148},"                                    length:",{"type":22,"tag":818,"props":2150,"children":2151},{"style":837},[2152],{"type":28,"value":2130},{"type":22,"tag":818,"props":2154,"children":2155},{"style":902},[2156],{"type":28,"value":2157},"length",{"type":22,"tag":818,"props":2159,"children":2160},{"style":837},[2161],{"type":28,"value":2140},{"type":22,"tag":818,"props":2163,"children":2164},{"class":820,"line":1309},[2165,2170],{"type":22,"tag":818,"props":2166,"children":2167},{"style":902},[2168],{"type":28,"value":2169},"                                  encoding:NSUTF8StringEncoding",{"type":22,"tag":818,"props":2171,"children":2172},{"style":837},[2173],{"type":28,"value":2140},{"type":22,"tag":818,"props":2175,"children":2176},{"class":820,"line":1318},[2177],{"type":22,"tag":818,"props":2178,"children":2179},{"style":837},[2180],{"type":28,"value":2181},"           autorelease];\n",{"type":22,"tag":818,"props":2183,"children":2184},{"class":820,"line":1326},[2185],{"type":22,"tag":818,"props":2186,"children":2187},{"style":837},[2188],{"type":28,"value":1039},{"type":22,"tag":818,"props":2190,"children":2191},{"class":820,"line":1351},[2192],{"type":22,"tag":818,"props":2193,"children":2194},{"emptyLinePlaceholder":859},[2195],{"type":28,"value":862},{"type":22,"tag":818,"props":2197,"children":2198},{"class":820,"line":1359},[2199],{"type":22,"tag":818,"props":2200,"children":2201},{"style":825},[2202],{"type":28,"value":941},{"type":22,"tag":31,"props":2204,"children":2205},{},[2206,2208,2213,2215,2220,2222,2227,2229,2234],{"type":28,"value":2207},"Once these classes are set up, the Core Data model editor lets you assign an entity ",{"type":22,"tag":37,"props":2209,"children":2210},{},[2211],{"type":28,"value":2212},"attribute type",{"type":28,"value":2214}," of ",{"type":22,"tag":41,"props":2216,"children":2217},{},[2218],{"type":28,"value":2219},"Transformable",{"type":28,"value":2221}," and a ",{"type":22,"tag":37,"props":2223,"children":2224},{},[2225],{"type":28,"value":2226},"name",{"type":28,"value":2228}," of the NSValueTransformer class, such as ",{"type":22,"tag":41,"props":2230,"children":2231},{},[2232],{"type":28,"value":2233},"StringEncryptionTransformer",{"type":28,"value":296},{"type":22,"tag":31,"props":2236,"children":2237},{},[2238,2243],{"type":22,"tag":615,"props":2239,"children":2242},{"alt":8,"src":2240,"title":2241},"/nharrison/2012-07/img/core-data-editor1.png","Core Data editor",[],{"type":28,"value":2244}," Core Data model editor in Xcode showing an entity's Transformable attribute.",{"type":22,"tag":31,"props":2246,"children":2247},{},[2248,2250,2256],{"type":28,"value":2249},"Now, these attributes can be written to in code just like any other (e.g. ",{"type":22,"tag":155,"props":2251,"children":2253},{"className":2252},[],[2254],{"type":28,"value":2255},"clark.secretIdentity = @\"superman\"",{"type":28,"value":2257},"), but when they are persisted to the underlying SQLite database (or other sort of data store), the appropriate NSValueTransformer class will be called to encrypt the values before writing them to the data store.",{"type":22,"tag":31,"props":2259,"children":2260},{},[2261],{"type":28,"value":2262},"Likewise, at the time a persisted object is read from the data store, the NSValueTransformer class will decrypt it. Encryption and decryption is thus lazy and only performed when an object is used or updated -- no need to decrypt an entire file or database during app startup.",{"type":22,"tag":59,"props":2264,"children":2266},{"id":2265},"aes-256-encryption-category",[2267],{"type":28,"value":2268},"AES-256 encryption category",{"type":22,"tag":31,"props":2270,"children":2271},{},[2272,2274,2281,2283,2290,2292,2299],{"type":28,"value":2273},"There are a number of example classes that make performing ",{"type":22,"tag":110,"props":2275,"children":2278},{"href":2276,"rel":2277},"http://en.wikipedia.org/wiki/Advanced_Encryption_Standard",[114],[2279],{"type":28,"value":2280},"AES-256",{"type":28,"value":2282}," encryption as simple as shown above, such as Jim Dovey's ",{"type":22,"tag":110,"props":2284,"children":2287},{"href":2285,"rel":2286},"https://github.com/AlanQuatermain/aqtoolkit/tree/master/CommonCrypto",[114],[2288],{"type":28,"value":2289},"NSData+CommonCrypto category",{"type":28,"value":2291}," and this ",{"type":22,"tag":110,"props":2293,"children":2296},{"href":2294,"rel":2295},"http://pastie.org/426530",[114],[2297],{"type":28,"value":2298},"unattributed snippet",{"type":28,"value":2300},".  The better ones use encryption libraries provided by Apple, which may (or may not, IANAL) mean that you don't need a CCATS form for app submission.",{"type":22,"tag":31,"props":2302,"children":2303},{},[2304,2306,2312,2314,2320,2322,2328,2330,2337],{"type":28,"value":2305},"However, one major caveat to encrypting attributes individually is that patterns from short, repeated values will naturally rise.  If you are encrypting only a couple different possible values for an attribute (e.g. \"superhero\" and \"evildoer\"), simple encryption using the same key will result in only two encrypted values.  That is, for the key \"",{"type":22,"tag":155,"props":2307,"children":2309},{"className":2308},[],[2310],{"type":28,"value":2311},"top secret",{"type":28,"value":2313},"\", the value \"",{"type":22,"tag":155,"props":2315,"children":2317},{"className":2316},[],[2318],{"type":28,"value":2319},"Superman",{"type":28,"value":2321},"\" will always encrypt to \"",{"type":22,"tag":155,"props":2323,"children":2325},{"className":2324},[],[2326],{"type":28,"value":2327},"?b64JzJ4aC0IhKaf7xeTWaglC6L/3VFxwA5XVrfDRntxebO4rFUSdNNrzfVFIU3yZH0F?64b",{"type":28,"value":2329},"\" (",{"type":22,"tag":110,"props":2331,"children":2334},{"href":2332,"rel":2333},"http://www.fourmilab.ch/javascrypt/javascrypt.html",[114],[2335],{"type":28,"value":2336},"Javascrypt",{"type":28,"value":2338}," is a handy online tool for encryption).",{"type":22,"tag":31,"props":2340,"children":2341},{},[2342,2344,2354,2356,2363],{"type":28,"value":2343},"Enter the ",{"type":22,"tag":110,"props":2345,"children":2348},{"href":2346,"rel":2347},"http://en.wikipedia.org/wiki/Initialization_vector",[114],[2349],{"type":22,"tag":41,"props":2350,"children":2351},{},[2352],{"type":28,"value":2353},"initialization vector",{"type":28,"value":2355}," (IV), which like the ",{"type":22,"tag":110,"props":2357,"children":2360},{"href":2358,"rel":2359},"http://en.wikipedia.org/wiki/Salt_%28cryptography%29",[114],[2361],{"type":28,"value":2362},"salt",{"type":28,"value":2364}," for a password helps hide patterns by randomizing encryption input.  The IV should be:",{"type":22,"tag":2366,"props":2367,"children":2368},"ol",{},[2369,2381,2386,2391],{"type":22,"tag":222,"props":2370,"children":2371},{},[2372,2374],{"type":28,"value":2373},"a random number, for example the result of ",{"type":22,"tag":110,"props":2375,"children":2378},{"href":2376,"rel":2377},"https://developer.apple.com/library/mac/#documentation/Darwin/Reference/Manpages/man3/arc4random.3.html",[114],[2379],{"type":28,"value":2380},"arc4random()",{"type":22,"tag":222,"props":2382,"children":2383},{},[2384],{"type":28,"value":2385},"different for every attribute, or at least every entity",{"type":22,"tag":222,"props":2387,"children":2388},{},[2389],{"type":28,"value":2390},"stored alongside the encrypted value, since the same IV used for encryption is necessary for decryption",{"type":22,"tag":222,"props":2392,"children":2393},{},[2394],{"type":28,"value":2395},"public, that is it need not (and should not) be encrypted",{"type":22,"tag":31,"props":2397,"children":2398},{},[2399],{"type":28,"value":2400},"Unfortunately, many example code snippets that call CCCrypt (including one linked above) leave the initialization vector parameter as simply:",{"type":22,"tag":31,"props":2402,"children":2403},{},[2404],{"type":22,"tag":155,"props":2405,"children":2407},{"className":2406},[],[2408],{"type":28,"value":2409},"NULL / _initialization vector (optional)_ /,",{"type":22,"tag":31,"props":2411,"children":2412},{},[2413],{"type":28,"value":2414},"Rather than follow suit, it's simple to update our EncryptionTransformer to generate a IV and prepend it to the encrypted data:",{"type":22,"tag":1745,"props":2416,"children":2418},{"id":2417},"encryptiontransformermencryptiontransformerm",[2419],{"type":28,"value":2420},"EncryptionTransformer.mEncryptionTransformer.m",{"type":22,"tag":274,"props":2422,"children":2424},{"className":810,"code":2423,"language":812,"meta":8,"style":8},"- (id)transformedValue:(NSData*)data\n{\n   ...\n\n   // Use another NSData category method (left as an exercise \n   // to the reader) to randomly generate the IV data\n   NSData* iv = [NSData randomDataOfLength:32];\n\n   data = [data dataAES256EncryptedWithKey:[self key] Iv:iv];\n\n   // Return a data object that includes the IV with the \n   // encrypted data appended\n   NSMutableData* mutableData = [NSMutableData dataWithData:iv];\n   [mutableData appendData:data];\n   return mutableData;\n}\n\n- (id)reverseTransformedValue:(NSData*)data\n{\n   ...\n\n   // The IV was stored in the first 32 bytes of the data\n   NSData* iv = [data subdataWithRange:NSMakeRange(0, 32)];\n\n   // Remove the IV from the encrypted data and decrypt it\n   NSMutableData* mutableData = [NSMutableData dataWithData:data];\n   [mutableData replaceBytesInRange:NSMakeRange(0, 32) withBytes:NULL];\n   return [mutableData dataAES256DecryptedWithKey:[self key] Iv:iv];\n}\n",[2425],{"type":22,"tag":155,"props":2426,"children":2427},{"__ignoreMap":8},[2428,2461,2468,2476,2483,2491,2499,2536,2543,2588,2595,2603,2611,2650,2667,2679,2686,2693,2725,2732,2739,2746,2754,2806,2813,2821,2856,2898,2938],{"type":22,"tag":818,"props":2429,"children":2430},{"class":820,"line":821},[2431,2436,2440,2444,2449,2453,2457],{"type":22,"tag":818,"props":2432,"children":2433},{"style":825},[2434],{"type":28,"value":2435},"-",{"type":22,"tag":818,"props":2437,"children":2438},{"style":837},[2439],{"type":28,"value":1254},{"type":22,"tag":818,"props":2441,"children":2442},{"style":825},[2443],{"type":28,"value":1196},{"type":22,"tag":818,"props":2445,"children":2446},{"style":837},[2447],{"type":28,"value":2448},")transformedValue:(",{"type":22,"tag":818,"props":2450,"children":2451},{"style":902},[2452],{"type":28,"value":799},{"type":22,"tag":818,"props":2454,"children":2455},{"style":825},[2456],{"type":28,"value":910},{"type":22,"tag":818,"props":2458,"children":2459},{"style":837},[2460],{"type":28,"value":1223},{"type":22,"tag":818,"props":2462,"children":2463},{"class":820,"line":390},[2464],{"type":22,"tag":818,"props":2465,"children":2466},{"style":837},[2467],{"type":28,"value":1004},{"type":22,"tag":818,"props":2469,"children":2470},{"class":820,"line":387},[2471],{"type":22,"tag":818,"props":2472,"children":2473},{"style":837},[2474],{"type":28,"value":2475},"   ...\n",{"type":22,"tag":818,"props":2477,"children":2478},{"class":820,"line":865},[2479],{"type":22,"tag":818,"props":2480,"children":2481},{"emptyLinePlaceholder":859},[2482],{"type":28,"value":862},{"type":22,"tag":818,"props":2484,"children":2485},{"class":820,"line":875},[2486],{"type":22,"tag":818,"props":2487,"children":2488},{"style":869},[2489],{"type":28,"value":2490},"   // Use another NSData category method (left as an exercise \n",{"type":22,"tag":818,"props":2492,"children":2493},{"class":820,"line":884},[2494],{"type":22,"tag":818,"props":2495,"children":2496},{"style":869},[2497],{"type":28,"value":2498},"   // to the reader) to randomly generate the IV data\n",{"type":22,"tag":818,"props":2500,"children":2501},{"class":820,"line":893},[2502,2506,2510,2515,2519,2523,2527,2532],{"type":22,"tag":818,"props":2503,"children":2504},{"style":902},[2505],{"type":28,"value":1889},{"type":22,"tag":818,"props":2507,"children":2508},{"style":825},[2509],{"type":28,"value":910},{"type":22,"tag":818,"props":2511,"children":2512},{"style":837},[2513],{"type":28,"value":2514}," iv ",{"type":22,"tag":818,"props":2516,"children":2517},{"style":825},[2518],{"type":28,"value":1903},{"type":22,"tag":818,"props":2520,"children":2521},{"style":837},[2522],{"type":28,"value":1017},{"type":22,"tag":818,"props":2524,"children":2525},{"style":902},[2526],{"type":28,"value":799},{"type":22,"tag":818,"props":2528,"children":2529},{"style":902},[2530],{"type":28,"value":2531}," randomDataOfLength:32",{"type":22,"tag":818,"props":2533,"children":2534},{"style":837},[2535],{"type":28,"value":1031},{"type":22,"tag":818,"props":2537,"children":2538},{"class":820,"line":927},[2539],{"type":22,"tag":818,"props":2540,"children":2541},{"emptyLinePlaceholder":859},[2542],{"type":28,"value":862},{"type":22,"tag":818,"props":2544,"children":2545},{"class":820,"line":935},[2546,2550,2554,2558,2562,2566,2570,2574,2578,2583],{"type":22,"tag":818,"props":2547,"children":2548},{"style":837},[2549],{"type":28,"value":2066},{"type":22,"tag":818,"props":2551,"children":2552},{"style":825},[2553],{"type":28,"value":1903},{"type":22,"tag":818,"props":2555,"children":2556},{"style":837},[2557],{"type":28,"value":1402},{"type":22,"tag":818,"props":2559,"children":2560},{"style":902},[2561],{"type":28,"value":1407},{"type":22,"tag":818,"props":2563,"children":2564},{"style":837},[2565],{"type":28,"value":1412},{"type":22,"tag":818,"props":2567,"children":2568},{"style":902},[2569],{"type":28,"value":1273},{"type":22,"tag":818,"props":2571,"children":2572},{"style":902},[2573],{"type":28,"value":1278},{"type":22,"tag":818,"props":2575,"children":2576},{"style":837},[2577],{"type":28,"value":2120},{"type":22,"tag":818,"props":2579,"children":2580},{"style":902},[2581],{"type":28,"value":2582},"Iv:",{"type":22,"tag":818,"props":2584,"children":2585},{"style":837},[2586],{"type":28,"value":2587},"iv];\n",{"type":22,"tag":818,"props":2589,"children":2590},{"class":820,"line":1077},[2591],{"type":22,"tag":818,"props":2592,"children":2593},{"emptyLinePlaceholder":859},[2594],{"type":28,"value":862},{"type":22,"tag":818,"props":2596,"children":2597},{"class":820,"line":1094},[2598],{"type":22,"tag":818,"props":2599,"children":2600},{"style":869},[2601],{"type":28,"value":2602},"   // Return a data object that includes the IV with the \n",{"type":22,"tag":818,"props":2604,"children":2605},{"class":820,"line":1102},[2606],{"type":22,"tag":818,"props":2607,"children":2608},{"style":869},[2609],{"type":28,"value":2610},"   // encrypted data appended\n",{"type":22,"tag":818,"props":2612,"children":2613},{"class":820,"line":1110},[2614,2619,2623,2628,2632,2636,2641,2646],{"type":22,"tag":818,"props":2615,"children":2616},{"style":902},[2617],{"type":28,"value":2618},"   NSMutableData",{"type":22,"tag":818,"props":2620,"children":2621},{"style":825},[2622],{"type":28,"value":910},{"type":22,"tag":818,"props":2624,"children":2625},{"style":837},[2626],{"type":28,"value":2627}," mutableData ",{"type":22,"tag":818,"props":2629,"children":2630},{"style":825},[2631],{"type":28,"value":1903},{"type":22,"tag":818,"props":2633,"children":2634},{"style":837},[2635],{"type":28,"value":1017},{"type":22,"tag":818,"props":2637,"children":2638},{"style":902},[2639],{"type":28,"value":2640},"NSMutableData",{"type":22,"tag":818,"props":2642,"children":2643},{"style":902},[2644],{"type":28,"value":2645}," dataWithData:",{"type":22,"tag":818,"props":2647,"children":2648},{"style":837},[2649],{"type":28,"value":2587},{"type":22,"tag":818,"props":2651,"children":2652},{"class":820,"line":1135},[2653,2658,2663],{"type":22,"tag":818,"props":2654,"children":2655},{"style":837},[2656],{"type":28,"value":2657},"   [mutableData ",{"type":22,"tag":818,"props":2659,"children":2660},{"style":902},[2661],{"type":28,"value":2662},"appendData:",{"type":22,"tag":818,"props":2664,"children":2665},{"style":837},[2666],{"type":28,"value":1943},{"type":22,"tag":818,"props":2668,"children":2669},{"class":820,"line":1143},[2670,2674],{"type":22,"tag":818,"props":2671,"children":2672},{"style":825},[2673],{"type":28,"value":1012},{"type":22,"tag":818,"props":2675,"children":2676},{"style":837},[2677],{"type":28,"value":2678}," mutableData;\n",{"type":22,"tag":818,"props":2680,"children":2681},{"class":820,"line":1152},[2682],{"type":22,"tag":818,"props":2683,"children":2684},{"style":837},[2685],{"type":28,"value":1039},{"type":22,"tag":818,"props":2687,"children":2688},{"class":820,"line":1170},[2689],{"type":22,"tag":818,"props":2690,"children":2691},{"emptyLinePlaceholder":859},[2692],{"type":28,"value":862},{"type":22,"tag":818,"props":2694,"children":2695},{"class":820,"line":1178},[2696,2700,2704,2708,2713,2717,2721],{"type":22,"tag":818,"props":2697,"children":2698},{"style":825},[2699],{"type":28,"value":2435},{"type":22,"tag":818,"props":2701,"children":2702},{"style":837},[2703],{"type":28,"value":1254},{"type":22,"tag":818,"props":2705,"children":2706},{"style":825},[2707],{"type":28,"value":1196},{"type":22,"tag":818,"props":2709,"children":2710},{"style":837},[2711],{"type":28,"value":2712},")reverseTransformedValue:(",{"type":22,"tag":818,"props":2714,"children":2715},{"style":902},[2716],{"type":28,"value":799},{"type":22,"tag":818,"props":2718,"children":2719},{"style":825},[2720],{"type":28,"value":910},{"type":22,"tag":818,"props":2722,"children":2723},{"style":837},[2724],{"type":28,"value":1223},{"type":22,"tag":818,"props":2726,"children":2727},{"class":820,"line":1186},[2728],{"type":22,"tag":818,"props":2729,"children":2730},{"style":837},[2731],{"type":28,"value":1004},{"type":22,"tag":818,"props":2733,"children":2734},{"class":820,"line":1226},[2735],{"type":22,"tag":818,"props":2736,"children":2737},{"style":837},[2738],{"type":28,"value":2475},{"type":22,"tag":818,"props":2740,"children":2741},{"class":820,"line":1234},[2742],{"type":22,"tag":818,"props":2743,"children":2744},{"emptyLinePlaceholder":859},[2745],{"type":28,"value":862},{"type":22,"tag":818,"props":2747,"children":2748},{"class":820,"line":1243},[2749],{"type":22,"tag":818,"props":2750,"children":2751},{"style":869},[2752],{"type":28,"value":2753},"   // The IV was stored in the first 32 bytes of the data\n",{"type":22,"tag":818,"props":2755,"children":2756},{"class":820,"line":1286},[2757,2761,2765,2769,2773,2777,2782,2786,2791,2796,2801],{"type":22,"tag":818,"props":2758,"children":2759},{"style":902},[2760],{"type":28,"value":1889},{"type":22,"tag":818,"props":2762,"children":2763},{"style":825},[2764],{"type":28,"value":910},{"type":22,"tag":818,"props":2766,"children":2767},{"style":837},[2768],{"type":28,"value":2514},{"type":22,"tag":818,"props":2770,"children":2771},{"style":825},[2772],{"type":28,"value":1903},{"type":22,"tag":818,"props":2774,"children":2775},{"style":837},[2776],{"type":28,"value":1402},{"type":22,"tag":818,"props":2778,"children":2779},{"style":902},[2780],{"type":28,"value":2781},"subdataWithRange:NSMakeRange",{"type":22,"tag":818,"props":2783,"children":2784},{"style":837},[2785],{"type":28,"value":1210},{"type":22,"tag":818,"props":2787,"children":2788},{"style":902},[2789],{"type":28,"value":2790},"0",{"type":22,"tag":818,"props":2792,"children":2793},{"style":837},[2794],{"type":28,"value":2795},", ",{"type":22,"tag":818,"props":2797,"children":2798},{"style":902},[2799],{"type":28,"value":2800},"32",{"type":22,"tag":818,"props":2802,"children":2803},{"style":837},[2804],{"type":28,"value":2805},")];\n",{"type":22,"tag":818,"props":2807,"children":2808},{"class":820,"line":1295},[2809],{"type":22,"tag":818,"props":2810,"children":2811},{"emptyLinePlaceholder":859},[2812],{"type":28,"value":862},{"type":22,"tag":818,"props":2814,"children":2815},{"class":820,"line":1309},[2816],{"type":22,"tag":818,"props":2817,"children":2818},{"style":869},[2819],{"type":28,"value":2820},"   // Remove the IV from the encrypted data and decrypt it\n",{"type":22,"tag":818,"props":2822,"children":2823},{"class":820,"line":1318},[2824,2828,2832,2836,2840,2844,2848,2852],{"type":22,"tag":818,"props":2825,"children":2826},{"style":902},[2827],{"type":28,"value":2618},{"type":22,"tag":818,"props":2829,"children":2830},{"style":825},[2831],{"type":28,"value":910},{"type":22,"tag":818,"props":2833,"children":2834},{"style":837},[2835],{"type":28,"value":2627},{"type":22,"tag":818,"props":2837,"children":2838},{"style":825},[2839],{"type":28,"value":1903},{"type":22,"tag":818,"props":2841,"children":2842},{"style":837},[2843],{"type":28,"value":1017},{"type":22,"tag":818,"props":2845,"children":2846},{"style":902},[2847],{"type":28,"value":2640},{"type":22,"tag":818,"props":2849,"children":2850},{"style":902},[2851],{"type":28,"value":2645},{"type":22,"tag":818,"props":2853,"children":2854},{"style":837},[2855],{"type":28,"value":1943},{"type":22,"tag":818,"props":2857,"children":2858},{"class":820,"line":1326},[2859,2863,2868,2872,2876,2880,2884,2889,2894],{"type":22,"tag":818,"props":2860,"children":2861},{"style":837},[2862],{"type":28,"value":2657},{"type":22,"tag":818,"props":2864,"children":2865},{"style":902},[2866],{"type":28,"value":2867},"replaceBytesInRange:NSMakeRange",{"type":22,"tag":818,"props":2869,"children":2870},{"style":837},[2871],{"type":28,"value":1210},{"type":22,"tag":818,"props":2873,"children":2874},{"style":902},[2875],{"type":28,"value":2790},{"type":22,"tag":818,"props":2877,"children":2878},{"style":837},[2879],{"type":28,"value":2795},{"type":22,"tag":818,"props":2881,"children":2882},{"style":902},[2883],{"type":28,"value":2800},{"type":22,"tag":818,"props":2885,"children":2886},{"style":837},[2887],{"type":28,"value":2888},") ",{"type":22,"tag":818,"props":2890,"children":2891},{"style":902},[2892],{"type":28,"value":2893},"withBytes:NULL",{"type":22,"tag":818,"props":2895,"children":2896},{"style":837},[2897],{"type":28,"value":1031},{"type":22,"tag":818,"props":2899,"children":2900},{"class":820,"line":1351},[2901,2905,2910,2914,2918,2922,2926,2930,2934],{"type":22,"tag":818,"props":2902,"children":2903},{"style":825},[2904],{"type":28,"value":1012},{"type":22,"tag":818,"props":2906,"children":2907},{"style":837},[2908],{"type":28,"value":2909}," [mutableData ",{"type":22,"tag":818,"props":2911,"children":2912},{"style":902},[2913],{"type":28,"value":1647},{"type":22,"tag":818,"props":2915,"children":2916},{"style":837},[2917],{"type":28,"value":1412},{"type":22,"tag":818,"props":2919,"children":2920},{"style":902},[2921],{"type":28,"value":1273},{"type":22,"tag":818,"props":2923,"children":2924},{"style":902},[2925],{"type":28,"value":1278},{"type":22,"tag":818,"props":2927,"children":2928},{"style":837},[2929],{"type":28,"value":2120},{"type":22,"tag":818,"props":2931,"children":2932},{"style":902},[2933],{"type":28,"value":2582},{"type":22,"tag":818,"props":2935,"children":2936},{"style":837},[2937],{"type":28,"value":2587},{"type":22,"tag":818,"props":2939,"children":2940},{"class":820,"line":1359},[2941],{"type":22,"tag":818,"props":2942,"children":2943},{"style":837},[2944],{"type":28,"value":1039},{"type":22,"tag":31,"props":2946,"children":2947},{},[2948],{"type":28,"value":2949},"Now, every time an attribute value is saved, its encrypted version includes an extra stage of randomization that prevents comparisons between different attributes encrypted with the same key.",{"type":22,"tag":31,"props":2951,"children":2952},{},[2953],{"type":28,"value":2954},"Thus, with fairly minimal code that ensures resilient encryption, we have an easy way to store private information in Core Data attributes with as many different keys as necessary.",{"type":22,"tag":2956,"props":2957,"children":2958},"style",{},[2959],{"type":28,"value":2960},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":8,"searchDepth":387,"depth":387,"links":2962},[2963,2970],{"id":738,"depth":390,"text":741,"children":2964},[2965,2966,2967],{"id":804,"depth":387,"text":807},{"id":944,"depth":387,"text":947},{"id":1706,"depth":387,"text":807,"children":2968},[2969],{"id":1747,"depth":865,"text":947},{"id":2265,"depth":390,"text":2268,"children":2971},[2972],{"id":2417,"depth":865,"text":2420},"content:nharrison:2012-07:core-data.md","nharrison/2012-07/core-data.md","nharrison/2012-07/core-data",{"user":2977,"name":2978},"nharrison","Noah Harrison",{"_path":2980,"_dir":686,"_draft":7,"_partial":7,"_locale":8,"title":2981,"description":2982,"publishDate":2983,"tags":2984,"image":2986,"excerpt":2982,"body":2987,"_type":399,"_id":3151,"_source":401,"_file":3152,"_stem":3153,"_extension":404,"author":3154},"/shuey/2012-07/reset-button","The Reset Button","Horace Dediu of Asymco has been publishing some fantastic insights and analysis of the mobile market in the past few weeks. I linked to some of Dediu's analysis of the Economics of Android in an earlier post, and since then he's updated his work with the latest data and is studying RIM and Microsoft's efforts in the space as well.","2012-07-19",[2985,416,16],"android","/shuey/2012-07/img/kevin.jpg",{"type":19,"children":2988,"toc":3149},[2989,3012,3026,3031,3053,3103,3115,3129,3134],{"type":22,"tag":31,"props":2990,"children":2991},{},[2992,2994,3001,3003,3010],{"type":28,"value":2993},"Horace Dediu of ",{"type":22,"tag":110,"props":2995,"children":2998},{"href":2996,"rel":2997},"http://asymco.com",[114],[2999],{"type":28,"value":3000},"Asymco",{"type":28,"value":3002}," has been publishing some fantastic insights and analysis of the mobile market in the past few weeks. I linked to some of Dediu's analysis of the ",{"type":22,"tag":110,"props":3004,"children":3007},{"href":3005,"rel":3006},"http://blog.artlogic.com/2012/05/17/the-economics-of-android/",[114],[3008],{"type":28,"value":3009},"Economics of Android",{"type":28,"value":3011}," in an earlier post, and since then he's updated his work with the latest data and is studying RIM and Microsoft's efforts in the space as well.",{"type":22,"tag":31,"props":3013,"children":3014},{},[3015,3017,3024],{"type":28,"value":3016},"The recent episode of ",{"type":22,"tag":110,"props":3018,"children":3021},{"href":3019,"rel":3020},"http://5by5.tv/criticalpath/45",[114],[3022],{"type":28,"value":3023},"The Critical Path \"Management vs. Leadership\"",{"type":28,"value":3025}," is simply fantastic. In the episode he posits that management is the process of running the day to day operations, of keeping a well organized system moving. Leadership on the other hand, is about disruption, about what's next, about bold moves. He captures this with the phrase, \"pressing the reset button\". With these definitions in mind, a successful leader is one who disrupts their business at its peak, and unsuccessful ones wait too long to make any bold moves. Dediu cites the famous example of Steve Jobs killing off the popular iPod Mini line and wonders if Apple is now \"pressing the reset button\" on the iPad as it dominates the tablet market.",{"type":22,"tag":31,"props":3027,"children":3028},{},[3029],{"type":28,"value":3030},"With that in mind, what have some of Apple's competitors been up to?",{"type":22,"tag":31,"props":3032,"children":3033},{},[3034,3036,3043,3045,3052],{"type":28,"value":3035},"RIM is making desperate, not bold moves, and possibly far too late. It's considering selling its handset business, BlackBerry OS 10 is delayed, and it's ",{"type":22,"tag":110,"props":3037,"children":3040},{"href":3038,"rel":3039},"http://www.businessweek.com/videos/2012-07-10/rim-to-sell-corporate-jet",[114],[3041],{"type":28,"value":3042},"selling a corporate jet to save some cash",{"type":28,"value":3044},". It's stock price has fallen to record lows and the company just ",{"type":22,"tag":110,"props":3046,"children":3049},{"href":3047,"rel":3048},"http://www.morningstar.com/advisor/t/59341272/rim-found-guilty-of-infringing-mformation-patent.htm",[114],[3050],{"type":28,"value":3051},"lost a patent lawsuit to the tune of $142.7M",{"type":28,"value":296},{"type":22,"tag":31,"props":3054,"children":3055},{},[3056,3058,3065,3067,3074,3076,3083,3085,3092,3094,3101],{"type":28,"value":3057},"Microsoft is ",{"type":22,"tag":110,"props":3059,"children":3062},{"href":3060,"rel":3061},"http://www.bloomberg.com/news/2011-03-07/microsoft-is-said-to-pay-nokia-more-than-1-billion-under-software-accord.html",[114],[3063],{"type":28,"value":3064},"tied closely to Nokia",{"type":28,"value":3066}," who bet heavily on the Lumia series of smartphones. Estimates show that ",{"type":22,"tag":110,"props":3068,"children":3071},{"href":3069,"rel":3070},"http://www.asymco.com/2012/07/19/how-many-lumia-phones-were-shipped-in-the-us/",[114],[3072],{"type":28,"value":3073},"400k to 1M Lumias were sold in the US",{"type":28,"value":3075}," (updated 7/19/12 at 3:02pm) ",{"type":22,"tag":110,"props":3077,"children":3080},{"href":3078,"rel":3079},"http://www.asymco.com/2012/07/13/how-many-lumia/",[114],[3081],{"type":28,"value":3082},"that only 330k Lumias were sold in the US",{"type":28,"value":3084}," and their launch partner AT&T is now ",{"type":22,"tag":110,"props":3086,"children":3089},{"href":3087,"rel":3088},"http://news.cnet.com/8301-1035_3-57472577-94/at-t-slashes-nokia-lumia-900-price-by-half/?tag=mncol;txt",[114],[3090],{"type":28,"value":3091},"selling them for half price.",{"type":28,"value":3093}," Making matters worse, the Lumias aren't able to be upgraded to the newly demoed Windows Mobile 8 that was introduced alongside the new Surface tablet. In addition to competing with Apple's iPad, the Surface is set to compete against Microsoft's OEM partners, which ",{"type":22,"tag":110,"props":3095,"children":3098},{"href":3096,"rel":3097},"http://news.cnet.com/8301-10805_3-57469903-75/microsofts-surface-is-a-design-point-says-ceo/",[114],[3099],{"type":28,"value":3100},"they've tried to downplay",{"type":28,"value":3102},". Following the failed Zune and Kin brands, the struggling Lumia line which they backed heavily, the Surface brand has its work cut out for itself. Pricing and a release date haven't been announced yet, but it will be interesting to see when it ships and what it will retail for.",{"type":22,"tag":31,"props":3104,"children":3105},{},[3106,3113],{"type":22,"tag":110,"props":3107,"children":3110},{"href":3108,"rel":3109},"http://www.asymco.com/2012/07/16/from-bad-to-worse-and-from-good-to-great/",[114],[3111],{"type":28,"value":3112},"Samsung is making most of the money",{"type":28,"value":3114}," in the Android ecosystem and companies like HTC are suffering significant losses. In Dediu's analysis of HTC's woes it looks as if they've struggled to match Samsung in volume in their transition from a relatively low volume Windows Mobile smartphone business to Android. An area that Apple has excelled at, thanks largely to Tim Cook, is in volume, and they've been able to quickly ramp up production, purchase components in unheard of quantities, and are investing billions in their production facilities. This is an area that Microsoft may struggle in as well. Their Xbox business doesn't come close in size to the iPad or iPhone in units produced.",{"type":22,"tag":31,"props":3116,"children":3117},{},[3118,3120,3127],{"type":28,"value":3119},"Google's new Android tablet, the ",{"type":22,"tag":110,"props":3121,"children":3124},{"href":3122,"rel":3123},"http://www.google.com/nexus/#/7",[114],[3125],{"type":28,"value":3126},"Google Nexus 7",{"type":28,"value":3128}," is getting good reviews, but looks to compete more with Amazon's Kindle Fire than the iPad. However, both devices are US only for the most part due to the lack of content distribution deals internationally which Apple has worked hard to establish. The US market is becoming an increasingly smaller piece of the worldwide mobile market so it will be interesting to see how Amazon and Google respond.",{"type":22,"tag":31,"props":3130,"children":3131},{},[3132],{"type":28,"value":3133},"Apple is set to release their third quarter earnings next Tuesday and rumors are swirling that a 7.85\" iPad and iPhone 5 will be announced and ship in September or October.  Will these products be an evolution of the current lineup or will there be some indications that the reset button has been pressed in Cupertino?",{"type":22,"tag":31,"props":3135,"children":3136},{},[3137],{"type":22,"tag":37,"props":3138,"children":3139},{},[3140,3142],{"type":28,"value":3141},"Image credit: ",{"type":22,"tag":110,"props":3143,"children":3146},{"href":3144,"rel":3145},"http://www.flickr.com/photos/fortunelivemedia/",[114],[3147],{"type":28,"value":3148},"Fortune Live Media",{"title":8,"searchDepth":387,"depth":387,"links":3150},[],"content:shuey:2012-07:reset-button.md","shuey/2012-07/reset-button.md","shuey/2012-07/reset-button",{"user":3155,"name":3156},"shuey","Steven Huey",{"_path":3158,"_dir":686,"_draft":7,"_partial":7,"_locale":8,"title":3159,"description":3160,"publishDate":3161,"tags":3162,"image":3164,"excerpt":3160,"body":3165,"_type":399,"_id":5090,"_source":401,"_file":5091,"_stem":5092,"_extension":404,"author":5093},"/shuey/2012-07/mixer","A Simple Mixer Using AVFoundation","In iOS 4.0 Apple introduced the AV Foundation APIs that made working with audio and video media much easier than it had been in previous versions of iOS. Apple then brought these APIs to Mac OS X in OS X 10.7 \"Lion\". In this post I'll show how to use some of the APIs to create a simple four track mixer.","2012-07-02",[416,3163,16],"cocoa","/shuey/2012-07/img/mixer-screenshot.jpg",{"type":19,"children":3166,"toc":5088},[3167,3181,3213,3221,3244,3267,4144,4167,4175,4358,4363,4371,4544,4549,4557,4660,4665,4673,5043,5066,5074,5079,5084],{"type":22,"tag":31,"props":3168,"children":3169},{},[3170,3172,3179],{"type":28,"value":3171},"In iOS 4.0 Apple introduced the ",{"type":22,"tag":110,"props":3173,"children":3176},{"href":3174,"rel":3175},"https://developer.apple.com/library/mac/#documentation/AudioVideo/Conceptual/AVFoundationPG/Articles/00_Introduction.html#//apple_ref/doc/uid/TP40010188",[114],[3177],{"type":28,"value":3178},"AV Foundation APIs",{"type":28,"value":3180}," that made working with audio and video media much easier than it had been in previous versions of iOS. Apple then brought these APIs to Mac OS X in OS X 10.7 \"Lion\". In this post I'll show how to use some of the APIs to create a simple four track mixer.",{"type":22,"tag":31,"props":3182,"children":3183},{},[3184,3186,3193,3195,3202,3204,3211],{"type":28,"value":3185},"The code for the project is ",{"type":22,"tag":110,"props":3187,"children":3190},{"href":3188,"rel":3189},"https://github.com/stevenhuey/ALMixer",[114],[3191],{"type":28,"value":3192},"available on GitHub",{"type":28,"value":3194},". You'll need to provide your own audio files. The project is setup to use four WAV files named track1.wav - track4.wav but the ",{"type":22,"tag":110,"props":3196,"children":3199},{"href":3197,"rel":3198},"https://github.com/stevenhuey/ALMixer/blob/master/README.md",[114],[3200],{"type":28,"value":3201},"ReadMe.md",{"type":28,"value":3203}," lists the two lines of code you need to change to use another audio format or naming scheme. Obviously you need to use an audio format supported by iOS. The project is configured to use ",{"type":22,"tag":110,"props":3205,"children":3208},{"href":3206,"rel":3207},"https://developer.apple.com/library/ios/#releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html#//apple_ref/doc/uid/TP40011226",[114],[3209],{"type":28,"value":3210},"ARC",{"type":28,"value":3212}," (Automatic Reference Counting).",{"type":22,"tag":31,"props":3214,"children":3215},{},[3216],{"type":22,"tag":41,"props":3217,"children":3218},{},[3219],{"type":28,"value":3220},"Setup",{"type":22,"tag":31,"props":3222,"children":3223},{},[3224,3226,3233,3235,3242],{"type":28,"value":3225},"To start we'll create an ",{"type":22,"tag":110,"props":3227,"children":3230},{"href":3228,"rel":3229},"https://developer.apple.com/library/ios/#documentation/AVFoundation/Reference/AVMutableComposition_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40009526",[114],[3231],{"type":28,"value":3232},"AVMutableComposition",{"type":28,"value":3234}," instance and two ",{"type":22,"tag":110,"props":3236,"children":3239},{"href":3237,"rel":3238},"https://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Classes/NSMutableDictionary_Class/Reference/Reference.html",[114],[3240],{"type":28,"value":3241},"NSMutableDictionaries",{"type":28,"value":3243},". We'll use the dictionaries for keeping track of the IDs assigned to the audio tracks by the AVFoundation framework and for storing the volume level of each track.",{"type":22,"tag":31,"props":3245,"children":3246},{},[3247,3249,3256,3258,3265],{"type":28,"value":3248},"Our audio tracks are loaded from the Resources directory within the app bundle using the ",{"type":22,"tag":110,"props":3250,"children":3253},{"href":3251,"rel":3252},"https://developer.apple.com/library/ios/#documentation/AVFoundation/Reference/AVURLAsset_Class/Reference/Reference.html",[114],[3254],{"type":28,"value":3255},"AVURLAsset",{"type":28,"value":3257}," class and then used to create an ",{"type":22,"tag":110,"props":3259,"children":3262},{"href":3260,"rel":3261},"https://developer.apple.com/library/ios/#documentation/AVFoundation/Reference/AVMutableCompositionTrack_Class/Reference/Reference.html",[114],[3263],{"type":28,"value":3264},"AVMutableCompositionTrack",{"type":28,"value":3266}," that we insert into our AVMutableComposition. We record the ID of the track and set the track volume to 1.0, the maximum. The volume for each track can be set from 0.0 - 1.0.",{"type":22,"tag":274,"props":3268,"children":3272},{"className":3269,"code":3270,"language":3271,"meta":8,"style":8},"language-swift shiki shiki-themes github-light github-dark","// Setup\n   _composition = [AVMutableComposition composition];\n\n   _audioMixValues = [[NSMutableDictionary alloc] initWithCapacity:0];\n   _audioMixTrackIDs = [[NSMutableDictionary alloc] initWithCapacity:0];\n\n   // Insert the audio tracks into our composition\n   NSArray* tracks = [NSArray arrayWithObjects:@\"track1\", @\"track2\", @\"track3\", @\"track4\", nil];\n   NSString* audioFileType = @\"wav\";\n\n   for (NSString* trackName in tracks)\n   {\n      AVURLAsset* audioAsset = [[AVURLAsset alloc]initWithURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:trackName ofType:audioFileType]]\n                                                      options:nil];\n\n      AVMutableCompositionTrack* audioTrack = [_composition addMutableTrackWithMediaType:AVMediaTypeAudio\n                                                                        preferredTrackID:kCMPersistentTrackID_Invalid];\n\n      NSError* error;\n      [audioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, audioAsset.duration)\n                          ofTrack:[[audioAsset tracksWithMediaType:AVMediaTypeAudio]objectAtIndex:0]\n                           atTime:kCMTimeZero\n                            error:&error];\n\n      if (error)\n      {\n         NSLog(@\"%@\", [error localizedDescription]);\n      }\n\n      // Store the track IDs as track name -> track ID\n      [_audioMixTrackIDs setValue:[NSNumber numberWithInteger:audioTrack.trackID]\n                           forKey:trackName];\n\n      // Set the volume to 1.0 (max) for the track\n      [self setVolume:1.0f forTrack:trackName];\n   }\n\n   // Create a player for our composition of audio tracks. We observe the status so\n   // we know when the player is ready to play\n   AVPlayerItem* playerItem = [[AVPlayerItem alloc] initWithAsset:[_composition copy]];\n   [playerItem addObserver:self\n                forKeyPath:@\"status\"\n                   options:0\n                   context:NULL];\n\n   _player = [[AVPlayer alloc] initWithPlayerItem:playerItem];\n","swift",[3273],{"type":22,"tag":155,"props":3274,"children":3275},{"__ignoreMap":8},[3276,3284,3301,3308,3338,3366,3373,3381,3461,3496,3503,3535,3542,3604,3624,3631,3666,3683,3690,3707,3729,3767,3784,3802,3809,3822,3830,3853,3861,3868,3876,3902,3919,3926,3934,3974,3981,3988,3996,4004,4039,4056,4077,4094,4111,4118],{"type":22,"tag":818,"props":3277,"children":3278},{"class":820,"line":821},[3279],{"type":22,"tag":818,"props":3280,"children":3281},{"style":869},[3282],{"type":28,"value":3283},"// Setup\n",{"type":22,"tag":818,"props":3285,"children":3286},{"class":820,"line":390},[3287,3292,3296],{"type":22,"tag":818,"props":3288,"children":3289},{"style":837},[3290],{"type":28,"value":3291},"   _composition ",{"type":22,"tag":818,"props":3293,"children":3294},{"style":825},[3295],{"type":28,"value":1903},{"type":22,"tag":818,"props":3297,"children":3298},{"style":837},[3299],{"type":28,"value":3300}," [AVMutableComposition composition];\n",{"type":22,"tag":818,"props":3302,"children":3303},{"class":820,"line":387},[3304],{"type":22,"tag":818,"props":3305,"children":3306},{"emptyLinePlaceholder":859},[3307],{"type":28,"value":862},{"type":22,"tag":818,"props":3309,"children":3310},{"class":820,"line":865},[3311,3316,3320,3325,3330,3334],{"type":22,"tag":818,"props":3312,"children":3313},{"style":837},[3314],{"type":28,"value":3315},"   _audioMixValues ",{"type":22,"tag":818,"props":3317,"children":3318},{"style":825},[3319],{"type":28,"value":1903},{"type":22,"tag":818,"props":3321,"children":3322},{"style":837},[3323],{"type":28,"value":3324}," [[NSMutableDictionary alloc] initWithCapacity",{"type":22,"tag":818,"props":3326,"children":3327},{"style":825},[3328],{"type":28,"value":3329},":",{"type":22,"tag":818,"props":3331,"children":3332},{"style":902},[3333],{"type":28,"value":2790},{"type":22,"tag":818,"props":3335,"children":3336},{"style":837},[3337],{"type":28,"value":1031},{"type":22,"tag":818,"props":3339,"children":3340},{"class":820,"line":875},[3341,3346,3350,3354,3358,3362],{"type":22,"tag":818,"props":3342,"children":3343},{"style":837},[3344],{"type":28,"value":3345},"   _audioMixTrackIDs ",{"type":22,"tag":818,"props":3347,"children":3348},{"style":825},[3349],{"type":28,"value":1903},{"type":22,"tag":818,"props":3351,"children":3352},{"style":837},[3353],{"type":28,"value":3324},{"type":22,"tag":818,"props":3355,"children":3356},{"style":825},[3357],{"type":28,"value":3329},{"type":22,"tag":818,"props":3359,"children":3360},{"style":902},[3361],{"type":28,"value":2790},{"type":22,"tag":818,"props":3363,"children":3364},{"style":837},[3365],{"type":28,"value":1031},{"type":22,"tag":818,"props":3367,"children":3368},{"class":820,"line":884},[3369],{"type":22,"tag":818,"props":3370,"children":3371},{"emptyLinePlaceholder":859},[3372],{"type":28,"value":862},{"type":22,"tag":818,"props":3374,"children":3375},{"class":820,"line":893},[3376],{"type":22,"tag":818,"props":3377,"children":3378},{"style":869},[3379],{"type":28,"value":3380},"   // Insert the audio tracks into our composition\n",{"type":22,"tag":818,"props":3382,"children":3383},{"class":820,"line":927},[3384,3389,3393,3398,3402,3407,3411,3416,3421,3426,3431,3435,3440,3444,3449,3453,3457],{"type":22,"tag":818,"props":3385,"children":3386},{"style":837},[3387],{"type":28,"value":3388},"   NSArray",{"type":22,"tag":818,"props":3390,"children":3391},{"style":825},[3392],{"type":28,"value":910},{"type":22,"tag":818,"props":3394,"children":3395},{"style":837},[3396],{"type":28,"value":3397}," tracks ",{"type":22,"tag":818,"props":3399,"children":3400},{"style":825},[3401],{"type":28,"value":1903},{"type":22,"tag":818,"props":3403,"children":3404},{"style":837},[3405],{"type":28,"value":3406}," [NSArray arrayWithObjects",{"type":22,"tag":818,"props":3408,"children":3409},{"style":825},[3410],{"type":28,"value":3329},{"type":22,"tag":818,"props":3412,"children":3413},{"style":837},[3414],{"type":28,"value":3415},"@",{"type":22,"tag":818,"props":3417,"children":3418},{"style":1160},[3419],{"type":28,"value":3420},"\"track1\"",{"type":22,"tag":818,"props":3422,"children":3423},{"style":837},[3424],{"type":28,"value":3425},", @",{"type":22,"tag":818,"props":3427,"children":3428},{"style":1160},[3429],{"type":28,"value":3430},"\"track2\"",{"type":22,"tag":818,"props":3432,"children":3433},{"style":837},[3434],{"type":28,"value":3425},{"type":22,"tag":818,"props":3436,"children":3437},{"style":1160},[3438],{"type":28,"value":3439},"\"track3\"",{"type":22,"tag":818,"props":3441,"children":3442},{"style":837},[3443],{"type":28,"value":3425},{"type":22,"tag":818,"props":3445,"children":3446},{"style":1160},[3447],{"type":28,"value":3448},"\"track4\"",{"type":22,"tag":818,"props":3450,"children":3451},{"style":837},[3452],{"type":28,"value":2795},{"type":22,"tag":818,"props":3454,"children":3455},{"style":902},[3456],{"type":28,"value":1259},{"type":22,"tag":818,"props":3458,"children":3459},{"style":837},[3460],{"type":28,"value":1031},{"type":22,"tag":818,"props":3462,"children":3463},{"class":820,"line":935},[3464,3469,3473,3478,3482,3487,3492],{"type":22,"tag":818,"props":3465,"children":3466},{"style":837},[3467],{"type":28,"value":3468},"   NSString",{"type":22,"tag":818,"props":3470,"children":3471},{"style":825},[3472],{"type":28,"value":910},{"type":22,"tag":818,"props":3474,"children":3475},{"style":837},[3476],{"type":28,"value":3477}," audioFileType ",{"type":22,"tag":818,"props":3479,"children":3480},{"style":825},[3481],{"type":28,"value":1903},{"type":22,"tag":818,"props":3483,"children":3484},{"style":837},[3485],{"type":28,"value":3486}," @",{"type":22,"tag":818,"props":3488,"children":3489},{"style":1160},[3490],{"type":28,"value":3491},"\"wav\"",{"type":22,"tag":818,"props":3493,"children":3494},{"style":837},[3495],{"type":28,"value":924},{"type":22,"tag":818,"props":3497,"children":3498},{"class":820,"line":1077},[3499],{"type":22,"tag":818,"props":3500,"children":3501},{"emptyLinePlaceholder":859},[3502],{"type":28,"value":862},{"type":22,"tag":818,"props":3504,"children":3505},{"class":820,"line":1094},[3506,3511,3516,3520,3525,3530],{"type":22,"tag":818,"props":3507,"children":3508},{"style":825},[3509],{"type":28,"value":3510},"   for",{"type":22,"tag":818,"props":3512,"children":3513},{"style":837},[3514],{"type":28,"value":3515}," (NSString",{"type":22,"tag":818,"props":3517,"children":3518},{"style":825},[3519],{"type":28,"value":910},{"type":22,"tag":818,"props":3521,"children":3522},{"style":837},[3523],{"type":28,"value":3524}," trackName ",{"type":22,"tag":818,"props":3526,"children":3527},{"style":825},[3528],{"type":28,"value":3529},"in",{"type":22,"tag":818,"props":3531,"children":3532},{"style":837},[3533],{"type":28,"value":3534}," tracks)\n",{"type":22,"tag":818,"props":3536,"children":3537},{"class":820,"line":1102},[3538],{"type":22,"tag":818,"props":3539,"children":3540},{"style":837},[3541],{"type":28,"value":1292},{"type":22,"tag":818,"props":3543,"children":3544},{"class":820,"line":1110},[3545,3550,3554,3559,3563,3568,3572,3577,3581,3586,3590,3595,3599],{"type":22,"tag":818,"props":3546,"children":3547},{"style":837},[3548],{"type":28,"value":3549},"      AVURLAsset",{"type":22,"tag":818,"props":3551,"children":3552},{"style":825},[3553],{"type":28,"value":910},{"type":22,"tag":818,"props":3555,"children":3556},{"style":837},[3557],{"type":28,"value":3558}," audioAsset ",{"type":22,"tag":818,"props":3560,"children":3561},{"style":825},[3562],{"type":28,"value":1903},{"type":22,"tag":818,"props":3564,"children":3565},{"style":837},[3566],{"type":28,"value":3567}," [[AVURLAsset alloc]initWithURL",{"type":22,"tag":818,"props":3569,"children":3570},{"style":825},[3571],{"type":28,"value":3329},{"type":22,"tag":818,"props":3573,"children":3574},{"style":837},[3575],{"type":28,"value":3576},"[NSURL fileURLWithPath",{"type":22,"tag":818,"props":3578,"children":3579},{"style":825},[3580],{"type":28,"value":3329},{"type":22,"tag":818,"props":3582,"children":3583},{"style":837},[3584],{"type":28,"value":3585},"[[NSBundle mainBundle] pathForResource",{"type":22,"tag":818,"props":3587,"children":3588},{"style":825},[3589],{"type":28,"value":3329},{"type":22,"tag":818,"props":3591,"children":3592},{"style":837},[3593],{"type":28,"value":3594},"trackName ofType",{"type":22,"tag":818,"props":3596,"children":3597},{"style":825},[3598],{"type":28,"value":3329},{"type":22,"tag":818,"props":3600,"children":3601},{"style":837},[3602],{"type":28,"value":3603},"audioFileType]]\n",{"type":22,"tag":818,"props":3605,"children":3606},{"class":820,"line":1135},[3607,3612,3616,3620],{"type":22,"tag":818,"props":3608,"children":3609},{"style":837},[3610],{"type":28,"value":3611},"                                                      options",{"type":22,"tag":818,"props":3613,"children":3614},{"style":825},[3615],{"type":28,"value":3329},{"type":22,"tag":818,"props":3617,"children":3618},{"style":902},[3619],{"type":28,"value":1259},{"type":22,"tag":818,"props":3621,"children":3622},{"style":837},[3623],{"type":28,"value":1031},{"type":22,"tag":818,"props":3625,"children":3626},{"class":820,"line":1143},[3627],{"type":22,"tag":818,"props":3628,"children":3629},{"emptyLinePlaceholder":859},[3630],{"type":28,"value":862},{"type":22,"tag":818,"props":3632,"children":3633},{"class":820,"line":1152},[3634,3639,3643,3648,3652,3657,3661],{"type":22,"tag":818,"props":3635,"children":3636},{"style":837},[3637],{"type":28,"value":3638},"      AVMutableCompositionTrack",{"type":22,"tag":818,"props":3640,"children":3641},{"style":825},[3642],{"type":28,"value":910},{"type":22,"tag":818,"props":3644,"children":3645},{"style":837},[3646],{"type":28,"value":3647}," audioTrack ",{"type":22,"tag":818,"props":3649,"children":3650},{"style":825},[3651],{"type":28,"value":1903},{"type":22,"tag":818,"props":3653,"children":3654},{"style":837},[3655],{"type":28,"value":3656}," [_composition addMutableTrackWithMediaType",{"type":22,"tag":818,"props":3658,"children":3659},{"style":825},[3660],{"type":28,"value":3329},{"type":22,"tag":818,"props":3662,"children":3663},{"style":837},[3664],{"type":28,"value":3665},"AVMediaTypeAudio\n",{"type":22,"tag":818,"props":3667,"children":3668},{"class":820,"line":1170},[3669,3674,3678],{"type":22,"tag":818,"props":3670,"children":3671},{"style":837},[3672],{"type":28,"value":3673},"                                                                        preferredTrackID",{"type":22,"tag":818,"props":3675,"children":3676},{"style":825},[3677],{"type":28,"value":3329},{"type":22,"tag":818,"props":3679,"children":3680},{"style":837},[3681],{"type":28,"value":3682},"kCMPersistentTrackID_Invalid];\n",{"type":22,"tag":818,"props":3684,"children":3685},{"class":820,"line":1178},[3686],{"type":22,"tag":818,"props":3687,"children":3688},{"emptyLinePlaceholder":859},[3689],{"type":28,"value":862},{"type":22,"tag":818,"props":3691,"children":3692},{"class":820,"line":1186},[3693,3698,3702],{"type":22,"tag":818,"props":3694,"children":3695},{"style":837},[3696],{"type":28,"value":3697},"      NSError",{"type":22,"tag":818,"props":3699,"children":3700},{"style":825},[3701],{"type":28,"value":910},{"type":22,"tag":818,"props":3703,"children":3704},{"style":837},[3705],{"type":28,"value":3706}," error;\n",{"type":22,"tag":818,"props":3708,"children":3709},{"class":820,"line":1226},[3710,3715,3719,3724],{"type":22,"tag":818,"props":3711,"children":3712},{"style":837},[3713],{"type":28,"value":3714},"      [audioTrack insertTimeRange",{"type":22,"tag":818,"props":3716,"children":3717},{"style":825},[3718],{"type":28,"value":3329},{"type":22,"tag":818,"props":3720,"children":3721},{"style":902},[3722],{"type":28,"value":3723},"CMTimeRangeMake",{"type":22,"tag":818,"props":3725,"children":3726},{"style":837},[3727],{"type":28,"value":3728},"(kCMTimeZero, audioAsset.duration)\n",{"type":22,"tag":818,"props":3730,"children":3731},{"class":820,"line":1234},[3732,3737,3741,3746,3750,3755,3759,3763],{"type":22,"tag":818,"props":3733,"children":3734},{"style":837},[3735],{"type":28,"value":3736},"                          ofTrack",{"type":22,"tag":818,"props":3738,"children":3739},{"style":825},[3740],{"type":28,"value":3329},{"type":22,"tag":818,"props":3742,"children":3743},{"style":837},[3744],{"type":28,"value":3745},"[[audioAsset tracksWithMediaType",{"type":22,"tag":818,"props":3747,"children":3748},{"style":825},[3749],{"type":28,"value":3329},{"type":22,"tag":818,"props":3751,"children":3752},{"style":837},[3753],{"type":28,"value":3754},"AVMediaTypeAudio]objectAtIndex",{"type":22,"tag":818,"props":3756,"children":3757},{"style":825},[3758],{"type":28,"value":3329},{"type":22,"tag":818,"props":3760,"children":3761},{"style":902},[3762],{"type":28,"value":2790},{"type":22,"tag":818,"props":3764,"children":3765},{"style":837},[3766],{"type":28,"value":2140},{"type":22,"tag":818,"props":3768,"children":3769},{"class":820,"line":1243},[3770,3775,3779],{"type":22,"tag":818,"props":3771,"children":3772},{"style":837},[3773],{"type":28,"value":3774},"                           atTime",{"type":22,"tag":818,"props":3776,"children":3777},{"style":825},[3778],{"type":28,"value":3329},{"type":22,"tag":818,"props":3780,"children":3781},{"style":837},[3782],{"type":28,"value":3783},"kCMTimeZero\n",{"type":22,"tag":818,"props":3785,"children":3786},{"class":820,"line":1286},[3787,3792,3797],{"type":22,"tag":818,"props":3788,"children":3789},{"style":837},[3790],{"type":28,"value":3791},"                            error",{"type":22,"tag":818,"props":3793,"children":3794},{"style":825},[3795],{"type":28,"value":3796},":&",{"type":22,"tag":818,"props":3798,"children":3799},{"style":837},[3800],{"type":28,"value":3801},"error];\n",{"type":22,"tag":818,"props":3803,"children":3804},{"class":820,"line":1295},[3805],{"type":22,"tag":818,"props":3806,"children":3807},{"emptyLinePlaceholder":859},[3808],{"type":28,"value":862},{"type":22,"tag":818,"props":3810,"children":3811},{"class":820,"line":1309},[3812,3817],{"type":22,"tag":818,"props":3813,"children":3814},{"style":825},[3815],{"type":28,"value":3816},"      if",{"type":22,"tag":818,"props":3818,"children":3819},{"style":837},[3820],{"type":28,"value":3821}," (error)\n",{"type":22,"tag":818,"props":3823,"children":3824},{"class":820,"line":1318},[3825],{"type":22,"tag":818,"props":3826,"children":3827},{"style":837},[3828],{"type":28,"value":3829},"      {\n",{"type":22,"tag":818,"props":3831,"children":3832},{"class":820,"line":1326},[3833,3838,3843,3848],{"type":22,"tag":818,"props":3834,"children":3835},{"style":902},[3836],{"type":28,"value":3837},"         NSLog",{"type":22,"tag":818,"props":3839,"children":3840},{"style":837},[3841],{"type":28,"value":3842},"(@",{"type":22,"tag":818,"props":3844,"children":3845},{"style":1160},[3846],{"type":28,"value":3847},"\"%@\"",{"type":22,"tag":818,"props":3849,"children":3850},{"style":837},[3851],{"type":28,"value":3852},", [error localizedDescription]);\n",{"type":22,"tag":818,"props":3854,"children":3855},{"class":820,"line":1351},[3856],{"type":22,"tag":818,"props":3857,"children":3858},{"style":837},[3859],{"type":28,"value":3860},"      }\n",{"type":22,"tag":818,"props":3862,"children":3863},{"class":820,"line":1359},[3864],{"type":22,"tag":818,"props":3865,"children":3866},{"emptyLinePlaceholder":859},[3867],{"type":28,"value":862},{"type":22,"tag":818,"props":3869,"children":3870},{"class":820,"line":1376},[3871],{"type":22,"tag":818,"props":3872,"children":3873},{"style":869},[3874],{"type":28,"value":3875},"      // Store the track IDs as track name -> track ID\n",{"type":22,"tag":818,"props":3877,"children":3878},{"class":820,"line":1384},[3879,3884,3888,3893,3897],{"type":22,"tag":818,"props":3880,"children":3881},{"style":837},[3882],{"type":28,"value":3883},"      [_audioMixTrackIDs setValue",{"type":22,"tag":818,"props":3885,"children":3886},{"style":825},[3887],{"type":28,"value":3329},{"type":22,"tag":818,"props":3889,"children":3890},{"style":837},[3891],{"type":28,"value":3892},"[NSNumber numberWithInteger",{"type":22,"tag":818,"props":3894,"children":3895},{"style":825},[3896],{"type":28,"value":3329},{"type":22,"tag":818,"props":3898,"children":3899},{"style":837},[3900],{"type":28,"value":3901},"audioTrack.trackID]\n",{"type":22,"tag":818,"props":3903,"children":3904},{"class":820,"line":1392},[3905,3910,3914],{"type":22,"tag":818,"props":3906,"children":3907},{"style":837},[3908],{"type":28,"value":3909},"                           forKey",{"type":22,"tag":818,"props":3911,"children":3912},{"style":825},[3913],{"type":28,"value":3329},{"type":22,"tag":818,"props":3915,"children":3916},{"style":837},[3917],{"type":28,"value":3918},"trackName];\n",{"type":22,"tag":818,"props":3920,"children":3921},{"class":820,"line":1428},[3922],{"type":22,"tag":818,"props":3923,"children":3924},{"emptyLinePlaceholder":859},[3925],{"type":28,"value":862},{"type":22,"tag":818,"props":3927,"children":3928},{"class":820,"line":1436},[3929],{"type":22,"tag":818,"props":3930,"children":3931},{"style":869},[3932],{"type":28,"value":3933},"      // Set the volume to 1.0 (max) for the track\n",{"type":22,"tag":818,"props":3935,"children":3936},{"class":820,"line":1444},[3937,3942,3946,3951,3955,3961,3966,3970],{"type":22,"tag":818,"props":3938,"children":3939},{"style":837},[3940],{"type":28,"value":3941},"      [",{"type":22,"tag":818,"props":3943,"children":3944},{"style":902},[3945],{"type":28,"value":1273},{"type":22,"tag":818,"props":3947,"children":3948},{"style":837},[3949],{"type":28,"value":3950}," setVolume",{"type":22,"tag":818,"props":3952,"children":3953},{"style":825},[3954],{"type":28,"value":3329},{"type":22,"tag":818,"props":3956,"children":3958},{"style":3957},"--shiki-default:#B31D28;--shiki-default-font-style:italic;--shiki-dark:#FDAEB7;--shiki-dark-font-style:italic",[3959],{"type":28,"value":3960},"1.0f",{"type":22,"tag":818,"props":3962,"children":3963},{"style":837},[3964],{"type":28,"value":3965}," forTrack",{"type":22,"tag":818,"props":3967,"children":3968},{"style":825},[3969],{"type":28,"value":3329},{"type":22,"tag":818,"props":3971,"children":3972},{"style":837},[3973],{"type":28,"value":3918},{"type":22,"tag":818,"props":3975,"children":3976},{"class":820,"line":1481},[3977],{"type":22,"tag":818,"props":3978,"children":3979},{"style":837},[3980],{"type":28,"value":1315},{"type":22,"tag":818,"props":3982,"children":3983},{"class":820,"line":1489},[3984],{"type":22,"tag":818,"props":3985,"children":3986},{"emptyLinePlaceholder":859},[3987],{"type":28,"value":862},{"type":22,"tag":818,"props":3989,"children":3990},{"class":820,"line":1497},[3991],{"type":22,"tag":818,"props":3992,"children":3993},{"style":869},[3994],{"type":28,"value":3995},"   // Create a player for our composition of audio tracks. We observe the status so\n",{"type":22,"tag":818,"props":3997,"children":3998},{"class":820,"line":1533},[3999],{"type":22,"tag":818,"props":4000,"children":4001},{"style":869},[4002],{"type":28,"value":4003},"   // we know when the player is ready to play\n",{"type":22,"tag":818,"props":4005,"children":4006},{"class":820,"line":1541},[4007,4012,4016,4021,4025,4030,4034],{"type":22,"tag":818,"props":4008,"children":4009},{"style":837},[4010],{"type":28,"value":4011},"   AVPlayerItem",{"type":22,"tag":818,"props":4013,"children":4014},{"style":825},[4015],{"type":28,"value":910},{"type":22,"tag":818,"props":4017,"children":4018},{"style":837},[4019],{"type":28,"value":4020}," playerItem ",{"type":22,"tag":818,"props":4022,"children":4023},{"style":825},[4024],{"type":28,"value":1903},{"type":22,"tag":818,"props":4026,"children":4027},{"style":837},[4028],{"type":28,"value":4029}," [[AVPlayerItem alloc] initWithAsset",{"type":22,"tag":818,"props":4031,"children":4032},{"style":825},[4033],{"type":28,"value":3329},{"type":22,"tag":818,"props":4035,"children":4036},{"style":837},[4037],{"type":28,"value":4038},"[_composition copy]];\n",{"type":22,"tag":818,"props":4040,"children":4041},{"class":820,"line":1553},[4042,4047,4051],{"type":22,"tag":818,"props":4043,"children":4044},{"style":837},[4045],{"type":28,"value":4046},"   [playerItem addObserver",{"type":22,"tag":818,"props":4048,"children":4049},{"style":825},[4050],{"type":28,"value":3329},{"type":22,"tag":818,"props":4052,"children":4053},{"style":902},[4054],{"type":28,"value":4055},"self\n",{"type":22,"tag":818,"props":4057,"children":4058},{"class":820,"line":1561},[4059,4064,4068,4072],{"type":22,"tag":818,"props":4060,"children":4061},{"style":837},[4062],{"type":28,"value":4063},"                forKeyPath",{"type":22,"tag":818,"props":4065,"children":4066},{"style":825},[4067],{"type":28,"value":3329},{"type":22,"tag":818,"props":4069,"children":4070},{"style":837},[4071],{"type":28,"value":3415},{"type":22,"tag":818,"props":4073,"children":4074},{"style":1160},[4075],{"type":28,"value":4076},"\"status\"\n",{"type":22,"tag":818,"props":4078,"children":4079},{"class":820,"line":1569},[4080,4085,4089],{"type":22,"tag":818,"props":4081,"children":4082},{"style":837},[4083],{"type":28,"value":4084},"                   options",{"type":22,"tag":818,"props":4086,"children":4087},{"style":825},[4088],{"type":28,"value":3329},{"type":22,"tag":818,"props":4090,"children":4091},{"style":902},[4092],{"type":28,"value":4093},"0\n",{"type":22,"tag":818,"props":4095,"children":4096},{"class":820,"line":1593},[4097,4102,4106],{"type":22,"tag":818,"props":4098,"children":4099},{"style":837},[4100],{"type":28,"value":4101},"                   context",{"type":22,"tag":818,"props":4103,"children":4104},{"style":825},[4105],{"type":28,"value":3329},{"type":22,"tag":818,"props":4107,"children":4108},{"style":837},[4109],{"type":28,"value":4110},"NULL];\n",{"type":22,"tag":818,"props":4112,"children":4113},{"class":820,"line":1601},[4114],{"type":22,"tag":818,"props":4115,"children":4116},{"emptyLinePlaceholder":859},[4117],{"type":28,"value":862},{"type":22,"tag":818,"props":4119,"children":4120},{"class":820,"line":1617},[4121,4126,4130,4135,4139],{"type":22,"tag":818,"props":4122,"children":4123},{"style":837},[4124],{"type":28,"value":4125},"   _player ",{"type":22,"tag":818,"props":4127,"children":4128},{"style":825},[4129],{"type":28,"value":1903},{"type":22,"tag":818,"props":4131,"children":4132},{"style":837},[4133],{"type":28,"value":4134}," [[AVPlayer alloc] initWithPlayerItem",{"type":22,"tag":818,"props":4136,"children":4137},{"style":825},[4138],{"type":28,"value":3329},{"type":22,"tag":818,"props":4140,"children":4141},{"style":837},[4142],{"type":28,"value":4143},"playerItem];\n",{"type":22,"tag":31,"props":4145,"children":4146},{},[4147,4149,4156,4158,4165],{"type":28,"value":4148},"Finally, we create an ",{"type":22,"tag":110,"props":4150,"children":4153},{"href":4151,"rel":4152},"https://developer.apple.com/library/ios/#documentation/AVFoundation/Reference/AVPlayerItem_Class/Reference/Reference.html",[114],[4154],{"type":28,"value":4155},"AVPlayerItem",{"type":28,"value":4157}," using our AVMutableComposition, and use that to create a ",{"type":22,"tag":110,"props":4159,"children":4162},{"href":4160,"rel":4161},"https://developer.apple.com/library/ios/#documentation/AVFoundation/Reference/AVPlayer_Class/Reference/Reference.html",[114],[4163],{"type":28,"value":4164},"AVPlayer",{"type":28,"value":4166}," that we'll use to control playback of the composition. We also want to observe the \"status\" key of our player item to be notified of changes in the state of our AVPlayerItem.",{"type":22,"tag":31,"props":4168,"children":4169},{},[4170],{"type":22,"tag":41,"props":4171,"children":4172},{},[4173],{"type":28,"value":4174},"Key Value Observing (KVO)",{"type":22,"tag":274,"props":4176,"children":4178},{"className":3269,"code":4177,"language":3271,"meta":8,"style":8},"- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context\n{\n   if ([keyPath isEqualToString:@\"status\"])\n   {\n      if (AVPlayerItemStatusReadyToPlay == _player.currentItem.status)\n      {\n         [_player play];\n      }\n   }\n}\n",[4179],{"type":22,"tag":155,"props":4180,"children":4181},{"__ignoreMap":8},[4182,4257,4264,4293,4300,4322,4329,4337,4344,4351],{"type":22,"tag":818,"props":4183,"children":4184},{"class":820,"line":821},[4185,4189,4194,4198,4203,4207,4212,4216,4221,4225,4230,4234,4239,4243,4248,4252],{"type":22,"tag":818,"props":4186,"children":4187},{"style":825},[4188],{"type":28,"value":2435},{"type":22,"tag":818,"props":4190,"children":4191},{"style":837},[4192],{"type":28,"value":4193}," (void)observeValueForKeyPath",{"type":22,"tag":818,"props":4195,"children":4196},{"style":825},[4197],{"type":28,"value":3329},{"type":22,"tag":818,"props":4199,"children":4200},{"style":837},[4201],{"type":28,"value":4202},"(NSString ",{"type":22,"tag":818,"props":4204,"children":4205},{"style":825},[4206],{"type":28,"value":910},{"type":22,"tag":818,"props":4208,"children":4209},{"style":837},[4210],{"type":28,"value":4211},")keyPath ofObject",{"type":22,"tag":818,"props":4213,"children":4214},{"style":825},[4215],{"type":28,"value":3329},{"type":22,"tag":818,"props":4217,"children":4218},{"style":837},[4219],{"type":28,"value":4220},"(id)object change",{"type":22,"tag":818,"props":4222,"children":4223},{"style":825},[4224],{"type":28,"value":3329},{"type":22,"tag":818,"props":4226,"children":4227},{"style":837},[4228],{"type":28,"value":4229},"(NSDictionary ",{"type":22,"tag":818,"props":4231,"children":4232},{"style":825},[4233],{"type":28,"value":910},{"type":22,"tag":818,"props":4235,"children":4236},{"style":837},[4237],{"type":28,"value":4238},")change context",{"type":22,"tag":818,"props":4240,"children":4241},{"style":825},[4242],{"type":28,"value":3329},{"type":22,"tag":818,"props":4244,"children":4245},{"style":837},[4246],{"type":28,"value":4247},"(void ",{"type":22,"tag":818,"props":4249,"children":4250},{"style":825},[4251],{"type":28,"value":910},{"type":22,"tag":818,"props":4253,"children":4254},{"style":837},[4255],{"type":28,"value":4256},")context\n",{"type":22,"tag":818,"props":4258,"children":4259},{"class":820,"line":390},[4260],{"type":22,"tag":818,"props":4261,"children":4262},{"style":837},[4263],{"type":28,"value":1004},{"type":22,"tag":818,"props":4265,"children":4266},{"class":820,"line":387},[4267,4271,4276,4280,4284,4289],{"type":22,"tag":818,"props":4268,"children":4269},{"style":825},[4270],{"type":28,"value":1249},{"type":22,"tag":818,"props":4272,"children":4273},{"style":837},[4274],{"type":28,"value":4275}," ([keyPath isEqualToString",{"type":22,"tag":818,"props":4277,"children":4278},{"style":825},[4279],{"type":28,"value":3329},{"type":22,"tag":818,"props":4281,"children":4282},{"style":837},[4283],{"type":28,"value":3415},{"type":22,"tag":818,"props":4285,"children":4286},{"style":1160},[4287],{"type":28,"value":4288},"\"status\"",{"type":22,"tag":818,"props":4290,"children":4291},{"style":837},[4292],{"type":28,"value":1283},{"type":22,"tag":818,"props":4294,"children":4295},{"class":820,"line":865},[4296],{"type":22,"tag":818,"props":4297,"children":4298},{"style":837},[4299],{"type":28,"value":1292},{"type":22,"tag":818,"props":4301,"children":4302},{"class":820,"line":875},[4303,4307,4312,4317],{"type":22,"tag":818,"props":4304,"children":4305},{"style":825},[4306],{"type":28,"value":3816},{"type":22,"tag":818,"props":4308,"children":4309},{"style":837},[4310],{"type":28,"value":4311}," (AVPlayerItemStatusReadyToPlay ",{"type":22,"tag":818,"props":4313,"children":4314},{"style":825},[4315],{"type":28,"value":4316},"==",{"type":22,"tag":818,"props":4318,"children":4319},{"style":837},[4320],{"type":28,"value":4321}," _player.currentItem.status)\n",{"type":22,"tag":818,"props":4323,"children":4324},{"class":820,"line":884},[4325],{"type":22,"tag":818,"props":4326,"children":4327},{"style":837},[4328],{"type":28,"value":3829},{"type":22,"tag":818,"props":4330,"children":4331},{"class":820,"line":893},[4332],{"type":22,"tag":818,"props":4333,"children":4334},{"style":837},[4335],{"type":28,"value":4336},"         [_player play];\n",{"type":22,"tag":818,"props":4338,"children":4339},{"class":820,"line":927},[4340],{"type":22,"tag":818,"props":4341,"children":4342},{"style":837},[4343],{"type":28,"value":3860},{"type":22,"tag":818,"props":4345,"children":4346},{"class":820,"line":935},[4347],{"type":22,"tag":818,"props":4348,"children":4349},{"style":837},[4350],{"type":28,"value":1315},{"type":22,"tag":818,"props":4352,"children":4353},{"class":820,"line":1077},[4354],{"type":22,"tag":818,"props":4355,"children":4356},{"style":837},[4357],{"type":28,"value":1039},{"type":22,"tag":31,"props":4359,"children":4360},{},[4361],{"type":28,"value":4362},"This code is pretty straightforward. If our AVPlayerItem is ready to play, then go ahead and start playing the audio composition that we created above.",{"type":22,"tag":31,"props":4364,"children":4365},{},[4366],{"type":22,"tag":41,"props":4367,"children":4368},{},[4369],{"type":28,"value":4370},"Slider Action",{"type":22,"tag":274,"props":4372,"children":4374},{"className":3269,"code":4373,"language":3271,"meta":8,"style":8},"// Action for our 4 sliders\n- (IBAction)mix:(id)sender\n{\n   UISlider* slider = (UISlider*)sender;\n\n   [self setVolume:slider.value\n          forTrack:[NSString stringWithFormat:@\"track%d\", slider.tag]];\n   [self applyAudioMix];\n}\n",[4375],{"type":22,"tag":155,"props":4376,"children":4377},{"__ignoreMap":8},[4378,4386,4407,4414,4449,4456,4486,4521,4537],{"type":22,"tag":818,"props":4379,"children":4380},{"class":820,"line":821},[4381],{"type":22,"tag":818,"props":4382,"children":4383},{"style":869},[4384],{"type":28,"value":4385},"// Action for our 4 sliders\n",{"type":22,"tag":818,"props":4387,"children":4388},{"class":820,"line":390},[4389,4393,4398,4402],{"type":22,"tag":818,"props":4390,"children":4391},{"style":825},[4392],{"type":28,"value":2435},{"type":22,"tag":818,"props":4394,"children":4395},{"style":837},[4396],{"type":28,"value":4397}," (IBAction)mix",{"type":22,"tag":818,"props":4399,"children":4400},{"style":825},[4401],{"type":28,"value":3329},{"type":22,"tag":818,"props":4403,"children":4404},{"style":837},[4405],{"type":28,"value":4406},"(id)sender\n",{"type":22,"tag":818,"props":4408,"children":4409},{"class":820,"line":387},[4410],{"type":22,"tag":818,"props":4411,"children":4412},{"style":837},[4413],{"type":28,"value":1004},{"type":22,"tag":818,"props":4415,"children":4416},{"class":820,"line":865},[4417,4422,4426,4431,4435,4440,4444],{"type":22,"tag":818,"props":4418,"children":4419},{"style":837},[4420],{"type":28,"value":4421},"   UISlider",{"type":22,"tag":818,"props":4423,"children":4424},{"style":825},[4425],{"type":28,"value":910},{"type":22,"tag":818,"props":4427,"children":4428},{"style":837},[4429],{"type":28,"value":4430}," slider ",{"type":22,"tag":818,"props":4432,"children":4433},{"style":825},[4434],{"type":28,"value":1903},{"type":22,"tag":818,"props":4436,"children":4437},{"style":837},[4438],{"type":28,"value":4439}," (UISlider",{"type":22,"tag":818,"props":4441,"children":4442},{"style":825},[4443],{"type":28,"value":910},{"type":22,"tag":818,"props":4445,"children":4446},{"style":837},[4447],{"type":28,"value":4448},")sender;\n",{"type":22,"tag":818,"props":4450,"children":4451},{"class":820,"line":875},[4452],{"type":22,"tag":818,"props":4453,"children":4454},{"emptyLinePlaceholder":859},[4455],{"type":28,"value":862},{"type":22,"tag":818,"props":4457,"children":4458},{"class":820,"line":884},[4459,4464,4468,4472,4476,4481],{"type":22,"tag":818,"props":4460,"children":4461},{"style":837},[4462],{"type":28,"value":4463},"   [",{"type":22,"tag":818,"props":4465,"children":4466},{"style":902},[4467],{"type":28,"value":1273},{"type":22,"tag":818,"props":4469,"children":4470},{"style":837},[4471],{"type":28,"value":3950},{"type":22,"tag":818,"props":4473,"children":4474},{"style":825},[4475],{"type":28,"value":3329},{"type":22,"tag":818,"props":4477,"children":4478},{"style":837},[4479],{"type":28,"value":4480},"slider.",{"type":22,"tag":818,"props":4482,"children":4483},{"style":902},[4484],{"type":28,"value":4485},"value\n",{"type":22,"tag":818,"props":4487,"children":4488},{"class":820,"line":893},[4489,4494,4498,4503,4507,4511,4516],{"type":22,"tag":818,"props":4490,"children":4491},{"style":837},[4492],{"type":28,"value":4493},"          forTrack",{"type":22,"tag":818,"props":4495,"children":4496},{"style":825},[4497],{"type":28,"value":3329},{"type":22,"tag":818,"props":4499,"children":4500},{"style":837},[4501],{"type":28,"value":4502},"[NSString stringWithFormat",{"type":22,"tag":818,"props":4504,"children":4505},{"style":825},[4506],{"type":28,"value":3329},{"type":22,"tag":818,"props":4508,"children":4509},{"style":837},[4510],{"type":28,"value":3415},{"type":22,"tag":818,"props":4512,"children":4513},{"style":1160},[4514],{"type":28,"value":4515},"\"track%d\"",{"type":22,"tag":818,"props":4517,"children":4518},{"style":837},[4519],{"type":28,"value":4520},", slider.tag]];\n",{"type":22,"tag":818,"props":4522,"children":4523},{"class":820,"line":927},[4524,4528,4532],{"type":22,"tag":818,"props":4525,"children":4526},{"style":837},[4527],{"type":28,"value":4463},{"type":22,"tag":818,"props":4529,"children":4530},{"style":902},[4531],{"type":28,"value":1273},{"type":22,"tag":818,"props":4533,"children":4534},{"style":837},[4535],{"type":28,"value":4536}," applyAudioMix];\n",{"type":22,"tag":818,"props":4538,"children":4539},{"class":820,"line":935},[4540],{"type":22,"tag":818,"props":4541,"children":4542},{"style":837},[4543],{"type":28,"value":1039},{"type":22,"tag":31,"props":4545,"children":4546},{},[4547],{"type":28,"value":4548},"Our UI has four UISliders, each of which call this action method. The sliders are tagged from 1 to 4 and we use the tag to map to the corresponding audio track. The value of the slider is configured to be between 0.0 and 1.0 so we use it to set the track volume and then apply the updated audio mix to the composition.",{"type":22,"tag":31,"props":4550,"children":4551},{},[4552],{"type":22,"tag":41,"props":4553,"children":4554},{},[4555],{"type":28,"value":4556},"Setting the Volume",{"type":22,"tag":274,"props":4558,"children":4560},{"className":3269,"code":4559,"language":3271,"meta":8,"style":8},"// Set the volumne (0.0 - 1.0) for the given track\n- (void)setVolume:(float)volume forTrack:(NSString*)audioTrackName\n{\n   [_audioMixValues setValue:[NSNumber numberWithFloat:volume] forKey:audioTrackName];\n}\n",[4561],{"type":22,"tag":155,"props":4562,"children":4563},{"__ignoreMap":8},[4564,4572,4611,4618,4653],{"type":22,"tag":818,"props":4565,"children":4566},{"class":820,"line":821},[4567],{"type":22,"tag":818,"props":4568,"children":4569},{"style":869},[4570],{"type":28,"value":4571},"// Set the volumne (0.0 - 1.0) for the given track\n",{"type":22,"tag":818,"props":4573,"children":4574},{"class":820,"line":390},[4575,4579,4584,4588,4593,4597,4602,4606],{"type":22,"tag":818,"props":4576,"children":4577},{"style":825},[4578],{"type":28,"value":2435},{"type":22,"tag":818,"props":4580,"children":4581},{"style":837},[4582],{"type":28,"value":4583}," (void)setVolume",{"type":22,"tag":818,"props":4585,"children":4586},{"style":825},[4587],{"type":28,"value":3329},{"type":22,"tag":818,"props":4589,"children":4590},{"style":837},[4591],{"type":28,"value":4592},"(float)volume forTrack",{"type":22,"tag":818,"props":4594,"children":4595},{"style":825},[4596],{"type":28,"value":3329},{"type":22,"tag":818,"props":4598,"children":4599},{"style":837},[4600],{"type":28,"value":4601},"(NSString",{"type":22,"tag":818,"props":4603,"children":4604},{"style":825},[4605],{"type":28,"value":910},{"type":22,"tag":818,"props":4607,"children":4608},{"style":837},[4609],{"type":28,"value":4610},")audioTrackName\n",{"type":22,"tag":818,"props":4612,"children":4613},{"class":820,"line":387},[4614],{"type":22,"tag":818,"props":4615,"children":4616},{"style":837},[4617],{"type":28,"value":1004},{"type":22,"tag":818,"props":4619,"children":4620},{"class":820,"line":865},[4621,4626,4630,4635,4639,4644,4648],{"type":22,"tag":818,"props":4622,"children":4623},{"style":837},[4624],{"type":28,"value":4625},"   [_audioMixValues setValue",{"type":22,"tag":818,"props":4627,"children":4628},{"style":825},[4629],{"type":28,"value":3329},{"type":22,"tag":818,"props":4631,"children":4632},{"style":837},[4633],{"type":28,"value":4634},"[NSNumber numberWithFloat",{"type":22,"tag":818,"props":4636,"children":4637},{"style":825},[4638],{"type":28,"value":3329},{"type":22,"tag":818,"props":4640,"children":4641},{"style":837},[4642],{"type":28,"value":4643},"volume] forKey",{"type":22,"tag":818,"props":4645,"children":4646},{"style":825},[4647],{"type":28,"value":3329},{"type":22,"tag":818,"props":4649,"children":4650},{"style":837},[4651],{"type":28,"value":4652},"audioTrackName];\n",{"type":22,"tag":818,"props":4654,"children":4655},{"class":820,"line":875},[4656],{"type":22,"tag":818,"props":4657,"children":4658},{"style":837},[4659],{"type":28,"value":1039},{"type":22,"tag":31,"props":4661,"children":4662},{},[4663],{"type":28,"value":4664},"When we set the volume we simply update the value in our NSMutableDictionary that stores the volume level for each track.",{"type":22,"tag":31,"props":4666,"children":4667},{},[4668],{"type":22,"tag":41,"props":4669,"children":4670},{},[4671],{"type":28,"value":4672},"Applying the Mix",{"type":22,"tag":274,"props":4674,"children":4676},{"className":3269,"code":4675,"language":3271,"meta":8,"style":8},"// Build and apply an audio mix using our volume values\n- (void)applyAudioMix\n{\n   AVMutableAudioMix* mix = [AVMutableAudioMix audioMix];\n\n   NSMutableArray* inputParameters = [[NSMutableArray alloc] initWithCapacity:0];\n\n   [_audioMixTrackIDs enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL*stop) {\n      AVAssetTrack* track = [self trackWithId:(CMPersistentTrackID)[(NSNumber*)obj integerValue]];\n\n      AVMutableAudioMixInputParameters* params = [AVMutableAudioMixInputParameters audioMixInputParametersWithTrack:track];\n\n      [params setVolume:[[_audioMixValues valueForKey:key] floatValue]\n                 atTime:kCMTimeZero];\n\n      [inputParameters addObject:params];\n   }];\n\n   mix.inputParameters = inputParameters;\n\n   _player.currentItem.audioMix = mix;\n}\n",[4677],{"type":22,"tag":155,"props":4678,"children":4679},{"__ignoreMap":8},[4680,4688,4700,4707,4733,4740,4778,4785,4812,4864,4871,4906,4913,4939,4956,4963,4980,4988,4995,5012,5019,5036],{"type":22,"tag":818,"props":4681,"children":4682},{"class":820,"line":821},[4683],{"type":22,"tag":818,"props":4684,"children":4685},{"style":869},[4686],{"type":28,"value":4687},"// Build and apply an audio mix using our volume values\n",{"type":22,"tag":818,"props":4689,"children":4690},{"class":820,"line":390},[4691,4695],{"type":22,"tag":818,"props":4692,"children":4693},{"style":825},[4694],{"type":28,"value":2435},{"type":22,"tag":818,"props":4696,"children":4697},{"style":837},[4698],{"type":28,"value":4699}," (void)applyAudioMix\n",{"type":22,"tag":818,"props":4701,"children":4702},{"class":820,"line":387},[4703],{"type":22,"tag":818,"props":4704,"children":4705},{"style":837},[4706],{"type":28,"value":1004},{"type":22,"tag":818,"props":4708,"children":4709},{"class":820,"line":865},[4710,4715,4719,4724,4728],{"type":22,"tag":818,"props":4711,"children":4712},{"style":837},[4713],{"type":28,"value":4714},"   AVMutableAudioMix",{"type":22,"tag":818,"props":4716,"children":4717},{"style":825},[4718],{"type":28,"value":910},{"type":22,"tag":818,"props":4720,"children":4721},{"style":837},[4722],{"type":28,"value":4723}," mix ",{"type":22,"tag":818,"props":4725,"children":4726},{"style":825},[4727],{"type":28,"value":1903},{"type":22,"tag":818,"props":4729,"children":4730},{"style":837},[4731],{"type":28,"value":4732}," [AVMutableAudioMix audioMix];\n",{"type":22,"tag":818,"props":4734,"children":4735},{"class":820,"line":875},[4736],{"type":22,"tag":818,"props":4737,"children":4738},{"emptyLinePlaceholder":859},[4739],{"type":28,"value":862},{"type":22,"tag":818,"props":4741,"children":4742},{"class":820,"line":884},[4743,4748,4752,4757,4761,4766,4770,4774],{"type":22,"tag":818,"props":4744,"children":4745},{"style":837},[4746],{"type":28,"value":4747},"   NSMutableArray",{"type":22,"tag":818,"props":4749,"children":4750},{"style":825},[4751],{"type":28,"value":910},{"type":22,"tag":818,"props":4753,"children":4754},{"style":837},[4755],{"type":28,"value":4756}," inputParameters ",{"type":22,"tag":818,"props":4758,"children":4759},{"style":825},[4760],{"type":28,"value":1903},{"type":22,"tag":818,"props":4762,"children":4763},{"style":837},[4764],{"type":28,"value":4765}," [[NSMutableArray alloc] initWithCapacity",{"type":22,"tag":818,"props":4767,"children":4768},{"style":825},[4769],{"type":28,"value":3329},{"type":22,"tag":818,"props":4771,"children":4772},{"style":902},[4773],{"type":28,"value":2790},{"type":22,"tag":818,"props":4775,"children":4776},{"style":837},[4777],{"type":28,"value":1031},{"type":22,"tag":818,"props":4779,"children":4780},{"class":820,"line":893},[4781],{"type":22,"tag":818,"props":4782,"children":4783},{"emptyLinePlaceholder":859},[4784],{"type":28,"value":862},{"type":22,"tag":818,"props":4786,"children":4787},{"class":820,"line":927},[4788,4793,4798,4803,4807],{"type":22,"tag":818,"props":4789,"children":4790},{"style":837},[4791],{"type":28,"value":4792},"   [_audioMixTrackIDs enumerateKeysAndObjectsUsingBlock",{"type":22,"tag":818,"props":4794,"children":4795},{"style":825},[4796],{"type":28,"value":4797},":^",{"type":22,"tag":818,"props":4799,"children":4800},{"style":837},[4801],{"type":28,"value":4802},"(id key, id obj, BOOL",{"type":22,"tag":818,"props":4804,"children":4805},{"style":825},[4806],{"type":28,"value":910},{"type":22,"tag":818,"props":4808,"children":4809},{"style":837},[4810],{"type":28,"value":4811},"stop) {\n",{"type":22,"tag":818,"props":4813,"children":4814},{"class":820,"line":935},[4815,4820,4824,4829,4833,4837,4841,4846,4850,4855,4859],{"type":22,"tag":818,"props":4816,"children":4817},{"style":837},[4818],{"type":28,"value":4819},"      AVAssetTrack",{"type":22,"tag":818,"props":4821,"children":4822},{"style":825},[4823],{"type":28,"value":910},{"type":22,"tag":818,"props":4825,"children":4826},{"style":837},[4827],{"type":28,"value":4828}," track ",{"type":22,"tag":818,"props":4830,"children":4831},{"style":825},[4832],{"type":28,"value":1903},{"type":22,"tag":818,"props":4834,"children":4835},{"style":837},[4836],{"type":28,"value":1017},{"type":22,"tag":818,"props":4838,"children":4839},{"style":902},[4840],{"type":28,"value":1273},{"type":22,"tag":818,"props":4842,"children":4843},{"style":837},[4844],{"type":28,"value":4845}," trackWithId",{"type":22,"tag":818,"props":4847,"children":4848},{"style":825},[4849],{"type":28,"value":3329},{"type":22,"tag":818,"props":4851,"children":4852},{"style":837},[4853],{"type":28,"value":4854},"(CMPersistentTrackID)[(NSNumber",{"type":22,"tag":818,"props":4856,"children":4857},{"style":825},[4858],{"type":28,"value":910},{"type":22,"tag":818,"props":4860,"children":4861},{"style":837},[4862],{"type":28,"value":4863},")obj integerValue]];\n",{"type":22,"tag":818,"props":4865,"children":4866},{"class":820,"line":1077},[4867],{"type":22,"tag":818,"props":4868,"children":4869},{"emptyLinePlaceholder":859},[4870],{"type":28,"value":862},{"type":22,"tag":818,"props":4872,"children":4873},{"class":820,"line":1094},[4874,4879,4883,4888,4892,4897,4901],{"type":22,"tag":818,"props":4875,"children":4876},{"style":837},[4877],{"type":28,"value":4878},"      AVMutableAudioMixInputParameters",{"type":22,"tag":818,"props":4880,"children":4881},{"style":825},[4882],{"type":28,"value":910},{"type":22,"tag":818,"props":4884,"children":4885},{"style":837},[4886],{"type":28,"value":4887}," params ",{"type":22,"tag":818,"props":4889,"children":4890},{"style":825},[4891],{"type":28,"value":1903},{"type":22,"tag":818,"props":4893,"children":4894},{"style":837},[4895],{"type":28,"value":4896}," [AVMutableAudioMixInputParameters audioMixInputParametersWithTrack",{"type":22,"tag":818,"props":4898,"children":4899},{"style":825},[4900],{"type":28,"value":3329},{"type":22,"tag":818,"props":4902,"children":4903},{"style":837},[4904],{"type":28,"value":4905},"track];\n",{"type":22,"tag":818,"props":4907,"children":4908},{"class":820,"line":1102},[4909],{"type":22,"tag":818,"props":4910,"children":4911},{"emptyLinePlaceholder":859},[4912],{"type":28,"value":862},{"type":22,"tag":818,"props":4914,"children":4915},{"class":820,"line":1110},[4916,4921,4925,4930,4934],{"type":22,"tag":818,"props":4917,"children":4918},{"style":837},[4919],{"type":28,"value":4920},"      [params setVolume",{"type":22,"tag":818,"props":4922,"children":4923},{"style":825},[4924],{"type":28,"value":3329},{"type":22,"tag":818,"props":4926,"children":4927},{"style":837},[4928],{"type":28,"value":4929},"[[_audioMixValues valueForKey",{"type":22,"tag":818,"props":4931,"children":4932},{"style":825},[4933],{"type":28,"value":3329},{"type":22,"tag":818,"props":4935,"children":4936},{"style":837},[4937],{"type":28,"value":4938},"key] floatValue]\n",{"type":22,"tag":818,"props":4940,"children":4941},{"class":820,"line":1135},[4942,4947,4951],{"type":22,"tag":818,"props":4943,"children":4944},{"style":837},[4945],{"type":28,"value":4946},"                 atTime",{"type":22,"tag":818,"props":4948,"children":4949},{"style":825},[4950],{"type":28,"value":3329},{"type":22,"tag":818,"props":4952,"children":4953},{"style":837},[4954],{"type":28,"value":4955},"kCMTimeZero];\n",{"type":22,"tag":818,"props":4957,"children":4958},{"class":820,"line":1143},[4959],{"type":22,"tag":818,"props":4960,"children":4961},{"emptyLinePlaceholder":859},[4962],{"type":28,"value":862},{"type":22,"tag":818,"props":4964,"children":4965},{"class":820,"line":1152},[4966,4971,4975],{"type":22,"tag":818,"props":4967,"children":4968},{"style":837},[4969],{"type":28,"value":4970},"      [inputParameters addObject",{"type":22,"tag":818,"props":4972,"children":4973},{"style":825},[4974],{"type":28,"value":3329},{"type":22,"tag":818,"props":4976,"children":4977},{"style":837},[4978],{"type":28,"value":4979},"params];\n",{"type":22,"tag":818,"props":4981,"children":4982},{"class":820,"line":1170},[4983],{"type":22,"tag":818,"props":4984,"children":4985},{"style":837},[4986],{"type":28,"value":4987},"   }];\n",{"type":22,"tag":818,"props":4989,"children":4990},{"class":820,"line":1178},[4991],{"type":22,"tag":818,"props":4992,"children":4993},{"emptyLinePlaceholder":859},[4994],{"type":28,"value":862},{"type":22,"tag":818,"props":4996,"children":4997},{"class":820,"line":1186},[4998,5003,5007],{"type":22,"tag":818,"props":4999,"children":5000},{"style":837},[5001],{"type":28,"value":5002},"   mix.inputParameters ",{"type":22,"tag":818,"props":5004,"children":5005},{"style":825},[5006],{"type":28,"value":1903},{"type":22,"tag":818,"props":5008,"children":5009},{"style":837},[5010],{"type":28,"value":5011}," inputParameters;\n",{"type":22,"tag":818,"props":5013,"children":5014},{"class":820,"line":1226},[5015],{"type":22,"tag":818,"props":5016,"children":5017},{"emptyLinePlaceholder":859},[5018],{"type":28,"value":862},{"type":22,"tag":818,"props":5020,"children":5021},{"class":820,"line":1234},[5022,5027,5031],{"type":22,"tag":818,"props":5023,"children":5024},{"style":837},[5025],{"type":28,"value":5026},"   _player.currentItem.audioMix ",{"type":22,"tag":818,"props":5028,"children":5029},{"style":825},[5030],{"type":28,"value":1903},{"type":22,"tag":818,"props":5032,"children":5033},{"style":837},[5034],{"type":28,"value":5035}," mix;\n",{"type":22,"tag":818,"props":5037,"children":5038},{"class":820,"line":1243},[5039],{"type":22,"tag":818,"props":5040,"children":5041},{"style":837},[5042],{"type":28,"value":1039},{"type":22,"tag":31,"props":5044,"children":5045},{},[5046,5048,5055,5057,5064],{"type":28,"value":5047},"Here's where we update and apply the audio mix to our composition. First we create an instance of the ",{"type":22,"tag":110,"props":5049,"children":5052},{"href":5050,"rel":5051},"https://developer.apple.com/library/ios/#documentation/AVFoundation/Reference/AVMutableAudioMix_Class/Reference/Reference.html",[114],[5053],{"type":28,"value":5054},"AVMutableAudioMix",{"type":28,"value":5056}," class and then for each track create an ",{"type":22,"tag":110,"props":5058,"children":5061},{"href":5059,"rel":5060},"https://developer.apple.com/library/ios/#documentation/AVFoundation/Reference/AVMutableAudioMixInputParameters_Class/Reference/Reference.html",[114],[5062],{"type":28,"value":5063},"AVMutableAudioMixInputParameters",{"type":28,"value":5065}," instance for the track with the track volume as determined by the current slider value that we've stored. We add the AVMutableAudioMixInputParameters to an array and then set the parameters for our AVMutableAudioMix instance. Finally, we set the mix for the current item of our AVPlayer to our newly created mix.",{"type":22,"tag":31,"props":5067,"children":5068},{},[5069],{"type":22,"tag":41,"props":5070,"children":5071},{},[5072],{"type":28,"value":5073},"Closing Thoughts",{"type":22,"tag":31,"props":5075,"children":5076},{},[5077],{"type":28,"value":5078},"In just a few methods we have a simple four track mixer. This would have been much harder to accomplish without AVFoundation since we'd likely need to use the low-level Core Audio APIs.",{"type":22,"tag":31,"props":5080,"children":5081},{},[5082],{"type":28,"value":5083},"It will be interesting to see what updates Apple has planned for AVFoundation in iOS 6.0 and OS X 10.8 and if the related QuickTime APIs in OS X will be deprecated in favor of AVFoundation.",{"type":22,"tag":2956,"props":5085,"children":5086},{},[5087],{"type":28,"value":2960},{"title":8,"searchDepth":387,"depth":387,"links":5089},[],"content:shuey:2012-07:mixer.md","shuey/2012-07/mixer.md","shuey/2012-07/mixer",{"user":3155,"name":3156},{"_path":5095,"_dir":5096,"_draft":7,"_partial":7,"_locale":8,"title":5097,"description":5098,"publishDate":5099,"tags":5100,"image":5101,"excerpt":5098,"body":5102,"_type":399,"_id":5148,"_source":401,"_file":5149,"_stem":5150,"_extension":404,"author":5151},"/shuey/2012-06/thoughts-ios6","2012-06","A few thoughts on iOS 6","Apple made their session videos from WWDC 2012 available earlier this week in record time. It's nice to see since tickets for this years event sold out in under two hours. Apple has an iOS 6 Preview page touting some of the new features such as Siri's new abilities, tighter integration with Facebook, Photo Stream sharing, and things like iCloud tabs for Safari all of which look great.","2012-06-21",[416,16],"/shuey/2012-06/img/ios6.jpg",{"type":19,"children":5103,"toc":5146},[5104,5127,5132],{"type":22,"tag":31,"props":5105,"children":5106},{},[5107,5109,5116,5118,5125],{"type":28,"value":5108},"Apple made their ",{"type":22,"tag":110,"props":5110,"children":5113},{"href":5111,"rel":5112},"https://developer.apple.com/videos/wwdc/2012/",[114],[5114],{"type":28,"value":5115},"session videos from WWDC 2012 available",{"type":28,"value":5117}," earlier this week in record time. It's nice to see since tickets for this years event sold out in under two hours. Apple has an ",{"type":22,"tag":110,"props":5119,"children":5122},{"href":5120,"rel":5121},"http://www.apple.com/ios/ios6/",[114],[5123],{"type":28,"value":5124},"iOS 6 Preview",{"type":28,"value":5126}," page touting some of the new features such as Siri's new abilities, tighter integration with Facebook, Photo Stream sharing, and things like iCloud tabs for Safari all of which look great.",{"type":22,"tag":31,"props":5128,"children":5129},{},[5130],{"type":28,"value":5131},"What stands out most about iOS 6 to me are the changes Apple has made to the OS to compete in the mobile arena. The all new Maps app that uses their own data instead of Google's, the Safari search field now reads \"Search\" instead of \"Google\", the OS level integration with Facebook (to go along with Twitter), features catering to the expanding Chinese market, and increased use of iCloud.",{"type":22,"tag":31,"props":5133,"children":5134},{},[5135,5137,5144],{"type":28,"value":5136},"Apple took some shots at Android and Samsung during the keynote but looks to take an even larger one when iOS 6 is released this fall, likely alongside the release of the next iPhone. If the adoption rates for iOS 6 are similar to iOS 5 (which are huge compared to ",{"type":22,"tag":110,"props":5138,"children":5141},{"href":5139,"rel":5140},"http://www.android.com",[114],[5142],{"type":28,"value":5143},"Android's 4.0 Ice Cream Sandwich",{"type":28,"value":5145}," release) and if the next iPhone sells anything close to how the 4S is, it will be interesting to see how market shares and revenues turn out late this year for the two companies.",{"title":8,"searchDepth":387,"depth":387,"links":5147},[],"content:shuey:2012-06:thoughts-ios6.md","shuey/2012-06/thoughts-ios6.md","shuey/2012-06/thoughts-ios6",{"user":3155,"name":3156},{"_path":5153,"_dir":5154,"_draft":7,"_partial":7,"_locale":8,"title":5155,"description":5156,"publishDate":5157,"tags":5158,"image":5160,"excerpt":5156,"body":5161,"_type":399,"_id":5288,"_source":401,"_file":5289,"_stem":5290,"_extension":404,"author":5291},"/shuey/2012-05/rubymotion","2012-05","RubyMotion Brings Ruby to iOS","RubyMotion is a new development toolchain that allows you to build iOS apps using Ruby created by Laurent Sansonetti, a former Apple engineer and contributor to the MacRuby project. It has garnered a lot of attention the past few weeks and some detailed reviews have already been written:","2012-05-14",[16,5159],"ruby","/shuey/2012-05/img/logotype-icon.png",{"type":19,"children":5162,"toc":5286},[5163,5203,5250,5263],{"type":22,"tag":31,"props":5164,"children":5165},{},[5166,5174,5176,5183,5185,5192,5194,5201],{"type":22,"tag":110,"props":5167,"children":5171},{"href":5168,"rel":5169,"title":5170},"http://www.rubymotion.com/",[114],"RubyMotion - Ruby for iOS",[5172],{"type":28,"value":5173},"RubyMotion",{"type":28,"value":5175}," is a new development toolchain that allows you to build iOS apps using ",{"type":22,"tag":110,"props":5177,"children":5180},{"href":5178,"rel":5179},"http://www.ruby-lang.org/en/",[114],[5181],{"type":28,"value":5182},"Ruby",{"type":28,"value":5184}," created by ",{"type":22,"tag":110,"props":5186,"children":5189},{"href":5187,"rel":5188},"https://twitter.com/#!/lrz",[114],[5190],{"type":28,"value":5191},"Laurent Sansonetti",{"type":28,"value":5193},", a former Apple engineer and contributor to the ",{"type":22,"tag":110,"props":5195,"children":5198},{"href":5196,"rel":5197},"http://www.macruby.org/",[114],[5199],{"type":28,"value":5200},"MacRuby",{"type":28,"value":5202}," project. It has garnered a lot of attention the past few weeks and some detailed reviews have already been written:",{"type":22,"tag":218,"props":5204,"children":5205},{},[5206,5218,5238],{"type":22,"tag":222,"props":5207,"children":5208},{},[5209,5216],{"type":22,"tag":110,"props":5210,"children":5213},{"href":5211,"rel":5212},"http://arstechnica.com/business/2012/05/exclusive-building-ruby-ios-applications-with-rubymotion/",[114],[5214],{"type":28,"value":5215},"Exclusive: building native iOS apps with RubyMotion",{"type":28,"value":5217}," (ArsTechnica)",{"type":22,"tag":222,"props":5219,"children":5220},{},[5221,5228,5230,5237],{"type":22,"tag":110,"props":5222,"children":5225},{"href":5223,"rel":5224},"http://merbist.com/2012/05/04/macruby-on-ios-rubymotion-review/",[114],[5226],{"type":28,"value":5227},"RubyMotion - Ruby for iOS review",{"type":28,"value":5229}," (Matt Aimonetti, author of ",{"type":22,"tag":110,"props":5231,"children":5234},{"href":5232,"rel":5233},"http://shop.oreilly.com/product/0636920000723.do",[114],[5235],{"type":28,"value":5236},"MacRuby - The Definitive Guide",{"type":28,"value":915},{"type":22,"tag":222,"props":5239,"children":5240},{},[5241,5248],{"type":22,"tag":110,"props":5242,"children":5245},{"href":5243,"rel":5244},"http://pragmaticstudio.com/screencasts/rubymotion",[114],[5246],{"type":28,"value":5247},"RubyMotion screencast",{"type":28,"value":5249}," (The Pragmatic Studio)",{"type":22,"tag":31,"props":5251,"children":5252},{},[5253,5255,5261],{"type":28,"value":5254},"The MacRuby project (which is an open-source project supported by Apple) allows developers to create Mac OS X apps using ruby, however it doesn't work with iOS. MacRuby relies on the Garbage Collected (GC) Objective-C runtime that isn't available on iOS. With the introduction of ",{"type":22,"tag":110,"props":5256,"children":5259},{"href":5257,"rel":5258},"http://clang.llvm.org/docs/AutomaticReferenceCounting.html",[114],[5260],{"type":28,"value":3210},{"type":28,"value":5262}," for iOS and Mac OS X Apple will likely drop support for the garbage collected (GC) runtime in a future version of Mac OS X and won't bother to bring it to iOS. This move by Apple called into question the future of MacRuby for OS X and made the prospect of developing iOS apps using ruby look even more remote.",{"type":22,"tag":31,"props":5264,"children":5265},{},[5266,5268,5275,5277,5284],{"type":28,"value":5267},"Enter RubyMotion. It ",{"type":22,"tag":110,"props":5269,"children":5272},{"href":5270,"rel":5271},"http://www.rubymotion.com/features/",[114],[5273],{"type":28,"value":5274},"takes a different approach",{"type":28,"value":5276}," than MacRuby and based on early results looks to be a good solution for rubyists looking to build iOS apps. However, the lack of support for creating UI elements in Interface Builder, dependence on Apple's developer tools and SDKs, and other risks are being ",{"type":22,"tag":110,"props":5278,"children":5281},{"href":5279,"rel":5280},"http://www.upbeat.it/2012/05/08/on-why-i-am-not-buying-rubymotion/",[114],[5282],{"type":28,"value":5283},"called into question already as well",{"type":28,"value":5285},". It will be interesting to see Apple's reaction to RubyMotion, especially considering that Sansonetti is a former employee and MacRuby contributor. I've bought my copy and am hoping the project succeeds and finds its way back to OS X too.",{"title":8,"searchDepth":387,"depth":387,"links":5287},[],"content:shuey:2012-05:rubymotion.md","shuey/2012-05/rubymotion.md","shuey/2012-05/rubymotion",{"user":3155,"name":3156},1780330263893]