TweetFollow Us on Twitter

Beginning REALbasic: Inside the Application

Volume Number: 24 (2008)
Issue Number: 09
Column Tag: REALBasic

Beginning REALbasic: Inside the Application

by Norman Palardy

REALbasic is a Rapid Application Development (RAD) tool from REALSoftware. In the last column we started designing the application we're working on in this getting started series. Since the last issue REALbasic 2008r3 has been released and we'll move up to using that as here are a number of bug fixes and improvements in it.

Making the Database

In this installment we're continuing to build the application for tracking the prices of stocks. Last time we laid out the basic interface and also looked at how listboxes work. We still have a lot of work to do though.

One of those things is making sure that we have a place to store the data we get long term so we can look at it again. For that we're going to use a database. REALbasic comes with a built in database and we can make great use of it. The built in database is based on SQLite.

One of the tricky things with databases is that when you deal with them, you use their language, usually Structured Query Language (SQL), to do many things. Finding data, or selecting data, is done using SQL. Creating the places to store data is done using SQL, and even deleting data is often done using SQL.

So when you deal with a database one thing to keep in mind is that REALbasic has no clue about SQL. It does not read it, write it or interpret it in any way. As far as REALbasic is concerned there's no practical difference between these two bits of code:

dim s1 as string = "Hello World"
dim s2 as string = "create table test ( column1 varchar(100) ) "

Both are strings that have contents. REALbasic makes no distinction about what the contents are. The thing to remember is if you have trouble getting something for the database to work, try it manually, which we'll discuss a little later. If that works make sure the string you create in REALbasic does exactly what you did manually.

First, start REALbasic and load up the project from last time so we can work with it

As we saw last time this default project is a fully functioning program. You could immediately run it by pressing the green Run button.

Let's consider the data that we'll want to gather to make this program work the way we want.

We'll want a list of stocks we're interested in.

We'll have the quotes that we grab each time for each stock of interest

We'll need to keep track of the source(s) we're going to read data from

Please note that the screen shots here use REALbasic Professional. If you are using REALbasic Standard, screens may appear differently in your version.

Let's add a database. For the purposes of creating it quickly and simply we'll use the menu Project > Add > Database > New REAL SQL Database. Name it Stocks.rsd - the rsd extension is the default for REAL SQL databases.

Create the database file in the same directory as the REALbasic project (so it's easy to locate).

This will let us use the built in database tools to edit the database and browse the date. However, as recommended by REAL Software in http://forums.realsoftware.com/viewtopic.php?t=4342 everything else will be done in REALbasic code. This is not only more flexible but it ultimately gives you more control. Your project should now look like the one in Figure 1.


Figure 1: After adding the database

Now let's add the tables we'll require. Double click on the database icon and you should see the database editor as in Figure 2.


Figure 2: The database editor

In an SQL database, data are stored in "tables" - rows and columns of data much like you might see in a spreadsheet. Each row in a table is one complete "record". While that's technically not the right term it's so commonly used that we'll use it as well (The correct term is actually "tuple" but it's not frequently used). Each record in a table has every column that exists in the table. However, in an SQL database, a column for a particular record can have a value, say "Socks", or not have had a value assigned. This special "no value is assigned value" is called Null. There are special rules in SQL about NULL and how it is handled. You can find more about this as http://www.sqlite.org.

Just keep in mind that a string that is set to "" is NOT the same as NULL. The string has a value, but the value is empty and NULL means "no value at all".

Onwards!

The first thing we'll do is create the table for the stocks we want to track. The only things we'll need in this table are the full name of the stock, and its trading symbol.

Add the table by clicking "Add Table". Change the name of it to "StocksOfInterest".

We'll also add the two columns, Name and Symbol. You'll notice that when you click Add Column that there are also several properties that can be added to each column.


Figure 3: Adding a column in the database editor

The Type property sets the kind of data that this column can hold. Strings should go in varchar or text columns as those are the same "types" in REALbasic and the database. If you click the Type you'll see there are several others as well. Integers in REALbasic should go in integer columns in the database, floating point values from REALbasic (single or double) should go in float or double columns, and so on.

The Primary Key check box indicates whether this column is what is known as the primary key for the table. This means that the value in this column will always be required (ie it cannot be NULL) and it will be unique (no duplicates). For what we're doing we don't need to set this.

The Mandatory check box means this value, when you add a new row, MUST be provided and the addition of the row will fail if you do not provide it. In reality it means the column cannot be NULL (see? this NULL thing is really important!).

The Index check box specifies whether or not an "index" should be created. An index is a special data structure that a database uses to make access to data quicker. Often, primary keys are indexed and there may be reasons to index other columns; especially if you use them a lot to get data from the table. They can make a significant difference on very large tables. Again, for what we're doing, we can just ignore this.

The Default Value item is just that, the default that gets set if nothing is inserted for the column. It can be handy to make sure that a column always has at least some value.

The Length item usually only applies to the varchar or text types as they can be set to hold only X many characters (a length limit) or they can be set to hold an unlimited amount (up to the database limits) For what we're doing we'll leave this empty as well.

Now we have a table that can hold the stocks that we'll want to watch.

Click save to make sure your changes to the database design get saved. If you made a mistake, you can delete it and start over.

You'll also need to add a StockQuote table with the following columns: Symbol (type text), Price (type double) and quoteDateTime (type timestamp).

So now lets look at how we connect to this database, and insert rows to it and how we can use that to populate the listbox on our window.

In order to use the database in the program, we need to find the file that holds the database and connect to the database. We'll need a variable to refer to the database from anywhere in our program. There are lots of possible ways we could do these things. I'm going to show you one way you can use.

Close the Database editor window and open the App class in the project.

First, let's add a public property to the App class. Click on Add Property or use the Project > Add > Property menu item. Change the name to DB, and make the type REALSQLDatabase.

It should appear like the image in Figure 4


Figure 4: Adding a property to the App class

Now all we have to do is make it so this database variable points to the database file we just created. Again there are many ways to do this and I'm just going to illustrate one.

When an application starts up one of the first events that the application responds to is the "Open" event. This is the "Hey! I'm starting up" notification and the first opportunity you have as a programmer to do something.

Click on the "Event Handlers" disclosure triangle and you'll see there are other events as well.


Figure 5: The various events in the App class

Select the Open event and we'll add the following code to it:

dim fileTypeInst as FileType   
// create an instance of the Class
fileTypeInst = new FileType
// set up the "filter for what kind of file to select by 
fileTypeInst.Extensions = "rsd" 
// give it a name
fileTypeInst.Name = "REALSQLDatabase" 
// the Mac type and creator (only for OS X)
fileTypeInst.MacType = "RSdb" 
fileTypeInst.MacCreator = "RBv2"
  
// create a new instance of REALSQLDatabase Class
app.db = new REALSQLDatabase
// ask the user to select the database file
app.db.DatabaseFile = GetOpenFolderItem(fileTypeInst)   

There's no shortage of things going on in this little snippet. First we need to make it possible for use to ONLY select database files. So we set up a filter, known as a FileType.

The fist thing to do is create an "instance" of the class called "FileType".

In Object Oriented Programming (OOP) there are "Classes", which are a way of describing how something should work. Just like you say "Oh a car works like this by ... " and proceeding how internal combustion engines work, and how that eventually propels the car, a "Class" in OOP is a description of how things are supposed to work.

But your description of a car is not a car, just a description of one.

In order to get a car someone has to manufacture one and you get a NEW car.

In OOP programming you get a new instance using the New keyword.

So the first two lines:

dim fileTypeInst as FileType   
// create an instance of the Class
fileTypeInst = new FileType

say, "I'm going to create a thing and it's going to be of the type FileType. Now, create a new FileType thing and hold on to a reference to it in the variable I set aside for this purpose called fileTypeInst."

You'll notice a few things.

you create "instances"

you "refer" to instances

fileTypeInst is a reference to the instance created

yes it can be confusing :)

Suffice to say that we have created a new instance that we can set up to use as a filter for selecting the right file.

In order to complete the set up, we have to tell the filter what things to allow. Since OS X has adopted the use of extensions much like Windows, we set the extension AND the Mac Type and Creator. This filter will now only allow us to select REAL SQL Database files.

Then, because we are going to need a way to hold on to the reference to the database once we select it we need to create a new instance of the REALSQLDatabase class.

// create a new instance REASQLDatabase Class
app.db = new REALSQLDatabase

This does not create a new database. Rather, this creates a variable to hang on to the user's choice of database as long as the program runs. Now, we use the filter to ask the user to select the database that was created earlier. You did take my advice and put it next to the REAL basic project so you could find it, right?

// ask the user to select the database file
app.db.DatabaseFile = GetOpenFolderItem(fileTypeInst)

This will cause a dialog to be shown where the user can select the database file. There are, as I mentioned, other means to do this in REALbasic and this is only one of them. We still have not actually opened the database though.

One of things to realize is that in the dialog that gets shown as user could press "Cancel" and not select a file. In that case the DatabaseFile property would be set to Nil - this is a lot like NULL in a database.

So we'll need to test for this case and do something appropriate. If it is NIL then we should do nothing and if it is not NIL then we can try opening the database so we can use it else where in the application.

But, how will the rest of the application know that we did or did not open the database?

We don't want to have to check to see if app.Db.DatabaseFile is nil all over. That is one way but maybe there's a better way? What if we just set the app.db back to nil (remember this means "no value assigned") when a person does not select a database file? This actually will end up being "better" as it will immediately cause obvious errors if we try to use it when it is this way.

You might think it's odd to WANT errors, but in this case it is because of one unique feature that the REAL SQL database has. You don't actually need a file for it to connect to. In this case it will create an in-memory database that will behave exactly like one on disk except that when your program quits everything is lost. That can be very useful for some things, but not for what we're doing - at least not at the moment.

So let's add the following to the very end of the open event

if app.db.DatabaseFile is Nil then
  app.db = nil
else
end if

So this will set app.db, our global property for referring to the database, to nil if the user does not select a file.

In the event they do select a file, we should try and connect and see if that succeeds. If not maybe we should set the global property to nil for the same reason.

Alter the code so it reads

if app.db.DatabaseFile is Nil then
  app.db = nil
else
  if app.db.Connect() <> true then
    app.db = nil
  end if
end if

This will connect to a database and hold on to the reference or leave the reference as NIL (and we can check for that in other places). Thus far, we've created the database, connected to it and now, how to put it to use?

Let's hand code in adding the data we had for Apple last time so we can see how that is done and also eventually how to get it back into the list box. What we'll do is make sure the table is empty and then add in the data for Apple, then we'll extract that data from the database and populate the listbox with that data.

In the App.open event let's add in the cleaning out of the database, but in a way that it's easy enough to remove later on (we will want to remove it later on). The altered code in the Open event should now look like this:

if app.db.DatabaseFile is Nil then
  app.db = nil
else
  if app.db.Connect() <> true then
    app.db = nil
  else
    CleanOutDB()
  end if
end if

If you try to run at this point the compiler will complain about CleanOutDB as it does not exist yet.

Add a global method to the App class called CleanOutDatabase using either the Add Method button or Project > Add > Method. Make its name CleanOutDB. It does not need to do anything just yet.

Save everything then choose run and give things a try. You should see the dialog we created. Select the database file. Quit and run again and try to select a different file. Run it once again and press cancel so no file is selected.

You won't see much obvious happen yet. However, all of the code you have added has really been doing what is intended. But how to tell?

Well, you can see things run and it does what we discussed. Don't trust me? OK, there is a better way. REALbasic has a built in debugger. This is very handy to help you see what is going on in your program as it runs.

In the Open event if you look at the editor to the very left of the lines of the program you should see small dashes. If you click on one it should turn into a red dot like that in figure 6. This little red dot indicates that you have a "break point" on this line.


Figure 6: Setting a break point in the program

When you run your program in the IDE, and the program reaches this line of code, it will stop, and show you that it is about to run the line like in Figure 7.


Figure 7: Encountering a break point in the program

Now you can see where you are in your program, you can look at the value of variables and slowly advance through the program using the various Step buttons. You can actually see what's going on and control it at your leisure.

There is a whole section on using the debugger in the documentation from REAL. Learn how to use it well and it can be a great asset to you in your programming adventures.

If you're still looking at the screen shown in Figure 7, choose Resume and the program will proceed normally.

Let's open the CleanOutDB method we just added.

In this method we're going to remove all the data from the one table that exists currently.

First we should check to see if the database was connected to at all.

We can accomplish that with this line:

if app.db is nil then return

Recall that we set the app.db variable to nil if the user did not select a database or if the database could not be connected to. What this line does is check to see if there is a usable database, and if not leaves this routine immediately.

If the database was connected to we have to write the correct SQL to remove all the data from each table. The SQL command "delete" will delete things from a table. In its simplest form you simply use "delete from (tablename)". In our case this would be "delete from StocksOfInterest".

So lets write the REALbasic code that passes this command to the database.

dim sqlCmd as string = "delete from StocksOfInterest"

Recall that in REALbasic this is just a string and it means nothing special. It only has meaning when we tell the database to use it as a command. We do that by asking the database to "execute" it:

app.db.SqlExecute(sqlCmd)

This tells the database that we are connected to "run the SQL command that is in the variable sqlCMD".

How do we tell if things worked OK? Every database has several properties: error, errorCode and errorMessage. These properties can be checked to see if the previous operation succeeded. If everything worked properly, the error property will be false. If there was an error, the error property will be true.

If app.db.Error then
   msgbox "an error occurred " + format(app.db.ErrorCode,"-#") +_
          " " + app.db.ErrorMessage
end if

This displays a message box will the details of the error if things did not work, and does nothing if they did work.

Now we will want a way to add the data we have for Apple from last time. Since we will probably want to add data for quotes frequently we should make this a different method.

Create a new method called "AddDataForStock" that takes the stock symbol as one parameter, the stock price as another, and the date and time for the quote as the last one. Mine looks like that shown in Figure 8.


Figure 8: Definition of AddDataForStock

This method will be one that we'll use to add a quote for a given stock at a given date and time.

In the last installment, we just put the data directly into the listbox. This time, we'll alter that so the quote data goes into the database and then we retrieve it from the database to insert into the listbox.

For the moment, lets just pretend we are actually getting the quote from a service like Yahoo Finance or some other service and see how to get the data into the database.

In REALbasic there are at least two different ways you could add data to a database.

One is using raw SQL INSERT statements. While this gives you a great deal of control, it also means you have to take care of everything. Most SQL databases require you to double up quotes that are contained in values, and adding certain types of large binary chunks of data may be difficult using this method. You have to know what the specific database conventions are.

The second is using REALbasic's built-in DatabaseRecord class. This is substantially easier and only requires you to know how to use it and the specific database plugin does the rest of the grunt work; we'll use this second way for now.

First, you need to create a new instance of a DatabaseRecord. Then you add the specific values to it and then you add this record to the database. That code will look like:

  dim dbRec as DatabaseRecord   
  dbRec = new DatabaseRecord // create a databae record instance
  // add the data to it
  dbRec.Column("Symbol") = stockSymbol
  dbRec.DoubleColumn("Price") = stockPrice
  dbRec.DateColumn("quoteDateTime") = dateAndTimeForQuote
  // add the record to the database  
  db.InsertRecord("StockQuote", dbRec)
  
  // check for any errors
  if db.Error then
    msgbox "an error happened inserting the quote " + db.ErrorMessage
  end if 

This creates a new DatabaseRecord and sets the values. One thing to notice is that the addition of the values uses the names of the columns in the database table. The line:

dbRec.Column("Symbol") = stockSymbol  

can be interpreted as, "when you save this record the column called "Symbol" should be set to the value that is in stockSymbol. But this does not happen until you actually call InsertRecord.

At the end of the App.Open event, add in one line to add one quote for a stock like this:

  AddDataForStock "AAPL" , 169.73,  new Date

This will use the newly written method and pass in the symbol ("AAPL"), the stock price (169.73) and a date for the quote that is the current date and time.

Lets now see how to get this data out of the database and into our user interface. If you open the wStocks window and look in the Open event for the list box on that window you'll see:

  me.ColumnCount = 3
  me.HasHeading = true
  me.Heading(0) = "Symbol"
  me.Heading(1) = "Time"
  me.Heading(2) = "$"
  
  me.AddRow "AAPL" // add one symbol we're interested in watching
  dim newDate as new Date
  me.cell(me.LastIndex,1) = newDate.ShortDate + " " + newDate.ShortTime
  me.cell(me.LastIndex,2) = format(169.73,"$,#.00")

We're going to remove the last 4 lines and replace them with code that gets the data from the database. So lets first remove them and see what the new code will be to replace them:

dim rs as RecordSet 
// use SQL to get the data
rs = app.db.SQLSelect("select Symbol,  Price, quoteDateTime from stockquote")
  
// go through any and all rows we get back and put them in the list
while rs <> nil and rs.eof = false
    me.AddRow ""
    me.Cell(me.LastIndex,0) = rs.Field("Symbol").StringValue
    me.Cell(me.LastIndex,1) = rs.Field("quoteDateTime").DateValue.SQLDateTime
    me.Cell(me.LastIndex,2) = rs.Field("Price").StringValue
    
    rs.MoveNext
  wend

So what does all this do? First, we declare a variable to refer to a recordset. A recordset is what a database query returns to us. They can have lots of data (rows), or none. Only if the query has an error do you get a recordset that is NIL.

After declaring the variable, we then use a SQL SELECT query to get the set of data back that we want. In this case it's all rows and columns from the table called StockQuote. However SQL is very powerful and can be used to bring back data from one or more tables, sums and all kinds of other information. A full discussion of SQL is well beyond the scope of these articles.

Once we run the query, if there were no errors we will have a non-NIL recordset. I prefer to use a while loop to traverse all the data. For every row in the data set we get back from the query, we want to add a row to the list box. And then we want to set the columns in the listbox to the various values in each of the columns of the data set.

Each row in a recordset has many fields and each of those fields can be referred to by name, as it is in the database, or by a numeric index. I prefer to use names as they are easier to follow. Note that the query asks for "Symbol, Price, quoteDateTime" and the code just uses those names. Each of the lines in the loop grabs the string value of the field and puts it in the cell of the specific row of the listbox, then it moves to the next row. This continues until all the rows are loaded into the list box.

Now, run your application a few times and see what happens!

Next time we'll see how to grab the quotes from a service like Yahoo and add them to the database.


Norman Palardy has worked with SQL databases since 1992, and has programmed in C, C++, Java, REALbasic and other languages on a wide variety of platforms. In his 15+ years of IT experience, Norman has developed innovative and award-winning applications for TransCanada Pipelines, Minerva Technologies (now XWave), Zymeta Corporation, and the dining and entertainment industry. He holds a BSc from the University of Calgary in Alberta. He's also a founder of the Association of REALbasic Professionals (http://www.arbp.org/) and currently works for REAL Software.

 
AAPL
$95.60
Apple Inc.
+0.00
MSFT
$43.16
Microsoft Corpora
+0.00
GOOG
$571.60
Google Inc.
+0.00

MacTech Search:
Community Search:

Software Updates via MacUpdate

OneNote 15.2 - Free digital notebook fro...
OneNote is your very own digital notebook. With OneNote, you can capture that flash of genius, that moment of inspiration, or that list of errands that’s too important to forget. Whether you’re at... Read more
iStat Menus 4.22 - Monitor your system r...
iStat Menus lets you monitor your system right from the menubar. Included are 8 menu extras that let you monitor every aspect of your system. Some features: CPU -- Monitor cpu usage. 7 display... Read more
Ember 1.8 - Versatile digital scrapbook....
Ember (formerly LittleSnapper) is your digital scrapbook of things that inspire you: websites, photos, apps or other things. Just drag in images that you want to keep, organize them into relevant... Read more
OmniPlan 2.3.6 - Robust project manageme...
With OmniPlan, you can create logical, manageable project plans with Gantt charts, schedules, summaries, milestones, and critical paths. Break down the tasks needed to make your project a success,... Read more
Command-C 1.1.1 - Clipboard sharing tool...
Command-C is a revolutionary app which makes easy to share your clipboard between iOS and OS X using your local WiFi network, even if the app is not currently opened. Copy anything (text, pictures,... Read more
Knock 1.1.7 - Unlock your Mac by knockin...
Knock is a faster, safer way to sign in. You keep your iPhone with you all the time. Now you can use it as a password. You never have to open the app -- just knock on your phone twice, even when it's... Read more
Mellel 3.3.6 - Powerful word processor w...
Mellel is the leading word processor for OS X and has been widely considered the industry standard since its inception. Mellel focuses on writers and scholars for technical writing and multilingual... Read more
LibreOffice 4.3.0.4 - Free Open Source o...
LibreOffice is an office suite (word processor, spreadsheet, presentations, drawing tool) compatible with other major office suites. The Document Foundation is coordinating development and... Read more
Freeway Pro 7.0 - Drag-and-drop Web desi...
Freeway Pro lets you build websites with speed and precision... without writing a line of code! With it's user-oriented drag-and-drop interface, Freeway Pro helps you piece together the website of... Read more
Drive Genius 3.2.4 - Powerful system uti...
Drive Genius is an OS X utility designed to provide unsurpassed storage management. Featuring an easy-to-use interface, Drive Genius is packed with powerful tools such as a drive optimizer, a... Read more

Latest Forum Discussions

See All

Dawn of the Immortals Review
Dawn of the Immortals Review By Jennifer Allen on July 31st, 2014 Our Rating: :: RESPECTABLE EXPLORATIONUniversal App - Designed for iPhone and iPad Dawn of the Immortals might not re-invent the wheel, but it does tweak it a little... | Read more »
80 Days Review
80 Days Review By Jennifer Allen on July 31st, 2014 Our Rating: :: EPIC ADVENTUREUniversal App - Designed for iPhone and iPad A fantastic and fascinating re-envisioning of the classic novel by Jules Verne, 80 Days is a delightful... | Read more »
Battleheart Legacy Guide
The world of Battleheart Legacy is fun and deep; full of wizards, warriors, and witches. Here are some tips and tactics to help you get the most enjoyment out of this great game. | Read more »
Puzzle Roo Review
Puzzle Roo Review By Jennifer Allen on July 31st, 2014 Our Rating: :: PUZZLE-BASED TWISTUniversal App - Designed for iPhone and iPad A different take on the usual block dropping puzzle game, Puzzle Roo is quite pleasant.   | Read more »
Super Crossfire Re-Release Super Crossfi...
Super Crossfire Re-Release Super Crossfighter Coming Soon, Other Radiangames Titles Go 50% Off Posted by Ellis Spice on July 31st, 2014 [ | Read more »
Hexiled Review
Hexiled Review By Rob Thomas on July 31st, 2014 Our Rating: :: HEX SELLSUniversal App - Designed for iPhone and iPad In space, no one can hear you… spell? Hexiled is a neat concept for a word scramble puzzle, but it doesn’t go too... | Read more »
Summoners War: Sky Arena Passes 10 Milli...
Summoners War: Sky Arena Passes 10 Million Installs! Posted by Jessica Fisher on July 31st, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Deep Loot Review
Deep Loot Review By Jennifer Allen on July 31st, 2014 Our Rating: :: DIVE DEEPUniversal App - Designed for iPhone and iPad Dive deep in this fun explore-em-up that’s a little grind heavy but ultimately quite entertaining.   | Read more »
Despicable Me: Minion Rush is One Year O...
Despicable Me: Minion Rush is One Year Old, Gets its Biggest Update Yet Posted by Jennifer Allen on July 31st, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Fish & Shark Review
Fish & Shark Review By Jordan Minor on July 31st, 2014 Our Rating: :: FLAPPY FISHUniversal App - Designed for iPhone and iPad Fish & Shark’s beauty is only scale deep.   | Read more »

Price Scanner via MacPrices.net

13-inch MacBook Airs on sale for $100 off MSR...
B&H Photo has the new 2014 13″ MacBook Airs on sale $100 off MSRP. Shipping is free, and B&H charges NY sales tax only. They also include free copies of Parallels Desktop and LoJack for... Read more
16GB iPad Air on sale for $399, save $100
Best Buy is offering the 16GB WiFi iPad Air for $399.99 on their online store for a limited time. Their price is $100 off MSRP. Choose free shipping or free store pickup (if available). Price is for... Read more
All Over For Tablets Or Just A Maturing, Evol...
CNN’s David Goldman weighs in on tablet sector doom and gloom, asking rhetorically: “Is this the beginning of the end for the tablet?” Answering that, he contends that hysteria and panic are... Read more
Letterspace 1.0.1 – New Free iOS Text Editor...
Bangkok, Thailand based independent developer Sittipon Simasanti has released Letterspace, a new text editor for iPhone, iPad, and iPod touch devices. Letterspace is a note taking app with an... Read more
Save up to $130 on an iPad mini with Apple re...
The Apple Store has Certified Refurbished 2nd generation iPad minis with Retina Displays available for up to $130 off the cost of new models, starting at $339. Apple’s one-year warranty is included... Read more
iPad Cannibalization Threat “Overblown”
Seeking Alpha’s Kevin Greenhalgh observes that while many commentators think Apple’s forthcoming 5.5-inch panel iPhone 6 will cannibalize iPad sales, in his estimation, these concerns are being... Read more
Primate Labs Releases July 2014 MacBook Pro P...
Primate Labs’ John Poole has posted Geekbench 3 results for most of the new MacBook Pro models that Apple released on Tuesday. Poole observes that overall performance improvements for the new MacBook... Read more
Apple Re-Releases Bugfixed MacBook Air EFI Fi...
Apple has posted a bugfixed version EFI Firmware Update 2.9 a for MacBook Air (Mid 2011) models. The update addresses an issue where systems may take longer to wake from sleep than expected, and... Read more
Save $50 on the 2.5GHz Mac mini, plus free sh...
B&H Photo has the 2.5GHz Mac mini on sale for $549.99 including free shipping. That’s $50 off MSRP, and B&H will also include a free copy of Parallels Desktop software. NY sales tax only. Read more
Save up to $140 on an iPad Air with Apple ref...
Apple is offering Certified Refurbished iPad Airs for up to $140 off MSRP. Apple’s one-year warranty is included with each model, and shipping is free. Stock tends to come and go with some of these... Read more

Jobs Board

*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
Sr. Product Leader, *Apple* Store Apps - Ap...
**Job Summary** Imagine what you could do here. At Apple , great ideas have a way of becoming great products, services, and customer experiences very quickly. Bring Read more
Sr Software Lead Engineer, *Apple* Online S...
Sr Software Lead Engineer, Apple Online Store Publishing Systems Keywords: Company: Apple Job Code: E3PCAK8MgYYkw Location (City or ZIP): Santa Clara Status: Full Read more
Sr Software Lead Engineer, *Apple* Online S...
Sr Software Lead Engineer, Apple Online Store Publishing Systems Keywords: Company: Apple Job Code: E3PCAK8MgYYkw Location (City or ZIP): Santa Clara Status: Full Read more
*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.