diff --git a/Gemfile.lock b/Gemfile.lock index a983db2..34fecc5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - ProMotion (0.6.0) + ProMotion (0.6.1) GEM remote: https://rubygems.org/ diff --git a/README.md b/README.md index 69214c2..b0b897b 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ ProMotion is a RubyMotion gem that makes iOS development more like Ruby and less - [Working on Features](#working-on-features) - [Submitting a Pull Request](#submitting-a-pull-request) - [Primary Contributors](#primary-contributors) - + # Tutorials http://www.clearsightstudio.com/insights/ruby-motion-promotion-tutorial @@ -50,20 +50,25 @@ http://www.clearsightstudio.com/insights/tutorial-make-youtube-video-app-rubymot ## Sample Apps -[https://github.com/jamonholmgren/promotion-tutorial](https://github.com/jamonholmgren/promotion-tutorial) +This is pretty bare-bones, but we'll be building it out as we go along. + +[https://github.com/jamonholmgren/promotion-demo](https://github.com/jamonholmgren/promotion-demo) ## Apps Built With ProMotion ### BigDay! Reminder App -Check out the free [BigDay! Reminder app](https://itunes.apple.com/us/app/bigday!/id571756685?ls=1&mt=8) on the +Check out the free [BigDay! Reminder app](https://itunes.apple.com/us/app/bigday!/id571756685?ls=1&mt=8) on the App Store to see what's possible. ClearSight Studio built the app for Kijome Software, a small app investment company. ### TipCounter App [TipCounter](http://www.tipcounterapp.com) was built by [Matt Brewer](https://github.com/macfanatic/) for bartenders and servers to easily track their tips. Used ProMotion and the development was a lot of fun! +### Winston-Salem Crime Map +Have an interest in crime statistics and locations? Live in Winston-Salem, NC? This hyper-local and [open source](https://github.com/markrickert/WSCrime) RubyMotion app uses a mixture custom UIViewControllers and ProMotion for ease of attribute setting and adding views. Check it out [on the App Store](http://www.mohawkapps.com/winston-salem-crime-map/download/) or [fork it and contribute](https://github.com/markrickert/WSCrime)! + # Getting Started -ProMotion is designed to be as intuitive and Ruby-like as possible. For example, here is a +ProMotion is designed to be as intuitive and Ruby-like as possible. For example, here is a typical app folder structure: app/ @@ -108,7 +113,7 @@ gem "ProMotion", "~> 0.6.0" Run `bundle install` in Terminal to install ProMotion. -Go into your app/app_delegate.rb file and add the following: +Go into your app/app_delegate.rb file and replace everything with the following: ```ruby class AppDelegate < ProMotion::Delegate @@ -118,6 +123,9 @@ class AppDelegate < ProMotion::Delegate end ``` +Make sure you remove the `didFinishLoadingWithOptions` method or call `super` in it. Otherwise +ProMotion won't get set up and `on_load` won't be called. + Create a folder in `/app` named `screens`. Create a file in that folder named `home_screen.rb`. Now drop in this code: @@ -125,7 +133,7 @@ Now drop in this code: ```ruby class HomeScreen < ProMotion::Screen title "Home" - + def will_appear set_attributes self.view, { backgroundColor: UIColor.whiteColor @@ -165,12 +173,12 @@ class HomeScreen < ProMotion::Screen def on_load # Load data end - + def will_appear # Set up the elements in your view with add @label ||= add UILabel.alloc.initWithFrame(CGRectMake(5, 5, 20, 20)) end - + def on_appear # Everything's loaded and visible end @@ -209,18 +217,18 @@ def on_load(app, options) @home = MyHomeScreen.new(nav_bar: true) @settings = SettingsScreen.new @contact = ContactScreen.new(nav_bar: true) - + open_tab_bar @home, @settings, @contact end ``` -For each screen that belongs to the tab bar, you need to set the tab name and icon in the files. +For each screen that belongs to the tab bar, you need to set the tab name and icon in the files. In this example, we would need add the following to the three files (my_home_screen.rb, settings_screen.rb, contact_screen.rb): ```ruby def on_load set_tab_bar_item title: "Tab Name Goes Here", icon: "icons/tab_icon.png" # in resources/icons folder - + # or... set_tab_bar_item system_icon: UITabBarSystemItemContacts end @@ -244,6 +252,20 @@ set_nav_bar_right_button "Save", action: :save_something, type: UIBarButtonItemS set_nav_bar_left_button "Cancel", action: :return_to_some_other_screen, type: UIBarButtonItemStylePlain ``` +If you pass an instance of a `UIImage`, the `UIBarButton` will automatically display with that image instead of text. *Don't forget retina and landscape versions of your image!* + +If you pass `:system` for the title, then you can get a system item. E.g.: + +```ruby +set_nav_bar_right_button nil, action: :add_something, system_icon: UIBarButtonSystemItemAdd +``` + +Additionally, if you pass an instance of a `UIBarButtonItem`, the `UIBarButton` will automatically display that particular button item. + +```ruby +set_nav_bar_left_button self.editButtonItem +``` + ## Opening and closing screens If the user taps something and you want to open a new screen, it's easy. Just use `open` and pass in the screen class @@ -288,7 +310,6 @@ class ProfileScreen < ProMotion::Screen self.user # => some_user instance end end - ``` Closing a screen is as easy as can be. @@ -398,7 +419,7 @@ class SettingsScreen < ProMotion::GroupedTableScreen add_right_nav_button(label: "Save", action: :save) set_tab_bar_item(title: "Settings", icon: "settings.png") end - + # table_data is automatically called. Use this format in the return value. # It's an array of cell groups, each cell group consisting of a title and an array of cells. def table_data @@ -422,10 +443,10 @@ class SettingsScreen < ProMotion::GroupedTableScreen def table_data_index # Ruby magic to make an alphabetical array of letters. # Try this in Objective-C and tell me you want to go back. - return ("A".."Z").to_a + return ("A".."Z").to_a end - - # Your table cells, when tapped, will execute the corresponding actions + + # Your table cells, when tapped, will execute the corresponding actions # and pass in the specified arguments. def edit_profile(args={}) puts args[:id] # => 3 @@ -433,7 +454,7 @@ class SettingsScreen < ProMotion::GroupedTableScreen end ``` -You can provide remotely downloaded images for cells by including the CocoaPod "SDWebImage" in +You can provide remotely downloaded images for cells by including the CocoaPod "SDWebImage" in your Rakefile and doing this: ```ruby @@ -448,9 +469,9 @@ your Rakefile and doing this: ## Using your own UIViewController Sometimes you want to inherit from a different UIViewController other than that provided by ProMotion, -such as when using [Formotion](https://github.com/clayallsopp/formotion). **RubyMotion doesn't currently -allow us to override built-in methods when including them as a module.** And we really need to override -`viewDidLoad` and others. +such as when using [Formotion](https://github.com/clayallsopp/formotion). **RubyMotion doesn't currently +allow us to override built-in methods when including them as a module.** And we really need to override +`viewDidLoad` and others. Fortunately, there's a workaround for that. @@ -474,15 +495,15 @@ class EventsScreen < Formotion::FormController # Can also be < UIViewController super self.view_did_appear(animated) if self.respond_to?("view_did_appear:") end - + def viewWillDisappear(animated) self.view_will_disappear(animated) if self.respond_to?("view_will_disappear:") super end - + def viewDidDisappear(animated) self.view_did_disappear(animated) if self.respond_to?("view_did_disappear:") - super + super end def shouldAutorotateToInterfaceOrientation(orientation) @@ -496,7 +517,7 @@ class EventsScreen < Formotion::FormController # Can also be < UIViewController def willRotateToInterfaceOrientation(orientation, duration:duration) self.will_rotate(orientation, duration) end - + def didRotateFromInterfaceOrientation(orientation) self.on_rotate end @@ -530,13 +551,13 @@ end Creates the tab that is shown in a tab bar item.
Arguments: { icon: "imagename", systemIcon: UISystemIconContacts, title: "tabtitle" } - + on_appear Callback for when the screen appears.
- + will_appear @@ -568,12 +589,14 @@ end set_nav_bar_left_button(title, args = {}) Set a left nav bar button.
+ `title` can be a `String` or a `UIImage`. set_nav_bar_right_button(title, args = {}) Set a right nav bar button.
+ `title` can be a `String` or a `UIImage`.
@@ -604,7 +627,7 @@ end

 class SomeScreen
   title "Some screen"
-  
+
   def on_load
     # ...
   end
@@ -731,9 +754,9 @@ end
   
     
refreshable(
   callback: :on_refresh,
-  pull_message: "Pull to refresh", 
-  refreshing: "Refreshing data…", 
-  updated_format: "Last updated at %s", 
+  pull_message: "Pull to refresh",
+  refreshing: "Refreshing data…",
+  updated_format: "Last updated at %s",
   updated_time_format: "%l:%M %p"
 )
Class method to make the current table refreshable. @@ -755,7 +778,7 @@ end
Performance note... It's best to build this array in a different method and store it in something like @table_data. Then your table_data method just returns that. - +

 def table_data
   [{
@@ -770,7 +793,7 @@ def table_data
       arguments: { data: [ "lots", "of", "data" ] },
       action: :tapped_cell_1,
       height: 50, # manually changes the cell's height
-      cell_style: UITableViewCellStyleSubtitle, 
+      cell_style: UITableViewCellStyleSubtitle,
       cell_identifier: "Cell",
       cell_class: ProMotion::TableViewCell,
       masks_to_bounds: true,
@@ -786,7 +809,7 @@ def table_data
       accessory_checked: true, # whether it's "checked" or not
       image: { image: UIImage.imageNamed("something"), radius: 15 },
       remote_image: {  # remote image, requires SDWebImage CocoaPod
-        url: "http://placekitten.com/200/300", placeholder: "some-local-image", 
+        url: "http://placekitten.com/200/300", placeholder: "some-local-image",
         size: 50, radius: 15
       },
       subviews: [ @some_view, @some_other_view ] # arbitrary views added to the cell
@@ -890,7 +913,7 @@ Opening a ticket is usually the best and we respond to those pretty quickly.
 
 # Contributing
 
-I'm very open to ideas. Tweet me with your ideas or open a ticket (I don't mind!) 
+I'm very open to ideas. Tweet me with your ideas or open a ticket (I don't mind!)
 and let's discuss.
 
 ## Working on Features
diff --git a/Rakefile b/Rakefile
index 37bb157..34e30b9 100644
--- a/Rakefile
+++ b/Rakefile
@@ -1,5 +1,5 @@
 $:.unshift("/Library/RubyMotion/lib")
-require 'motion/project'
+require 'motion/project/template/ios'
 require 'bundler/gem_tasks'
 Bundler.setup
 Bundler.require
diff --git a/lib/ProMotion/screen_helpers/screen_navigation.rb b/lib/ProMotion/screen_helpers/screen_navigation.rb
index fc0173b..2415fec 100644
--- a/lib/ProMotion/screen_helpers/screen_navigation.rb
+++ b/lib/ProMotion/screen_helpers/screen_navigation.rb
@@ -10,10 +10,13 @@ module ProMotion
       screen.send(:on_load) if screen.respond_to?(:on_load)
       animated = args[:animated] || true
 
-      return self.split_screen.detail_screen = screen if args[:in_detail] && self.split_screen
-      return self.split_screen.master_screen = screen if args[:in_master] && self.split_screen
+      if args[:in_detail] && self.split_screen
+        self.split_screen.detail_screen = screen
 
-      if args[:close_all]
+      elsif args[:in_master] && self.split_screen
+        self.split_screen.master_screen = screen 
+
+      elsif args[:close_all]
         open_root_screen screen
 
       elsif args[:modal]
@@ -25,11 +28,8 @@ module ProMotion
       elsif self.navigation_controller
         push_view_controller screen
 
-      elsif screen.respond_to?(:main_controller)
-        open_view_controller screen.main_controller
-
       else
-        open_view_controller screen
+        open_root_screen screen
 
       end
 
@@ -76,8 +76,9 @@ module ProMotion
       end
     end
 
-    def open_view_controller(vc)
-      app_delegate.load_root_view vc
+    def open_view_controller(screen)
+      PM.logger.deprecated "Use `open_root_screen` instead of the more ambiguous `open_view_controller`."
+      open_root_screen screen
     end
 
     def push_view_controller(vc, nav_controller=nil)
@@ -133,6 +134,8 @@ module ProMotion
           screen.navigation_controller = vc if screen.respond_to?("navigation_controller=")
           push_view_controller(screen, vc)
         else
+          # TODO: This should probably open the vc, shouldn't it?
+          # This isn't well tested and needs to work better.
           self.tab_bar.selectedIndex = vc.tabBarItem.tag
         end
 
diff --git a/lib/ProMotion/screens/_screen_module.rb b/lib/ProMotion/screens/_screen_module.rb
index 7de8e43..f933244 100644
--- a/lib/ProMotion/screens/_screen_module.rb
+++ b/lib/ProMotion/screens/_screen_module.rb
@@ -6,13 +6,16 @@ module ProMotion
     include ProMotion::ScreenTabs
     include ProMotion::SplitScreen if NSBundle.mainBundle.infoDictionary["UIDeviceFamily"].include?("2")
 
-    attr_accessor :parent_screen, :first_screen, :tab_bar_item, :tab_bar, :modal, :split_screen
+    attr_accessor :parent_screen, :first_screen, :tab_bar_item, :tab_bar, :modal, :split_screen, :title
 
     def on_create(args = {})
       unless self.is_a?(UIViewController)
         raise StandardError.new("ERROR: Screens must extend UIViewController or a subclass of UIViewController.")
       end
 
+
+      self.title = self.class.send(:get_title)
+
       args.each do |k, v|
         self.send("#{k}=", v) if self.respond_to?("#{k}=")
       end
@@ -70,13 +73,26 @@ module ProMotion
       args[:title] = title
       set_nav_bar_button :left, args
     end
-    
+
+    # If you call set_nav_bar_button with a nil title and system_icon: UIBarButtonSystemItemAdd (or any other
+    # system icon), the button is initialized with a barButtonSystemItem instead of a title.
     def set_nav_bar_button(side, args={})
       args[:style]  ||= UIBarButtonItemStyleBordered
       args[:target] ||= self
       args[:action] ||= nil
 
-      button = UIBarButtonItem.alloc.initWithTitle(args[:title], style: args[:style], target: args[:target], action: args[:action])
+      button = case args[:title]
+        when String
+          UIBarButtonItem.alloc.initWithTitle(args[:title], style: args[:style], target: args[:target], action: args[:action])
+        when UIImage
+          UIBarButtonItem.alloc.initWithImage(args[:title], style: args[:style], target: args[:target], action: args[:action])
+        when Symbol, NilClass
+          UIBarButtonItem.alloc.initWithBarButtonSystemItem(args[:system_icon], target: args[:target], action: args[:action]) if args[:system_icon]
+        when UIBarButtonItem
+          args[:title]
+        else
+          PM.logger.error("Please supply a title string, a UIImage or :system.")
+      end
 
       self.navigationItem.leftBarButtonItem = button if side == :left
       self.navigationItem.rightBarButtonItem = button if side == :right
@@ -124,15 +140,6 @@ module ProMotion
     end
     def on_disappear; end
 
-    def title
-      self.class.send(:get_title)
-    end
-
-    def title=(new_title)
-      self.class.title = new_title
-      super
-    end
-
     def main_controller
       self.navigation_controller || self
     end
diff --git a/lib/ProMotion/version.rb b/lib/ProMotion/version.rb
index a198a22..0443a91 100644
--- a/lib/ProMotion/version.rb
+++ b/lib/ProMotion/version.rb
@@ -1,3 +1,3 @@
 module ProMotion
-  VERSION = "0.6.0" unless defined?(ProMotion::VERSION)
+  VERSION = "0.6.1" unless defined?(ProMotion::VERSION)
 end
diff --git a/resources/list.png b/resources/list.png
new file mode 100755
index 0000000..263cffd
Binary files /dev/null and b/resources/list.png differ
diff --git a/spec/helpers/basic_screen.rb b/spec/helpers/basic_screen.rb
index cee4052..2ddfc12 100644
--- a/spec/helpers/basic_screen.rb
+++ b/spec/helpers/basic_screen.rb
@@ -1,2 +1,3 @@
 class BasicScreen < ProMotion::Screen
+  title "Basic"
 end
diff --git a/spec/helpers/detail_screen.rb b/spec/helpers/detail_screen.rb
new file mode 100644
index 0000000..000805a
--- /dev/null
+++ b/spec/helpers/detail_screen.rb
@@ -0,0 +1,3 @@
+class DetailScreen < PM::Screen
+  title "Detail"
+end
diff --git a/spec/helpers/home_screen.rb b/spec/helpers/home_screen.rb
index dbde8b4..4ba59f2 100644
--- a/spec/helpers/home_screen.rb
+++ b/spec/helpers/home_screen.rb
@@ -4,10 +4,10 @@ class HomeScreen < ProMotion::Screen
 
   def on_load
     set_nav_bar_right_button "Save", action: :save_something, type: UIBarButtonItemStyleDone
-    set_nav_bar_left_button "Cancel", action: :return_to_some_other_screen, type: UIBarButtonItemStylePlain
+    set_nav_bar_left_button UIImage.imageNamed("list.png"), action: :return_to_some_other_screen, type: UIBarButtonItemStylePlain
   end
 
   def on_return(args={})
   end
 
-end
\ No newline at end of file
+end
diff --git a/spec/helpers/master_screen.rb b/spec/helpers/master_screen.rb
new file mode 100644
index 0000000..46b07c7
--- /dev/null
+++ b/spec/helpers/master_screen.rb
@@ -0,0 +1,3 @@
+class MasterScreen < PM::Screen
+  title "Master"
+end
diff --git a/spec/helpers/screen_module_view_controller.rb b/spec/helpers/screen_module_view_controller.rb
new file mode 100644
index 0000000..e829ea1
--- /dev/null
+++ b/spec/helpers/screen_module_view_controller.rb
@@ -0,0 +1,55 @@
+class ScreenModuleViewController < UIViewController
+  include PM::ScreenModule
+  title 'Test Title'
+
+  # Get rid of such hackiness when RubyMotion bug is fixed...
+  
+  def self.new(args = {})
+    s = self.alloc.initWithNibName(nil, bundle:nil)
+    s.on_create(args) if s.respond_to?(:on_create)
+    s
+  end
+
+  def viewDidLoad
+    super
+    self.view_did_load if self.respond_to?(:view_did_load)
+  end
+
+  def viewWillAppear(animated)
+    super
+    self.view_will_appear(animated) if self.respond_to?("view_will_appear:")
+  end
+
+  def viewDidAppear(animated)
+    super
+    self.view_did_appear(animated) if self.respond_to?("view_did_appear:")
+  end
+
+  def viewWillDisappear(animated)
+    self.view_will_disappear(animated) if self.respond_to?("view_will_disappear:")
+    super
+  end
+
+  def viewDidDisappear(animated)
+    if self.respond_to?("view_did_disappear:")
+      self.view_did_disappear(animated)
+    end
+    super
+  end
+
+  def shouldAutorotateToInterfaceOrientation(orientation)
+    self.should_rotate(orientation)
+  end
+
+  def shouldAutorotate
+    self.should_autorotate
+  end
+
+  def willRotateToInterfaceOrientation(orientation, duration:duration)
+    self.will_rotate(orientation, duration)
+  end
+
+  def didRotateFromInterfaceOrientation(orientation)
+    self.on_rotate
+  end
+end
diff --git a/spec/helpers/test_delegate.rb b/spec/helpers/test_delegate.rb
index 989783b..becdf95 100644
--- a/spec/helpers/test_delegate.rb
+++ b/spec/helpers/test_delegate.rb
@@ -1,9 +1,4 @@
 class TestDelegate < ProMotion::Delegate
   def on_load(app, options)
   end
-
-  # Hack to make RM 2.0 work.
-  # Ref: http://hipbyte.myjetbrains.com/youtrack/issue/RM-136
-  def dealloc
-  end
 end
diff --git a/spec/screen_helpers_spec.rb b/spec/screen_helpers_spec.rb
index 31a48c2..54bfa0d 100644
--- a/spec/screen_helpers_spec.rb
+++ b/spec/screen_helpers_spec.rb
@@ -35,25 +35,48 @@ describe "screen helpers" do
       @screen.add_to @subview, sub_subview, { backgroundColor: UIColor.redColor }
       @subview.subviews.last.backgroundColor.should == UIColor.redColor
     end
-    
+
   end
 
   describe "nav bar buttons" do
-    
+
     before do
       @screen = HomeScreen.new(nav_bar: true)
     end
-    
+
     it "should add a left nav bar button" do
       @screen.set_nav_bar_left_button "Save", action: :save_something, type: UIBarButtonItemStyleDone
       @screen.navigationItem.leftBarButtonItem.class.should == UIBarButtonItem
     end
-    
+
     it "should add a right nav bar button" do
       @screen.set_nav_bar_right_button "Cancel", action: :return_to_some_other_screen, type: UIBarButtonItemStylePlain
       @screen.navigationItem.rightBarButtonItem.class.should == UIBarButtonItem
     end
-    
+
+    it "should add an image right nav bar button" do
+      image = UIImage.imageNamed("list.png")
+      @screen.set_nav_bar_right_button image, action: :return_to_some_other_screen, type: UIBarButtonItemStylePlain
+      @screen.navigationItem.rightBarButtonItem.image.class.should == UIImage
+      @screen.navigationItem.rightBarButtonItem.image.should == image
+    end
+
+    it "should add an image left nav bar button" do
+      image = UIImage.imageNamed("list.png")
+      @screen.set_nav_bar_left_button image, action: :return_to_some_other_screen, type: UIBarButtonItemStylePlain
+      @screen.navigationItem.leftBarButtonItem.image.class.should == UIImage
+      @screen.navigationItem.leftBarButtonItem.image.should == image
+    end
+
+    it "should add a left UIBarButtonItem" do
+      @screen.set_nav_bar_left_button @screen.editButtonItem
+      @screen.navigationItem.leftBarButtonItem.class.should == UIBarButtonItem
+    end
+
+    it "should add a right UIBarButtonItem" do
+      @screen.set_nav_bar_right_button @screen.editButtonItem
+      @screen.navigationItem.rightBarButtonItem.class.should == UIBarButtonItem
+    end
   end
 
   describe "screen navigation" do
@@ -151,21 +174,11 @@ describe "screen helpers" do
         @screen.open BasicScreen
       end
 
-      it "should open the main controller if no options are provided" do
-        parent_screen = HomeScreen.new
-        nav_controller = ProMotion::NavigationController.new
-        new_screen = BasicScreen.new
-        new_screen.stub! :main_controller, return: nav_controller
-
-        parent_screen.mock!(:open_view_controller) { |vc| vc.should.be == nav_controller  }
-        parent_screen.open new_screen
-      end
-
-      it "should open the provided view controller if no other conditions are met" do
+      it "should open the provided view controller as root view if no other conditions are met" do
         parent_screen = HomeScreen.new
         new_screen = BasicScreen.new
-        parent_screen.mock!(:open_view_controller) { |vc| vc.should.be == new_screen }
-        parent_screen.open new_screen
+        parent_screen.mock!(:open_root_screen) { |vc| vc.should.be == new_screen }
+        parent_screen.open_screen new_screen
       end
 
     end
diff --git a/spec/screen_module_spec.rb b/spec/screen_module_spec.rb
new file mode 100644
index 0000000..7d1dbd7
--- /dev/null
+++ b/spec/screen_module_spec.rb
@@ -0,0 +1,13 @@
+describe "PM::ScreenModule" do
+
+  before { @subject = ScreenModuleViewController.new }
+
+  it 'should have PM::ScreenModule in ancestors' do
+    @subject.class.ancestors.include?(PM::ScreenModule).should == true
+  end
+
+  it 'should have a title from class method #title' do
+    @subject.title.should == 'Test Title'
+  end
+
+end
diff --git a/spec/screen_spec.rb b/spec/screen_spec.rb
index 4ca5932..0326d14 100644
--- a/spec/screen_spec.rb
+++ b/spec/screen_spec.rb
@@ -12,9 +12,18 @@ describe "screen properties" do
     HomeScreen.get_title.should == 'Home'
   end
 
-  it "should let the instance reset the title" do
+  it "should set default title on new instances" do
+    @screen.title.should == "Home"
+  end
+
+  it "should let the instance set its title" do
     @screen.title = "instance method"
-    HomeScreen.get_title.should == 'instance method'
+    @screen.title.should == 'instance method'
+  end
+
+  it "should not let the instance reset the default title" do
+    @screen.title = "instance method"
+    HomeScreen.get_title.should != 'instance method'
   end
 
   it "should store debug mode" do
@@ -73,10 +82,10 @@ describe "screen properties" do
     end
 
     it "-willRotateToInterfaceOrientation" do
-      @screen.mock! :will_rotate do |orientation, duration| 
+      @screen.mock! :will_rotate do |orientation, duration|
         orientation.should == UIInterfaceOrientationPortrait
         duration.should == 0.5
-      end 
+      end
       @screen.willRotateToInterfaceOrientation(UIInterfaceOrientationPortrait, duration: 0.5)
     end
 
@@ -108,4 +117,54 @@ describe "screen properties" do
 
   end
 
+  describe "bar button behavior" do
+    describe "system bar buttons" do
+      before do
+        @screen.set_nav_bar_right_button nil, action: :add_something, system_icon: UIBarButtonSystemItemAdd
+      end
+
+      it "has a right bar button item of the correct type" do
+        @screen.navigationItem.rightBarButtonItem.should.be.instance_of UIBarButtonItem
+      end
+
+      it "is an add button" do
+        @screen.navigationItem.rightBarButtonItem.action.should == :add_something
+      end
+    end
+
+    describe 'titled bar buttons' do
+      before do
+        @screen.set_nav_bar_right_button "Save", action: :save_something, style: UIBarButtonItemStyleDone
+      end
+
+      it "has a right bar button item of the correct type" do
+        @screen.navigationItem.rightBarButtonItem.should.be.instance_of UIBarButtonItem
+      end
+
+      it "has a right bar button item of the correct style" do
+        @screen.navigationItem.rightBarButtonItem.style.should == UIBarButtonItemStyleDone
+      end
+
+      it "is titled correctly" do
+        @screen.navigationItem.rightBarButtonItem.title.should == 'Save'
+      end
+    end
+
+    describe 'image bar buttons' do
+      before do
+        @image = UIImage.alloc.init
+        @screen.set_nav_bar_right_button @image, action: :save_something, style: UIBarButtonItemStyleDone
+      end
+
+      it "has a right bar button item of the correct type" do
+        @screen.navigationItem.rightBarButtonItem.should.be.instance_of UIBarButtonItem
+      end
+
+      it "is has the right image" do
+        @screen.navigationItem.rightBarButtonItem.title.should == nil
+      end
+    end
+
+  end
+
 end
diff --git a/spec/split_screen_in_tab_bar_spec.rb b/spec/split_screen_in_tab_bar_spec.rb
index 2661351..c21515d 100644
--- a/spec/split_screen_in_tab_bar_spec.rb
+++ b/spec/split_screen_in_tab_bar_spec.rb
@@ -10,6 +10,10 @@ describe "split screen in tab bar functionality" do
     @tab = @app.open_tab_bar @split_screen, HomeScreen, BasicScreen
   end
 
+  after do
+    @split_screen.delegate = nil # dereference to avoid memory issue
+  end
+
   it "should create a UISplitViewController" do
     @split_screen.is_a?(UISplitViewController).should == true
   end
@@ -46,4 +50,4 @@ describe "split screen in tab bar functionality" do
     @tab.viewControllers.first.should == @split_screen
   end
 
-end
\ No newline at end of file
+end
diff --git a/spec/split_screen_open_screen_spec.rb b/spec/split_screen_open_screen_spec.rb
index 0f6ecf1..10bbdb5 100644
--- a/spec/split_screen_open_screen_spec.rb
+++ b/spec/split_screen_open_screen_spec.rb
@@ -10,6 +10,10 @@ describe "split screen `open` functionality" do
     @split_screen = @app.open_split_screen @master_screen, @detail_screen_1
   end
 
+  after do
+    @split_screen.delegate = nil # dereference to avoid memory issue
+  end
+
   it "should open a new screen in the detail view" do
     @master_screen.open @detail_screen_2, in_detail: true
     @split_screen.detail_screen.should == @detail_screen_2
@@ -43,4 +47,4 @@ describe "split screen `open` functionality" do
     home.navigation_controller.topViewController.should == child
   end
 
-end
\ No newline at end of file
+end
diff --git a/spec/split_screen_spec.rb b/spec/split_screen_spec.rb
index 2fd506a..83de801 100644
--- a/spec/split_screen_spec.rb
+++ b/spec/split_screen_spec.rb
@@ -3,12 +3,16 @@ describe "split screen functionality" do
   before do
     @app = TestDelegate.new
 
-    @master_screen = HomeScreen.new nav_bar: true
-    @detail_screen = BasicScreen.new # no nav_bar on this one
+    @master_screen = MasterScreen.new nav_bar: true
+    @detail_screen = DetailScreen.new # no nav_bar on this one
 
     @split_screen = @app.open_split_screen @master_screen, @detail_screen
   end
 
+  after do
+    @split_screen.delegate = nil # dereference to avoid memory issue
+  end
+
   it "should have created a split screen" do
     @split_screen.should != nil
     @split_screen.is_a?(UISplitViewController).should == true
@@ -22,14 +26,42 @@ describe "split screen functionality" do
     @app.window.rootViewController.should == @split_screen
   end
 
-  it "should set the first viewController to HomeScreen" do
+  it "should set the first viewController to MasterScreen" do
     @split_screen.master_screen.should == @master_screen
     @split_screen.viewControllers.first.should == @master_screen.main_controller
   end
 
-  it "should set the second viewController to BasicScreen" do
+  it "should set the second viewController to DetailScreen" do
     @split_screen.detail_screen.should == @detail_screen
     @split_screen.viewControllers.last.should == @detail_screen.main_controller
   end
 
-end
\ No newline at end of file
+  it "should set the title on both screens" do
+    @master_screen.class.send(:get_title).should == "Master"
+    @master_screen.title.should == "Master"
+    @detail_screen.class.send(:get_title).should == "Detail"
+    @detail_screen.title.should == "Detail"
+  end
+end
+
+# Regression test for https://github.com/clearsightstudio/ProMotion/issues/74
+describe "split screen with UIViewControllers with ScreenModule" do
+
+  before do
+    @app = TestDelegate.new
+
+    @master_screen = ScreenModuleViewController.new
+    @detail_screen = DetailScreen.new(nav_bar: true)
+
+    @split_screen = @app.open_split_screen @master_screen, @detail_screen
+  end
+
+  it "should set the title on both screens" do
+    @master_screen.class.send(:get_title).should == "Test Title"
+    @master_screen.title.should == "Test Title"
+    @detail_screen.class.send(:get_title).should == "Detail"
+    @detail_screen.title.should == "Detail"
+  end
+
+end
+